diff --git a/.github/workflows/test-all.yml b/.github/workflows/test-all.yml index d38691576..e42e67190 100644 --- a/.github/workflows/test-all.yml +++ b/.github/workflows/test-all.yml @@ -9,7 +9,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: "22.10.0" + node-version: "22.18.0" cache: "yarn" - run: yarn install - run: yarn build:all diff --git a/.github/workflows/test-swap.yml b/.github/workflows/test-swap.yml index 5fcc50756..6c505d6c0 100644 --- a/.github/workflows/test-swap.yml +++ b/.github/workflows/test-swap.yml @@ -9,7 +9,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: - node-version: "22.10.0" + node-version: "22.18.0" cache: "yarn" - run: yarn install - run: yarn build:all diff --git a/.nvmrc b/.nvmrc index bb8c76c68..32cfab636 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v22.11.0 +v22.18.0 diff --git a/.vscode/settings.json b/.vscode/settings.json index 54e9b2be6..1017f72c9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,6 @@ "source.fixAll": "explicit" }, "editor.formatOnSave": true, - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.inlineSuggest.enabled": false } diff --git a/Dockerfile b/Dockerfile index 914be81b9..a67e7066a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:22.11-bookworm +FROM node:22.18-bookworm RUN apt-get update RUN apt-get install build-essential zip -y ENV HOME /home diff --git a/README.md b/README.md index 45a39b14d..80a7a630c 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,8 @@ Enkrypt is a web3 wallet built from the ground up to support the multi-chain fut - Gravity - Unit Zero - Unit Zero Testnet +- Nibiru +- Nibiru Testnet - More coming soon! Looking to add your project? [Contact us!](https://mewwallet.typeform.com/enkrypt-inquiry?typeform-source=www.enkrypt.com) @@ -226,4 +228,4 @@ Email - info@enkrypt.com Homepage - [https://www.enkrypt.com/](https://www.enkrypt.com/) -

(back to top)

+

(back to top)

\ No newline at end of file diff --git a/package.json b/package.json index 75b7a1a3a..8f27872f0 100644 --- a/package.json +++ b/package.json @@ -32,14 +32,15 @@ "prepare": "husky" }, "devDependencies": { - "@commitlint/cli": "^19.8.1", - "@commitlint/config-conventional": "^19.8.1", - "@swc/core": "^1.13.2", - "concurrently": "^9.2.0", + "@commitlint/cli": "^20.1.0", + "@commitlint/config-conventional": "^20.0.0", + "@swc/core": "^1.15.2", + "concurrently": "^9.2.1", "husky": "^9.1.7", "node-notifier": "^10.0.1", - "nodemon": "^3.1.10", - "ultra-runner": "^3.10.5" + "nodemon": "^3.1.11", + "ultra-runner": "^3.10.5", + "vite-plugin-node-polyfills": "0.24.0" }, "resolutions": { "@zondax/ledger-cosmos-js/vue": "^3.5.12", diff --git a/packages/extension-bridge/package.json b/packages/extension-bridge/package.json index 70a76b200..8622489b2 100644 --- a/packages/extension-bridge/package.json +++ b/packages/extension-bridge/package.json @@ -44,12 +44,12 @@ "webextension-polyfill": "^0.12.0" }, "devDependencies": { - "@types/node": "^22.16.5", - "@types/webextension-polyfill": "^0.12.3", - "@typescript-eslint/eslint-plugin": "^8.38.0", - "@typescript-eslint/parser": "^8.38.0", - "bumpp": "^10.2.0", - "eslint": "^9.32.0", + "@types/node": "^22.19.1", + "@types/webextension-polyfill": "^0.12.4", + "@typescript-eslint/eslint-plugin": "^8.47.0", + "@typescript-eslint/parser": "^8.47.0", + "bumpp": "^10.3.1", + "eslint": "^9.39.1", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^10.1.8", "eslint-import-resolver-alias": "^1.1.2", @@ -58,9 +58,9 @@ "prettier": "^3.6.2", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", - "tsup": "^8.5.0", - "type-fest": "^4.41.0", - "typescript": "^5.8.3", - "typescript-eslint": "8.38.0" + "tsup": "^8.5.1", + "type-fest": "^5.2.0", + "typescript": "^5.9.3", + "typescript-eslint": "8.47.0" } } diff --git a/packages/extension/configs/vitest.config.mts b/packages/extension/configs/vitest.config.mts index 90f0d6bd8..a39b3a10f 100644 --- a/packages/extension/configs/vitest.config.mts +++ b/packages/extension/configs/vitest.config.mts @@ -6,23 +6,26 @@ export default defineConfig({ plugins: [ tsconfigPaths() as any, nodePolyfills({ - include: [ - 'crypto', - // ... include other Node.js modules if needed - ], + include: ['crypto'], }), ], define: { - // setting __VERSION__ here blows it up for some reason - // __VERSION__: 'testing', __IS_OPERA__: false, }, test: { environment: 'jsdom', setupFiles: ['./tests/setup.ts'], - include: [ - 'src/**/*.{test,spec}.ts', - 'tests/**/*.{test,spec}.ts', + include: ['src/**/*.{test,spec}.ts', 'tests/**/*.{test,spec}.ts'], + }, + resolve: { + alias: [ + { + find: /^(vite-plugin-node-polyfills\/shims\/.+)/, + replacement: '$1', + customResolver(source) { + return import.meta.resolve(source).replace(/^file:\/\//, ''); + }, + }, ], }, }); diff --git a/packages/extension/package.json b/packages/extension/package.json index 8218c3344..e337636e5 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -1,6 +1,6 @@ { "name": "@enkryptcom/extension", - "version": "2.10.0", + "version": "2.14.0", "private": true, "type": "module", "scripts": { @@ -16,14 +16,14 @@ "build:chrome": "yarn prebuild && cross-env BROWSER='chrome' MINIFY='true' vite build", "build:firefox": "yarn prebuild && cross-env BROWSER='firefox' MINIFY='true' vite build && node configs/get-system-info.js", "build:opera": "yarn prebuild && cross-env BROWSER='opera' MINIFY='true' vite build", - "kadena:prebuild": "pactjs contract-generate --contract=coin --api https://api.chainweb.com/chainweb/0.0/mainnet01/chain/1/pact", + "kadena:prebuild": "pactjs contract-generate --contract=coin --api https://api.chainweb-community.org/chainweb/0.0/mainnet01/chain/1/pact", "test": "vitest run -c ./configs/vitest.config.mts", "watch": "yarn dev", "watch:chrome": "yarn dev", "watch:firefox": "yarn prebuild && cross-env BROWSER='firefox' vite" }, "dependencies": { - "@amplitude/analytics-browser": "^2.20.1", + "@amplitude/analytics-browser": "^2.31.1", "@enkryptcom/extension-bridge": "workspace:^", "@enkryptcom/hw-wallets": "workspace:^", "@enkryptcom/keyring": "workspace:^", @@ -36,34 +36,35 @@ "@ethereumjs/tx": "^5.4.0", "@ethereumjs/util": "^9.1.0", "@ethereumjs/wallet": "^2.0.4", - "@kadena/client": "^1.18.0", - "@kadena/pactjs-cli": "^1.18.0", - "@ledgerhq/hw-transport-webusb": "^6.29.8", + "@kadena/client": "^1.18.3", + "@kadena/pactjs-cli": "^1.18.3", + "@ledgerhq/hw-transport-webusb": "^6.29.13", + "@massalabs/massa-web3": "^5.3.0", "@metamask/eth-sig-util": "^8.2.0", "@metaplex-foundation/mpl-bubblegum": "^5.0.2", - "@metaplex-foundation/umi": "^1.2.0", - "@metaplex-foundation/umi-bundle-defaults": "^1.2.0", - "@polkadot/api": "^16.4.2", - "@polkadot/extension-inject": "^0.61.4", - "@polkadot/keyring": "^13.5.3", - "@polkadot/rpc-provider": "^16.4.2", - "@polkadot/types": "^16.4.2", - "@polkadot/types-known": "^16.4.2", - "@polkadot/ui-shared": "^3.15.2", - "@polkadot/util": "^13.5.3", - "@polkadot/wasm-crypto": "^7.4.1", + "@metaplex-foundation/umi": "^1.4.1", + "@metaplex-foundation/umi-bundle-defaults": "^1.4.1", + "@polkadot/api": "^16.5.2", + "@polkadot/extension-inject": "^0.62.5", + "@polkadot/keyring": "^13.5.8", + "@polkadot/rpc-provider": "^16.5.2", + "@polkadot/types": "^16.5.2", + "@polkadot/types-known": "^16.5.2", + "@polkadot/ui-shared": "^3.16.3", + "@polkadot/util": "^13.5.8", + "@polkadot/wasm-crypto": "^7.5.2", "@solana-developers/helpers": "2.8.0", - "@solana/spl-token": "^0.4.13", + "@solana/spl-token": "^0.4.14", "@solana/wallet-standard-features": "^1.3.0", - "@solana/web3.js": "^1.98.2", + "@solana/web3.js": "^1.98.4", "@wallet-standard/base": "^1.1.0", "add": "^2.0.6", "bignumber.js": "^9.3.1", "bip39": "^3.1.0", "bitcoinjs-lib": "^6.1.7", "bs58": "^6.0.0", - "concurrently": "^9.2.0", - "echarts": "^5.6.0", + "concurrently": "^9.2.1", + "echarts": "^6.0.0", "ethereum-cryptography": "^2.2.1", "ethereumjs-abi": "^0.6.8", "eventemitter3": "^5.0.1", @@ -73,14 +74,14 @@ "moment": "^2.30.1", "nanoevents": "^9.1.0", "pact-lang-api": "^4.3.6", - "pinia": "^3.0.3", + "pinia": "^3.0.4", "qrcode.vue": "^3.6.0", "switch-ts": "^1.1.1", "url-parse": "^1.5.10", - "uuid": "^11.1.0", - "vue": "^3.5.18", - "vue-echarts": "7.0.3", - "vue-router": "^4.5.1", + "uuid": "^13.0.0", + "vue": "^3.5.24", + "vue-echarts": "8.0.1", + "vue-router": "^4.6.3", "vue3-lottie": "^3.3.1", "vuedraggable": "^4.1.0", "web3-eth": "^1.10.4", @@ -89,56 +90,56 @@ "zxcvbn": "^4.4.2" }, "devDependencies": { - "@crxjs/vite-plugin": "^2.0.0-beta.32", - "@rollup/plugin-commonjs": "^28.0.6", + "@crxjs/vite-plugin": "^2.2.1", + "@rollup/plugin-commonjs": "^29.0.0", "@rollup/plugin-inject": "^5.0.5", "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "^16.0.1", - "@rollup/plugin-replace": "^6.0.2", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-replace": "^6.0.3", "@rollup/plugin-terser": "^0.4.4", - "@rollup/plugin-typescript": "^12.1.4", - "@tsconfig/node20": "^20.1.6", + "@rollup/plugin-typescript": "^12.3.0", + "@tsconfig/node20": "^20.1.8", "@types/bs58": "^5.0.0", - "@types/chrome": "^0.1.1", + "@types/chrome": "^0.1.31", "@types/ethereumjs-abi": "^0.6.5", "@types/events": "^3.0.3", "@types/fs-extra": "^11.0.4", "@types/less": "^3.0.8", "@types/lodash": "^4.17.20", - "@types/node": "^22.16.5", - "@types/semver": "^7.7.0", + "@types/node": "^22.19.1", + "@types/semver": "^7.7.1", "@types/url-parse": "^1.4.11", "@types/utf-8-validate": "^5.0.2", - "@types/uuid": "^10.0.0", + "@types/uuid": "^11.0.0", "@types/wif": "^2.0.5", "@types/zxcvbn": "^4.4.5", - "@vitejs/plugin-vue": "^5.2.4", + "@vitejs/plugin-vue": "^6.0.2", "@vue/eslint-config-prettier": "^10.2.0", "@vue/eslint-config-typescript": "^14.6.0", - "@vue/tsconfig": "^0.7.0", - "@vueuse/core": "^13.5.0", - "cross-env": "^7.0.3", - "eslint": "^9.32.0", - "eslint-plugin-vue": "^10.3.0", - "fs-extra": "^11.3.0", + "@vue/tsconfig": "^0.8.1", + "@vueuse/core": "^14.0.0", + "cross-env": "^10.1.0", + "eslint": "^9.39.1", + "eslint-plugin-vue": "^10.5.1", + "fs-extra": "^11.3.2", "jsdom": "^26.1.0", - "less": "^4.4.0", + "less": "^4.4.2", "less-loader": "^12.3.0", "npm-run-all2": "^8.0.4", "prettier": "^3.6.2", - "rimraf": "^6.0.1", - "rollup": "^4.45.1", - "rollup-plugin-visualizer": "^6.0.3", - "semver": "^7.7.2", - "systeminformation": "^5.27.7", - "tsup": "^8.5.0", - "typescript": "~5.8.3", + "rimraf": "^6.1.2", + "rollup": "^4.53.3", + "rollup-plugin-visualizer": "^6.0.5", + "semver": "^7.7.3", + "systeminformation": "^5.27.11", + "tsup": "^8.5.1", + "typescript": "~5.9.3", "url": "^0.11.4", - "vite": "^6.3.5", + "vite": "^7.2.2", "vite-plugin-node-polyfills": "0.24.0", "vite-tsconfig-paths": "^5.1.4", - "vitest": "^3.2.4", - "vue-tsc": "^2.2.12", + "vitest": "^4.0.10", + "vue-tsc": "^3.1.4", "webextension-polyfill": "^0.12.0" }, "installConfig": { diff --git a/packages/extension/src/libs/background/index.ts b/packages/extension/src/libs/background/index.ts index d00f28109..a888c2290 100644 --- a/packages/extension/src/libs/background/index.ts +++ b/packages/extension/src/libs/background/index.ts @@ -28,6 +28,7 @@ import { } from './internal'; import { handlePersistentEvents } from './external'; import SettingsState from '../settings-state'; +import { isGeoRestricted } from '../utils/screening'; class BackgroundHandler { #keyring: KeyRingBase; @@ -36,6 +37,7 @@ class BackgroundHandler { #persistentEvents: PersistentEvents; #domainState: DomainState; #settingsState: SettingsState; + #geoRestricted: boolean | undefined; constructor() { this.#keyring = new KeyRingBase(); @@ -48,8 +50,13 @@ class BackgroundHandler { [ProviderName.bitcoin]: {}, [ProviderName.kadena]: {}, [ProviderName.solana]: {}, + [ProviderName.massa]: {}, }; this.#providers = Providers; + this.#geoRestricted = undefined; + isGeoRestricted().then(restricted => { + this.#geoRestricted = restricted; + }); } async init(): Promise { await handlePersistentEvents.bind(this)(); @@ -82,6 +89,9 @@ class BackgroundHandler { method === InternalMethods.newWindowUnload ) { this.#persistentEvents.deleteEvents(_tabid); + isGeoRestricted().then(restricted => { + this.#geoRestricted = restricted; + }); return { result: JSON.stringify(true), }; @@ -96,6 +106,15 @@ class BackgroundHandler { error: JSON.stringify(getCustomError('Enkrypt: not implemented')), }; } + if (this.#geoRestricted !== undefined && this.#geoRestricted) { + return { + error: JSON.stringify( + getCustomError( + 'Enkrypt: Geo restricted https://www.myetherwallet.com/blocked', + ), + ), + }; + } const tabInfo = TabInfo(await Browser.tabs.get(_tabid)); if (!this.#tabProviders[_provider][_tabid]) { const toWindow = (message: string) => { diff --git a/packages/extension/src/libs/background/types.ts b/packages/extension/src/libs/background/types.ts index 73cc10eb9..ae2c834cd 100644 --- a/packages/extension/src/libs/background/types.ts +++ b/packages/extension/src/libs/background/types.ts @@ -3,6 +3,7 @@ import type EthereumProvider from '@/providers/ethereum'; import type PolkadotProvider from '@/providers/polkadot'; import type KadenaProvider from '@/providers/kadena'; import SolanaProvider from '@/providers/solana'; +import MassaProvider from '@/providers/massa'; export interface TabProviderType { [key: string]: Record< @@ -12,6 +13,7 @@ export interface TabProviderType { | BitcoinProvider | KadenaProvider | SolanaProvider + | MassaProvider >; } export interface ProviderType { @@ -20,7 +22,8 @@ export interface ProviderType { | typeof PolkadotProvider | typeof BitcoinProvider | typeof KadenaProvider - | typeof SolanaProvider; + | typeof SolanaProvider + | typeof MassaProvider; } export interface ExternalMessageOptions { savePersistentEvents: boolean; diff --git a/packages/extension/src/libs/backup-state/index.ts b/packages/extension/src/libs/backup-state/index.ts index 67ea556b8..e0a39ef83 100644 --- a/packages/extension/src/libs/backup-state/index.ts +++ b/packages/extension/src/libs/backup-state/index.ts @@ -156,6 +156,7 @@ class BackupState { async restoreBackup(userId: string, keyringPassword: string): Promise { const mainWallet = await this.getMainWallet(); + const exludedSignerTypes: SignerType[] = []; await sendUsingInternalMessengers({ method: InternalMethods.unlock, params: [keyringPassword, false], @@ -207,6 +208,7 @@ class BackupState { for (const key of Object.keys(highestPathIndex)) { const [basePath, signerType] = key.split('###'); + if (exludedSignerTypes.includes(signerType as SignerType)) continue; for (let i = 0; i <= highestPathIndex[key]; i++) { const newAccount = getAccountByIndex( decryptedBackup.accounts, diff --git a/packages/extension/src/libs/banners-state/index.ts b/packages/extension/src/libs/banners-state/index.ts index ef05bf0b9..efcfffc74 100644 --- a/packages/extension/src/libs/banners-state/index.ts +++ b/packages/extension/src/libs/banners-state/index.ts @@ -19,6 +19,7 @@ export default class BannersState { const newState: IState = { isHideSolanStakingBanner: false, isHideNetworkAssetSolanStakingBanner: false, + isHideSurveyPopup: false, }; await this.storage.set(StorageKeys.bannersInfo, newState); return newState; @@ -28,6 +29,7 @@ export default class BannersState { const state = await this.getOrInitializeState(); state.isHideNetworkAssetSolanStakingBanner = false; state.isHideSolanStakingBanner = false; + state.isHideSurveyPopup = false; await this.storage.set(StorageKeys.bannersInfo, state); } @@ -52,4 +54,15 @@ export default class BannersState { state.isHideSolanStakingBanner = true; await this.storage.set(StorageKeys.bannersInfo, state); } + + async showSurveyPopup(): Promise { + const state = await this.getOrInitializeState(); + return !state.isHideSurveyPopup; + } + + async hideSurveyPopup() { + const state = await this.getOrInitializeState(); + state.isHideSurveyPopup = true; + await this.storage.set(StorageKeys.bannersInfo, state); + } } diff --git a/packages/extension/src/libs/banners-state/types.ts b/packages/extension/src/libs/banners-state/types.ts index b1f048512..0758cb6a2 100644 --- a/packages/extension/src/libs/banners-state/types.ts +++ b/packages/extension/src/libs/banners-state/types.ts @@ -5,4 +5,5 @@ export enum StorageKeys { export type IState = { isHideSolanStakingBanner: boolean; isHideNetworkAssetSolanStakingBanner: boolean; + isHideSurveyPopup: boolean; }; diff --git a/packages/extension/src/libs/dapp-list/index.ts b/packages/extension/src/libs/dapp-list/index.ts index 9048fd680..34c3e0e93 100644 --- a/packages/extension/src/libs/dapp-list/index.ts +++ b/packages/extension/src/libs/dapp-list/index.ts @@ -33,16 +33,12 @@ const lists: Partial> = { 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/okc.json', [NetworkNames.Optimism]: 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/op.json', - [NetworkNames.Canto]: - 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/canto.json', [NetworkNames.Bifrost]: 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/bifrost.json', [NetworkNames.BifrostKusama]: 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/bifrost.json', [NetworkNames.Edgeware]: 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/edg.json', - [NetworkNames.ZkSyncGoerli]: - 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/zksyncgoerli.json', [NetworkNames.ZkSync]: 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/zksync.json', [NetworkNames.Rootstock]: @@ -75,8 +71,6 @@ const lists: Partial> = { 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/godwoken.json', [NetworkNames.ImmutableZkevm]: 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/imx.json', - [NetworkNames.ZChains]: - 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/zchains.json', [NetworkNames.MantaPacific]: 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/manta.json', [NetworkNames.Mode]: @@ -85,8 +79,6 @@ const lists: Partial> = { 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/opBNB.json', [NetworkNames.Palm]: 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/palm.json', - [NetworkNames.ProofOfPlayApex]: - 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/popApex.json', [NetworkNames.Scroll]: 'https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/dapps/scroll.json', [NetworkNames.Rari]: diff --git a/packages/extension/src/libs/tokens-state/index.ts b/packages/extension/src/libs/tokens-state/index.ts index 8feb22300..b86a5ec00 100644 --- a/packages/extension/src/libs/tokens-state/index.ts +++ b/packages/extension/src/libs/tokens-state/index.ts @@ -6,6 +6,7 @@ import { CustomToken, CustomErc20Token, TokenType, + CustomMassaToken, } from './types'; import { NetworkNames } from '@enkryptcom/types'; @@ -24,7 +25,7 @@ export class TokensState { */ async addErc20Token( chainName: NetworkNames, - token: CustomErc20Token, + token: CustomErc20Token | CustomMassaToken, ): Promise { let state: IState | null = await this.storage.get(StorageKeys.customTokens); diff --git a/packages/extension/src/libs/tokens-state/types.ts b/packages/extension/src/libs/tokens-state/types.ts index b64799858..8220ae87f 100644 --- a/packages/extension/src/libs/tokens-state/types.ts +++ b/packages/extension/src/libs/tokens-state/types.ts @@ -21,4 +21,8 @@ export interface CustomErc20Token extends CustomToken { address: `0x${string}`; } +export interface CustomMassaToken extends CustomToken { + address: `AS${string}`; +} + export type IState = Partial>; diff --git a/packages/extension/src/libs/utils/initialize-wallet.ts b/packages/extension/src/libs/utils/initialize-wallet.ts index 60d159be4..8456ad8a3 100644 --- a/packages/extension/src/libs/utils/initialize-wallet.ts +++ b/packages/extension/src/libs/utils/initialize-wallet.ts @@ -2,8 +2,9 @@ import KeyRing from '@/libs/keyring/keyring'; import EthereumNetworks from '@/providers/ethereum/networks'; import PolkadotNetworks from '@/providers/polkadot/networks'; import BitcoinNetworks from '@/providers/bitcoin/networks'; -import KadenaNetworks from '@/providers/kadena/networks'; import SolanaNetworks from '@/providers/solana/networks'; +import KadenaNetworks from '@/providers/kadena/networks'; +import MassaNetworks from '@/providers/massa/networks'; import { NetworkNames, WalletType } from '@enkryptcom/types'; import { getAccountsByNetworkName } from '@/libs/utils/accounts'; import BackupState from '../backup-state'; @@ -23,6 +24,9 @@ export const initAccounts = async (keyring: KeyRing) => { const ed25519sol = ( await getAccountsByNetworkName(NetworkNames.Solana) ).filter(acc => !acc.isTestWallet); + const ed25519massa = ( + await getAccountsByNetworkName(NetworkNames.Massa) + ).filter(acc => !acc.isTestWallet); if (secp256k1.length == 0) await keyring.saveNewAccount({ basePath: EthereumNetworks.ethereum.basePath, @@ -58,6 +62,13 @@ export const initAccounts = async (keyring: KeyRing) => { signerType: SolanaNetworks.solana.signer[0], walletType: WalletType.mnemonic, }); + if (ed25519massa.length == 0) + await keyring.saveNewAccount({ + basePath: MassaNetworks.Massa.basePath, + name: 'Massa Account 1', + signerType: MassaNetworks.Massa.signer[0], + walletType: WalletType.mnemonic, + }); }; export const onboardInitializeWallets = async (options: { mnemonic: string; diff --git a/packages/extension/src/libs/utils/networks.ts b/packages/extension/src/libs/utils/networks.ts index 608652fcc..2eccad1da 100644 --- a/packages/extension/src/libs/utils/networks.ts +++ b/packages/extension/src/libs/utils/networks.ts @@ -13,6 +13,8 @@ import Polkadot from '@/providers/polkadot/networks/polkadot'; import Bitcoin from '@/providers/bitcoin/networks/bitcoin'; import Kadena from '@/providers/kadena/networks/kadena'; import Solana from '@/providers/solana/networks/solana'; +import MassaNetworks from '@/providers/massa/networks'; +import Massa from '@/providers/massa/networks/mainnet'; const providerNetworks: Record> = { [ProviderName.ethereum]: EthereumNetworks, @@ -20,6 +22,7 @@ const providerNetworks: Record> = { [ProviderName.bitcoin]: BitcoinNetworks, [ProviderName.kadena]: KadenaNetworks, [ProviderName.solana]: SolanaNetworks, + [ProviderName.massa]: MassaNetworks, [ProviderName.enkrypt]: {}, }; const getAllNetworks = async ( @@ -34,7 +37,9 @@ const getAllNetworks = async ( .concat(Object.values(PolkadotNetworks) as BaseNetwork[]) .concat(Object.values(BitcoinNetworks) as BaseNetwork[]) .concat(Object.values(KadenaNetworks) as BaseNetwork[]) - .concat(Object.values(SolanaNetworks) as BaseNetwork[]); + .concat(Object.values(SolanaNetworks) as BaseNetwork[]) + .concat(Object.values(MassaNetworks) as BaseNetwork[]); + if (!includeCustom) { return allNetworks; } @@ -67,17 +72,20 @@ const DEFAULT_SUBSTRATE_NETWORK_NAME = NetworkNames.Polkadot; const DEFAULT_BTC_NETWORK_NAME = NetworkNames.Bitcoin; const DEFAULT_KADENA_NETWORK_NAME = NetworkNames.Kadena; const DEFAULT_SOLANA_NETWORK_NAME = NetworkNames.Solana; +const DEFAULT_MASSA_NETWORK_NAME = NetworkNames.Massa; const DEFAULT_EVM_NETWORK = Ethereum; const DEFAULT_SUBSTRATE_NETWORK = Polkadot; const DEFAULT_BTC_NETWORK = Bitcoin; const DEFAULT_KADENA_NETWORK = Kadena; const DEFAULT_SOLANA_NETWORK = Solana; +const DEFAULT_MASSA_NETWORK = Massa; const POPULAR_NAMES = [ NetworkNames.Bitcoin, NetworkNames.Ethereum, NetworkNames.Solana, + NetworkNames.Massa, NetworkNames.Matic, NetworkNames.Polkadot, NetworkNames.Binance, @@ -100,4 +108,6 @@ export { DEFAULT_KADENA_NETWORK_NAME, DEFAULT_SOLANA_NETWORK, DEFAULT_SOLANA_NETWORK_NAME, + DEFAULT_MASSA_NETWORK, + DEFAULT_MASSA_NETWORK_NAME, }; diff --git a/packages/extension/src/libs/utils/screening.ts b/packages/extension/src/libs/utils/screening.ts new file mode 100644 index 000000000..ae1dea90b --- /dev/null +++ b/packages/extension/src/libs/utils/screening.ts @@ -0,0 +1,32 @@ +const isGeoRestricted = async (): Promise => { + return fetch('https://partners.mewapi.io/o/ipcomply') + .then(async res => { + if (res.ok) { + const json = await res.json(); + return json.isRestricted; + } + return false; + }) + .catch(() => false); +}; + +const walletCache: Record = {}; +const isWalletRestricted = async (walletAddress: string): Promise => { + if (walletCache[walletAddress] !== undefined) + return walletCache[walletAddress]; + const result = await fetch( + `https://partners.mewapi.io/o/walletscreen?address=${walletAddress}`, + ) + .then(async res => { + if (res.ok) { + const { isRestricted } = await res.json(); + return isRestricted; + } + return false; + }) + .catch(() => false); + walletCache[walletAddress] = result; + return result; +}; + +export { isGeoRestricted, isWalletRestricted }; diff --git a/packages/extension/src/providers/common/libs/new-features.ts b/packages/extension/src/providers/common/libs/new-features.ts index 93cfa09a6..06df1bbae 100644 --- a/packages/extension/src/providers/common/libs/new-features.ts +++ b/packages/extension/src/providers/common/libs/new-features.ts @@ -1,6 +1,6 @@ import { NetworkNames } from '@enkryptcom/types'; -const newNetworks: NetworkNames[] = [NetworkNames.CoreDAO]; +const newNetworks: NetworkNames[] = [NetworkNames.Nibiru]; const newSwaps: NetworkNames[] = []; export { newNetworks, newSwaps }; diff --git a/packages/extension/src/providers/common/ui/send-transaction/send-input-amount.vue b/packages/extension/src/providers/common/ui/send-transaction/send-input-amount.vue index d90cbddf8..5d1734d2f 100644 --- a/packages/extension/src/providers/common/ui/send-transaction/send-input-amount.vue +++ b/packages/extension/src/providers/common/ui/send-transaction/send-input-amount.vue @@ -144,9 +144,14 @@ const changeFocus = () => { justify-content: flex-start; align-items: center; flex-direction: row; + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; svg { margin-right: 4px; + flex-shrink: 0; } span { @@ -157,6 +162,9 @@ const changeFocus = () => { text-align: center; letter-spacing: 0.25px; color: @tertiaryLabel; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } } diff --git a/packages/extension/src/providers/ethereum/libs/activity-handlers/index.ts b/packages/extension/src/providers/ethereum/libs/activity-handlers/index.ts index a1e12ad19..396872a5b 100644 --- a/packages/extension/src/providers/ethereum/libs/activity-handlers/index.ts +++ b/packages/extension/src/providers/ethereum/libs/activity-handlers/index.ts @@ -5,6 +5,7 @@ import TomoScan from './providers/tomoscan'; import OntEVMActivity from './providers/ont-evm'; import TelosActivity from './providers/telos'; import GodwokenActivity from './providers/godwoken'; +import RoutescanActivity from './providers/routescan'; export { RivetActivity, EtherscanActivity, @@ -13,4 +14,5 @@ export { TomoScan, TelosActivity, GodwokenActivity, + RoutescanActivity, }; diff --git a/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/etherscan/configs.ts b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/etherscan/configs.ts index 9dcf08319..0d34588d0 100644 --- a/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/etherscan/configs.ts +++ b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/etherscan/configs.ts @@ -1,79 +1,74 @@ import { NetworkNames } from '@enkryptcom/types'; const NetworkEndpoints: Record = { - [NetworkNames.Ethereum]: 'https://eth.blockscout.com/', - [NetworkNames.Binance]: 'https://api.bscscan.com/', - [NetworkNames.Matic]: 'https://polygon.blockscout.com/', - [NetworkNames.Moonbeam]: 'https://api-moonbeam.moonscan.io/', - [NetworkNames.Moonriver]: 'https://api-moonriver.moonscan.io/', - [NetworkNames.KaruraEVM]: 'https://blockscout.karura.network/', - [NetworkNames.AstarEVM]: 'https://blockscout.com/astar/', - [NetworkNames.ShidenEVM]: 'https://blockscout.com/shiden/', - [NetworkNames.Optimism]: 'https://api-optimistic.etherscan.io/', - [NetworkNames.EdgeEVM]: 'https://edgscan.live/', - [NetworkNames.Rootstock]: 'https://blockscout.com/rsk/mainnet/', - [NetworkNames.RootstockTestnet]: 'https://rootstock-testnet.blockscout.com/', + [NetworkNames.Ethereum]: 'https://eth.blockscout.com/api?', + [NetworkNames.Binance]: 'https://api.etherscan.io/v2/api?chainid=56&', + [NetworkNames.Matic]: 'https://polygon.blockscout.com/api?', + [NetworkNames.Moonbeam]: 'https://api.etherscan.io/v2/api?chainid=1284&', + [NetworkNames.Moonriver]: 'https://api.etherscan.io/v2/api?chainid=1285&', + [NetworkNames.KaruraEVM]: 'https://blockscout.karura.network/api?', + [NetworkNames.AstarEVM]: 'https://blockscout.com/astar/api?', + [NetworkNames.ShidenEVM]: 'https://blockscout.com/shiden/api?', + [NetworkNames.Optimism]: 'https://api.etherscan.io/v2/api?chainid=10&', + [NetworkNames.EdgeEVM]: 'https://edgscan.live/api?', + [NetworkNames.Rootstock]: 'https://blockscout.com/rsk/mainnet/api?', + [NetworkNames.RootstockTestnet]: + 'https://rootstock-testnet.blockscout.com/api?', [NetworkNames.SkaleBlockBrawlers]: - 'https://frayed-decent-antares.explorer.mainnet.skalenodes.com/', + 'https://frayed-decent-antares.explorer.mainnet.skalenodes.com/api?', [NetworkNames.SkaleCalypso]: - 'https://honorable-steel-rasalhague.explorer.mainnet.skalenodes.com/', + 'https://honorable-steel-rasalhague.explorer.mainnet.skalenodes.com/api?', [NetworkNames.SkaleCryptoBlades]: - 'https://affectionate-immediate-pollux.explorer.mainnet.skalenodes.com/', + 'https://affectionate-immediate-pollux.explorer.mainnet.skalenodes.com/api?', [NetworkNames.SkaleCryptoColosseum]: - 'https://haunting-devoted-deneb.explorer.mainnet.skalenodes.com/', + 'https://haunting-devoted-deneb.explorer.mainnet.skalenodes.com/api?', [NetworkNames.SkaleEuropa]: - 'https://elated-tan-skat.explorer.mainnet.skalenodes.com/', + 'https://elated-tan-skat.explorer.mainnet.skalenodes.com/api?', [NetworkNames.SkaleExorde]: - 'https://light-vast-diphda.explorer.mainnet.skalenodes.com/', + 'https://light-vast-diphda.explorer.mainnet.skalenodes.com/api?', [NetworkNames.SkaleNebula]: - 'https://green-giddy-denebola.explorer.mainnet.skalenodes.com/', + 'https://green-giddy-denebola.explorer.mainnet.skalenodes.com/api?', [NetworkNames.SkaleTitan]: - 'https://parallel-stormy-spica.explorer.mainnet.skalenodes.com/', - [NetworkNames.SkaleChaos]: - 'https://staging-fast-active-bellatrix.explorer.staging-v3.skalenodes.com/', - [NetworkNames.ZkSyncGoerli]: - 'https://block-explorer-api.testnets.zksync.dev/', - [NetworkNames.ZkSync]: 'https://block-explorer-api.mainnet.zksync.io/', - [NetworkNames.Arbitrum]: 'https://api.arbiscan.io/', - [NetworkNames.ArbitrumNova]: 'https://nova-explorer.arbitrum.io/', - [NetworkNames.Gnosis]: 'https://api.gnosisscan.io/', - [NetworkNames.Avalanche]: 'https://api.snowtrace.io/', - [NetworkNames.Aurora]: 'https://explorer.mainnet.aurora.dev/', - [NetworkNames.PuppyNet]: 'https://puppyscan.shib.io/', - [NetworkNames.Shibarium]: 'https://www.shibariumscan.io/', - [NetworkNames.MaticZK]: 'https://api-zkevm.polygonscan.com/', - [NetworkNames.Base]: 'https://api.basescan.org/', - [NetworkNames.Celo]: 'https://explorer.celo.org/mainnet/', - [NetworkNames.FormTestnet]: 'https://testnet-explorer.form.network/', - [NetworkNames.Form]: 'https://explorer.form.network/', - [NetworkNames.SyscoinNEVMTest]: 'https://explorer.tanenbaum.io/', - [NetworkNames.SyscoinNEVM]: 'https://explorer.syscoin.org/', - [NetworkNames.RolluxTest]: 'https://rollux.tanenbaum.io/', - [NetworkNames.Rollux]: 'https://explorer.rollux.com/', - [NetworkNames.Blast]: 'https://api.blastscan.io/', - [NetworkNames.Sanko]: 'https://explorer.sanko.xyz/', - [NetworkNames.Sonic]: 'https://api.sonicscan.org/', - [NetworkNames.Degen]: 'https://explorer.degen.tips/', - [NetworkNames.Ham]: 'https://explorer.ham.fun/', - [NetworkNames.Ink]: 'https://explorer.inkonchain.com/', - [NetworkNames.ImmutableZkevm]: 'https://explorer.immutable.com/', - [NetworkNames.Rari]: 'https://mainnet.explorer.rarichain.org/', - [NetworkNames.Forma]: 'https://explorer.forma.art/', - [NetworkNames.XLayer]: 'https://www.oklink.com/api/v5/explorer/xlayer/', - [NetworkNames.Linea]: 'https://api.lineascan.build/', - [NetworkNames.MantaPacific]: 'https://pacific-explorer.manta.network/', - [NetworkNames.Mode]: 'https://explorer.mode.network/', - [NetworkNames.ProofOfPlayApex]: 'https://explorer.apex.proofofplay.com/', - [NetworkNames.Scroll]: 'https://api.scrollscan.com/', - [NetworkNames.Fraxtal]: 'https://api.fraxscan.com/', - [NetworkNames.Coti]: 'https://mainnet.cotiscan.io/', + 'https://parallel-stormy-spica.explorer.mainnet.skalenodes.com/api?', + [NetworkNames.ZkSync]: 'https://block-explorer-api.mainnet.zksync.io/api?', + [NetworkNames.Arbitrum]: 'https://api.etherscan.io/v2/api?chainid=42161&', + [NetworkNames.ArbitrumNova]: 'https://api.etherscan.io/v2/api?chainid=42170&', + [NetworkNames.Gnosis]: 'https://api.etherscan.io/v2/api?chainid=100&', + [NetworkNames.Avalanche]: 'https://api.snowtrace.io/api?', + [NetworkNames.Aurora]: 'https://explorer.mainnet.aurora.dev/api?', + [NetworkNames.PuppyNet]: 'https://puppyscan.shib.io/api?', + [NetworkNames.Shibarium]: 'https://www.shibariumscan.io/api?', + [NetworkNames.MaticZK]: 'https://api.etherscan.io/v2/api?chainid=1101&', + [NetworkNames.Base]: 'https://api.etherscan.io/v2/api?chainid=8453&', + [NetworkNames.Celo]: 'https://explorer.celo.org/mainnet/api?', + [NetworkNames.SyscoinNEVMTest]: 'https://explorer.tanenbaum.io/api?', + [NetworkNames.SyscoinNEVM]: 'https://explorer.syscoin.org/api?', + [NetworkNames.RolluxTest]: 'https://rollux.tanenbaum.io/api?', + [NetworkNames.Rollux]: 'https://explorer.rollux.com/api?', + [NetworkNames.Blast]: 'https://api.etherscan.io/v2/api?chainid=81457&', + [NetworkNames.Sanko]: 'https://explorer.sanko.xyz/api?', + [NetworkNames.Sonic]: 'https://api.etherscan.io/v2/api?chainid=146&', + [NetworkNames.Degen]: 'https://explorer.degen.tips/api?', + [NetworkNames.Ink]: 'https://explorer.inkonchain.com/api?', + [NetworkNames.ImmutableZkevm]: 'https://explorer.immutable.com/api?', + [NetworkNames.Rari]: 'https://mainnet.explorer.rarichain.org/api?', + [NetworkNames.Forma]: 'https://explorer.forma.art/api?', + [NetworkNames.XLayer]: 'https://www.oklink.com/api/v5/explorer/xlayer/api?', + [NetworkNames.Linea]: 'https://api.lineascan.build/api?', + [NetworkNames.MantaPacific]: 'https://pacific-explorer.manta.network/api?', + [NetworkNames.Mode]: 'https://explorer.mode.network/api?', + [NetworkNames.Scroll]: 'https://api.scrollscan.com/api?', + [NetworkNames.Fraxtal]: 'https://api.etherscan.io/v2/api?chainid=252&', + [NetworkNames.Coti]: 'https://mainnet.cotiscan.io/api?', [NetworkNames.CytonicTestnet]: - 'https://explorer-api.evm.testnet.cytonic.com/api/', - [NetworkNames.Derive]: 'https://explorer.derive.xyz/', - [NetworkNames.Conflux]: 'https://evmapi.confluxscan.org/', - [NetworkNames.Hemi]: 'https://explorer.hemi.xyz/', - [NetworkNames.AppLayerTestnet]: 'https://testnet-explorer.applayer.com/api/', - [NetworkNames.EthereumClassic]: 'https://etc.blockscout.com/', + 'https://explorer-api.evm.testnet.cytonic.com/api/api?', + [NetworkNames.Derive]: 'https://explorer.derive.xyz/api?', + [NetworkNames.Conflux]: 'https://evmapi.confluxscan.org/api?', + [NetworkNames.Hemi]: 'https://explorer.hemi.xyz/api?', + [NetworkNames.AppLayerTestnet]: + 'https://testnet-explorer.applayer.com/api/api?', + [NetworkNames.EthereumClassic]: 'https://etc.blockscout.com/api?', + [NetworkNames.TAC]: 'https://explorer.tac.build/api?', }; export { NetworkEndpoints }; diff --git a/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/etherscan/index.ts b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/etherscan/index.ts index 557549b66..e92bd0c9b 100644 --- a/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/etherscan/index.ts +++ b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/etherscan/index.ts @@ -21,7 +21,7 @@ const getAddressActivity = async ( return cacheFetch( { // Note: would like to add offset=50 (i.e. results per page) but it seems to cause polygon API to hang - url: `${endpoint}api?module=account&action=txlist&address=${address}&sort=desc`, + url: `${endpoint}module=account&action=txlist&address=${address}&sort=desc`, headers, }, TTL, diff --git a/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/routescan/configs.ts b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/routescan/configs.ts new file mode 100644 index 000000000..5d1129b11 --- /dev/null +++ b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/routescan/configs.ts @@ -0,0 +1,8 @@ +import { NetworkNames } from '@enkryptcom/types'; + +const NetworkEndpoints: Record = { + [NetworkNames.Nibiru]: 'https://routescan.io', + [NetworkNames.NibiruTestnet]: 'https://testnet.routescan.io', +}; + +export { NetworkEndpoints }; diff --git a/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/routescan/index.ts b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/routescan/index.ts new file mode 100644 index 000000000..01c8b7126 --- /dev/null +++ b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/routescan/index.ts @@ -0,0 +1,87 @@ +import { EvmNetwork } from '@/providers/ethereum/types/evm-network'; +import { numberToHex } from 'web3-utils'; +import { + Activity, + ActivityStatus, + ActivityType, + EthereumRawInfo, +} from '@/types/activity'; +import { BaseNetwork } from '@/types/base-network'; +import { decodeTx } from '../../../transaction/decoder'; +import { NetworkEndpoints } from './configs'; +import { RoutescanTxType } from './types'; + +const getAddressActivity = async ( + address: string, + endpoint: string, + chainId: string, +): Promise => { + const limit = 50; + const decimalChainId = parseInt(chainId, 16); + const url = `${endpoint}/api/evm/all/transactions?includedChainIds=${decimalChainId}&limit=${limit}&sort=desc&fromAddresses=${address}&toAddresses=${address}`; + const response = await fetch(url); + if (!response.ok || response.status === 202) return []; + const res = await response.json(); + if (!res.items) return []; + + const results = res.items as RoutescanTxType[]; + const newResults = results.map(tx => { + const rawTx: EthereumRawInfo = { + blockHash: tx.blockHash, + blockNumber: numberToHex(tx.blockNumber), + contractAddress: tx.to?.isContract ? tx.to.id : '', + data: '0x0', + effectiveGasPrice: numberToHex(tx.gasPrice), + from: tx.from.id, + to: tx.to?.id === '' ? null : tx.to?.id, + gas: numberToHex(tx.gasLimit), + gasUsed: numberToHex(tx.gasUsed), + nonce: numberToHex(tx.txIndex), + status: tx.status, + transactionHash: tx.txHash, + value: numberToHex(tx.value), + timestamp: new Date(tx.timestamp).getTime(), + }; + return rawTx; + }); + return newResults.slice(0, limit) as EthereumRawInfo[]; +}; + +export default async ( + network: BaseNetwork, + address: string, +): Promise => { + address = address.toLowerCase(); + const endpoint = + NetworkEndpoints[network.name as keyof typeof NetworkEndpoints]; + const chainId = (network as EvmNetwork).chainID.replace('0x', ''); + const activities = await getAddressActivity(address, endpoint, chainId); + const Promises = activities.map(activity => { + return decodeTx(activity, network as EvmNetwork).then(txData => { + return { + from: activity.from, + to: activity.contractAddress + ? activity.contractAddress + : txData.tokenTo!, + isIncoming: activity.from !== address, + network: network.name, + rawInfo: activity, + status: activity.status + ? ActivityStatus.success + : ActivityStatus.failed, + timestamp: activity.timestamp ? activity.timestamp : 0, + value: txData.tokenValue, + transactionHash: activity.transactionHash, + type: ActivityType.transaction, + token: { + decimals: txData.tokenDecimals, + icon: txData.tokenImage, + name: txData.tokenName, + symbol: txData.tokenSymbol, + price: txData.currentPriceUSD.toString(), + }, + }; + }); + }); + return Promise.all(Promises); +}; diff --git a/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/routescan/types.ts b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/routescan/types.ts new file mode 100644 index 000000000..abf247084 --- /dev/null +++ b/packages/extension/src/providers/ethereum/libs/activity-handlers/providers/routescan/types.ts @@ -0,0 +1,32 @@ +export interface RoutescanTxType { + chainId: string; + blockNumber: number; + txIndex: number; + timestamp: string; + from: { + id: string; + isContract: boolean; + }; + to: { + id: string; + isContract: boolean; + alias?: string; + dapp?: any; + owner?: string; + icon?: string; + iconUrls?: Record; + tags?: string[]; + }; + blockHash: string; + txHash: string; + value: string; + gasLimit: string; + gasUsed: string; + gasPrice: string; + burnedFees: string; + methodId: string; + method?: string; + contractVerified?: boolean; + type: string; + status: boolean; +} diff --git a/packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts b/packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts index ac0043e48..f7ca87c8d 100644 --- a/packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts +++ b/packages/extension/src/providers/ethereum/libs/assets-handlers/assetinfo-mew.ts @@ -42,10 +42,6 @@ const supportedNetworks: Record = { tbName: 'astar', cgPlatform: CoingeckoPlatform.Astar, }, - [NetworkNames.Okc]: { - tbName: 'okt', - cgPlatform: CoingeckoPlatform.Okc, - }, [NetworkNames.Optimism]: { tbName: 'op', cgPlatform: CoingeckoPlatform.Optimism, @@ -62,10 +58,6 @@ const supportedNetworks: Record = { tbName: 'sdn', cgPlatform: CoingeckoPlatform.Shiden, }, - [NetworkNames.Canto]: { - tbName: 'canto', - cgPlatform: CoingeckoPlatform.Canto, - }, [NetworkNames.Rootstock]: { cgPlatform: CoingeckoPlatform.Rootstock, bsEndpoint: true, @@ -143,21 +135,14 @@ const supportedNetworks: Record = { cgPlatform: CoingeckoPlatform.Blast, }, [NetworkNames.Sanko]: { - tbName: 'sanko', + tbName: '', cgPlatform: CoingeckoPlatform.Sanko, + bsEndpoint: true, }, [NetworkNames.Degen]: { tbName: 'degen', cgPlatform: CoingeckoPlatform.Degen, }, - [NetworkNames.XLayer]: { - tbName: 'xlayer', - cgPlatform: CoingeckoPlatform.XLayer, - }, - [NetworkNames.ProofOfPlayApex]: { - tbName: 'apex', - cgPlatform: undefined, - }, [NetworkNames.Godwoken]: { tbName: 'ckb', cgPlatform: CoingeckoPlatform.Godwoken, diff --git a/packages/extension/src/providers/ethereum/libs/assets-handlers/blockscout.ts b/packages/extension/src/providers/ethereum/libs/assets-handlers/blockscout.ts index b78b132a0..1c8ceb653 100644 --- a/packages/extension/src/providers/ethereum/libs/assets-handlers/blockscout.ts +++ b/packages/extension/src/providers/ethereum/libs/assets-handlers/blockscout.ts @@ -28,8 +28,8 @@ const getBlockscoutBalances = ( address: string, ): Promise => { const encodedAddress = encodeURIComponent(address); - const nativeTokenUrl = `${NetworkEndpoints[chain]}api/v2/addresses/${encodedAddress}`; - const tokenBalancesUrl = `${NetworkEndpoints[chain]}api/v2/addresses/${encodedAddress}/tokens?type=ERC-20`; + const nativeTokenUrl = `${NetworkEndpoints[chain].replace('api?', '')}api/v2/addresses/${encodedAddress}`; + const tokenBalancesUrl = `${NetworkEndpoints[chain].replace('api?', '')}api/v2/addresses/${encodedAddress}/tokens?type=ERC-20`; return Promise.all([ fetch(nativeTokenUrl).then(res => res.json()), diff --git a/packages/extension/src/providers/ethereum/libs/assets-handlers/token-lists.ts b/packages/extension/src/providers/ethereum/libs/assets-handlers/token-lists.ts index f0d55856c..25d046f6c 100644 --- a/packages/extension/src/providers/ethereum/libs/assets-handlers/token-lists.ts +++ b/packages/extension/src/providers/ethereum/libs/assets-handlers/token-lists.ts @@ -11,7 +11,6 @@ const TokenList: Record = { [NetworkNames.Base]: `https://tokens.coingecko.com/${CoingeckoPlatform.Base}/all.json`, [NetworkNames.Binance]: `https://tokens.coingecko.com/${CoingeckoPlatform.Binance}/all.json`, [NetworkNames.Blast]: `https://tokens.coingecko.com/${CoingeckoPlatform.Blast}/all.json`, - [NetworkNames.Canto]: `https://tokens.coingecko.com/${CoingeckoPlatform.Canto}/all.json`, [NetworkNames.Celo]: `https://tokens.coingecko.com/${CoingeckoPlatform.Celo}/all.json`, [NetworkNames.Degen]: `https://tokens.coingecko.com/${CoingeckoPlatform.Degen}/all.json`, [NetworkNames.Ethereum]: `https://tokens.coingecko.com/${CoingeckoPlatform.Ethereum}/all.json`, @@ -27,10 +26,8 @@ const TokenList: Record = { [NetworkNames.Mode]: `https://tokens.coingecko.com/${CoingeckoPlatform.Mode}/all.json`, [NetworkNames.Moonbeam]: `https://tokens.coingecko.com/${CoingeckoPlatform.Moonbeam}/all.json`, [NetworkNames.Moonriver]: `https://tokens.coingecko.com/${CoingeckoPlatform.Moonriver}/all.json`, - [NetworkNames.Okc]: `https://tokens.coingecko.com/${CoingeckoPlatform.Okc}/all.json`, [NetworkNames.OpBNB]: `https://tokens.coingecko.com/${CoingeckoPlatform.OpBNB}/all.json`, [NetworkNames.Optimism]: `https://tokens.coingecko.com/${CoingeckoPlatform.Optimism}/all.json`, - [NetworkNames.ProofOfPlayApex]: `https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/tokenlists/apex.json`, [NetworkNames.Rari]: `https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/tokenlists/rari.json`, [NetworkNames.Rollux]: `https://tokens.coingecko.com/${CoingeckoPlatform.Rollux}/all.json`, [NetworkNames.Rootstock]: `https://raw.githubusercontent.com/enkryptcom/dynamic-data/main/tokenlists/rsk.json`, @@ -42,7 +39,6 @@ const TokenList: Record = { [NetworkNames.SyscoinNEVM]: `https://tokens.coingecko.com/${CoingeckoPlatform.Syscoin}/all.json`, [NetworkNames.Telos]: `https://tokens.coingecko.com/${CoingeckoPlatform.Telos}/all.json`, [NetworkNames.TomoChain]: `https://tokens.coingecko.com/${CoingeckoPlatform.TomoChain}/all.json`, - [NetworkNames.XLayer]: `https://tokens.coingecko.com/${CoingeckoPlatform.XLayer}/all.json`, [NetworkNames.ZkSync]: `https://tokens.coingecko.com/${CoingeckoPlatform.Zksync}/all.json`, [NetworkNames.Gravity]: `https://tokens.coingecko.com/${CoingeckoPlatform.Gravity}/all.json`, [NetworkNames.Abstract]: `https://tokens.coingecko.com/${CoingeckoPlatform.Abstract}/all.json`, diff --git a/packages/extension/src/providers/ethereum/libs/assets-handlers/types/tokenbalance-mew.ts b/packages/extension/src/providers/ethereum/libs/assets-handlers/types/tokenbalance-mew.ts index 7527bc7be..fd08f53af 100644 --- a/packages/extension/src/providers/ethereum/libs/assets-handlers/types/tokenbalance-mew.ts +++ b/packages/extension/src/providers/ethereum/libs/assets-handlers/types/tokenbalance-mew.ts @@ -31,12 +31,10 @@ export type SupportedNetworkNames = | NetworkNames.Ethereum | NetworkNames.Matic | NetworkNames.AstarEVM - | NetworkNames.Okc | NetworkNames.Optimism | NetworkNames.Moonriver | NetworkNames.Moonbeam | NetworkNames.ShidenEVM - | NetworkNames.Canto | NetworkNames.Rootstock | NetworkNames.Arbitrum | NetworkNames.ArbitrumNova @@ -58,8 +56,6 @@ export type SupportedNetworkNames = | NetworkNames.Degen | NetworkNames.Blast | NetworkNames.Solana - | NetworkNames.XLayer - | NetworkNames.ProofOfPlayApex | NetworkNames.Godwoken | NetworkNames.Linea | NetworkNames.MantaPacific diff --git a/packages/extension/src/providers/ethereum/methods/eth_accounts.ts b/packages/extension/src/providers/ethereum/methods/eth_accounts.ts index 95b6c5685..1976fa025 100644 --- a/packages/extension/src/providers/ethereum/methods/eth_accounts.ts +++ b/packages/extension/src/providers/ethereum/methods/eth_accounts.ts @@ -20,7 +20,8 @@ const method: MiddlewareFunction = async function ( if (payload.options && payload.options.domain) { if (!isInitialized) { res(null, payload.method === 'eth_coinbase' ? '' : []); - return throttledOpenOnboard(); + throttledOpenOnboard(); + return; } const accountsState = new AccountState(); accountsState diff --git a/packages/extension/src/providers/ethereum/networks/astr.ts b/packages/extension/src/providers/ethereum/networks/astr.ts index f76023af6..75de7856e 100644 --- a/packages/extension/src/providers/ethereum/networks/astr.ts +++ b/packages/extension/src/providers/ethereum/networks/astr.ts @@ -15,7 +15,7 @@ const astrOptions: EvmNetworkOptions = { isTestNetwork: false, currencyName: 'ASTR', currencyNameLong: 'Astar', - node: 'wss://astar.public.blastapi.io/', + node: 'wss://astar.api.onfinality.io/public-ws', icon, coingeckoID: 'astar', coingeckoPlatform: CoingeckoPlatform.Astar, diff --git a/packages/extension/src/providers/ethereum/networks/cagaAnkara.ts b/packages/extension/src/providers/ethereum/networks/cagaAnkara.ts deleted file mode 100644 index 73da9ee2f..000000000 --- a/packages/extension/src/providers/ethereum/networks/cagaAnkara.ts +++ /dev/null @@ -1,25 +0,0 @@ -import icon from './icons/caga.webp'; -import { NetworkNames } from '@enkryptcom/types'; -import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; -import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; - -const cagaTestOptions: EvmNetworkOptions = { - name: NetworkNames.CagaAnkara, - name_long: 'CAGA Ankara Testnet', - homePage: 'https://www.cagacrypto.com/', - blockExplorerTX: - 'https://explorer.ankara-cagacrypto.com/transaction/[[txHash]]', - blockExplorerAddr: - 'https://explorer.ankara-cagacrypto.com/address/[[address]]', - chainID: '0x11c4a', - isTestNetwork: true, - currencyName: 'CAGA', - currencyNameLong: 'CAGA', - node: 'wss://wss.ankara-cagacrypto.com', - icon, - activityHandler: wrapActivityHandler(() => Promise.resolve([])), -}; - -const cagaAnkara = new EvmNetwork(cagaTestOptions); - -export default cagaAnkara; diff --git a/packages/extension/src/providers/ethereum/networks/canto.ts b/packages/extension/src/providers/ethereum/networks/canto.ts deleted file mode 100644 index 06f118518..000000000 --- a/packages/extension/src/providers/ethereum/networks/canto.ts +++ /dev/null @@ -1,27 +0,0 @@ -import icon from './icons/canto.webp'; -import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; -import { CoingeckoPlatform, NetworkNames } from '@enkryptcom/types'; -import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; -import assetsInfoHandler from '@/providers/ethereum/libs/assets-handlers/assetinfo-mew'; - -const cantoOptions: EvmNetworkOptions = { - name: NetworkNames.Canto, - name_long: 'Canto', - homePage: 'https://canto.io/', - blockExplorerTX: 'https://evm.explorer.canto.io/tx/[[txHash]]', - blockExplorerAddr: 'https://evm.explorer.canto.io/address/[[address]]', - chainID: '0x1e14', - isTestNetwork: false, - currencyName: 'CANTO', - currencyNameLong: 'Canto', - node: 'https://canto.gravitychain.io/', - icon, - coingeckoID: 'canto', - coingeckoPlatform: CoingeckoPlatform.Canto, - assetsInfoHandler, - activityHandler: wrapActivityHandler(() => Promise.resolve([])), -}; - -const canto = new EvmNetwork(cantoOptions); - -export default canto; diff --git a/packages/extension/src/providers/ethereum/networks/coti-devnet.ts b/packages/extension/src/providers/ethereum/networks/coti-devnet.ts deleted file mode 100644 index 39eacd8b7..000000000 --- a/packages/extension/src/providers/ethereum/networks/coti-devnet.ts +++ /dev/null @@ -1,23 +0,0 @@ -import icon from './icons/coti.webp'; -import { NetworkNames } from '@enkryptcom/types'; -import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; -import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; - -const cotiDevnetOptions: EvmNetworkOptions = { - name: NetworkNames.CotiDevnet, - name_long: 'COTI Devnet', - homePage: 'https://coti.io/', - blockExplorerTX: 'https://explorer-devnet.coti.io/tx/[[txHash]]', - blockExplorerAddr: 'https://explorer-devnet.coti.io/address/[[address]]', - chainID: '0xc767a8', - isTestNetwork: true, - currencyName: 'COTI2', - currencyNameLong: 'COTI2 Devnet', - node: 'https://devnet.coti.io/rpc', - icon, - activityHandler: wrapActivityHandler(() => Promise.resolve([])), -}; - -const cotiDevnet = new EvmNetwork(cotiDevnetOptions); - -export default cotiDevnet; diff --git a/packages/extension/src/providers/ethereum/networks/coti-testnet.ts b/packages/extension/src/providers/ethereum/networks/coti-testnet.ts new file mode 100644 index 000000000..ffd4a3153 --- /dev/null +++ b/packages/extension/src/providers/ethereum/networks/coti-testnet.ts @@ -0,0 +1,23 @@ +import icon from './icons/coti.webp'; +import { NetworkNames } from '@enkryptcom/types'; +import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; +import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; + +const cotiTestnetOptions: EvmNetworkOptions = { + name: NetworkNames.CotiTestnet, + name_long: 'COTI Testnet', + homePage: 'https://coti.io/', + blockExplorerTX: 'https://testnet.cotiscan.io/tx/[[txHash]]', + blockExplorerAddr: 'https://testnet.cotiscan.io/address/[[address]]', + chainID: '0x6c11a0', + isTestNetwork: true, + currencyName: 'COTI', + currencyNameLong: 'COTI Testnet', + node: 'wss://testnet.coti.io/ws', + icon, + activityHandler: wrapActivityHandler(() => Promise.resolve([])), +}; + +const cotiTestnet = new EvmNetwork(cotiTestnetOptions); + +export default cotiTestnet; diff --git a/packages/extension/src/providers/ethereum/networks/form-testnet.ts b/packages/extension/src/providers/ethereum/networks/form-testnet.ts deleted file mode 100644 index bfc311aa5..000000000 --- a/packages/extension/src/providers/ethereum/networks/form-testnet.ts +++ /dev/null @@ -1,25 +0,0 @@ -import icon from './icons/form.webp'; -import { NetworkNames } from '@enkryptcom/types'; -import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; -import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; -import { EtherscanActivity } from '../libs/activity-handlers'; - -const formTestnetOptions: EvmNetworkOptions = { - name: NetworkNames.FormTestnet, - name_long: 'Form Testnet', - homePage: 'https://docs.form.network', - blockExplorerTX: 'https://testnet-explorer.form.network/tx/[[txHash]]', - blockExplorerAddr: - 'https://testnet-explorer.form.network/address/[[address]]', - chainID: '0x20726', - isTestNetwork: true, - currencyName: 'ETH', - currencyNameLong: 'Ethereum', - node: 'wss://testnet-rpc.form.network/ws', - icon, - activityHandler: wrapActivityHandler(EtherscanActivity), -}; - -const formTestnet = new EvmNetwork(formTestnetOptions); - -export default formTestnet; diff --git a/packages/extension/src/providers/ethereum/networks/form.ts b/packages/extension/src/providers/ethereum/networks/form.ts deleted file mode 100644 index 6d93830f4..000000000 --- a/packages/extension/src/providers/ethereum/networks/form.ts +++ /dev/null @@ -1,24 +0,0 @@ -import icon from './icons/form.webp'; -import { NetworkNames } from '@enkryptcom/types'; -import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; -import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; -import { EtherscanActivity } from '../libs/activity-handlers'; - -const formOptions: EvmNetworkOptions = { - name: NetworkNames.Form, - name_long: 'Form Mainnet', - homePage: 'https://docs.form.network', - blockExplorerTX: 'https://explorer.form.network/tx/[[txHash]]', - blockExplorerAddr: 'https://explorer.form.network/address/[[address]]', - chainID: '0x1de', - isTestNetwork: false, - currencyName: 'ETH', - currencyNameLong: 'Ethereum', - node: 'wss://rpc.form.network/ws', - icon, - activityHandler: wrapActivityHandler(EtherscanActivity), -}; - -const form = new EvmNetwork(formOptions); - -export default form; diff --git a/packages/extension/src/providers/ethereum/networks/ftm.ts b/packages/extension/src/providers/ethereum/networks/ftm.ts index 8cdec0328..e6bad343a 100644 --- a/packages/extension/src/providers/ethereum/networks/ftm.ts +++ b/packages/extension/src/providers/ethereum/networks/ftm.ts @@ -8,13 +8,13 @@ const ftmOptions: EvmNetworkOptions = { name: NetworkNames.Fantom, name_long: 'Fantom', homePage: 'https://fantom.foundation/', - blockExplorerTX: 'https://ftmscan.com/tx/[[txHash]]', - blockExplorerAddr: 'https://ftmscan.com/address/[[address]]', + blockExplorerTX: 'https://explorer.fantom.network/transactions/[[txHash]]', + blockExplorerAddr: 'https://explorer.fantom.network/address/[[address]]', chainID: '0xfa', isTestNetwork: false, currencyName: 'FTM', currencyNameLong: 'Fantom', - node: 'wss://fantom-rpc.publicnode.com', + node: 'https://rpc.fantom.network', icon, coingeckoID: 'fantom', coingeckoPlatform: CoingeckoPlatform.Fantom, diff --git a/packages/extension/src/providers/ethereum/networks/ham.ts b/packages/extension/src/providers/ethereum/networks/ham.ts deleted file mode 100644 index 98a4e1511..000000000 --- a/packages/extension/src/providers/ethereum/networks/ham.ts +++ /dev/null @@ -1,25 +0,0 @@ -import icon from './icons/ham.webp'; -import { NetworkNames } from '@enkryptcom/types'; -import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; -import { EtherscanActivity } from '../libs/activity-handlers'; -import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; - -const ethOptions: EvmNetworkOptions = { - name: NetworkNames.Ham, - name_long: 'Ham Chain', - homePage: 'https://ham.fun/', - blockExplorerTX: 'https://explorer.ham.fun/tx/[[txHash]]', - blockExplorerAddr: 'https://explorer.ham.fun/address/[[address]]', - chainID: '0x13f8', - isTestNetwork: false, - currencyName: 'ETH', - currencyNameLong: 'Ethereum', - node: 'https://rpc.ham.fun', - icon, - coingeckoID: 'ethereum', - activityHandler: wrapActivityHandler(EtherscanActivity), -}; - -const eth = new EvmNetwork(ethOptions); - -export default eth; diff --git a/packages/extension/src/providers/ethereum/networks/icons/apex.webp b/packages/extension/src/providers/ethereum/networks/icons/apex.webp deleted file mode 100644 index deb50f17d..000000000 Binary files a/packages/extension/src/providers/ethereum/networks/icons/apex.webp and /dev/null differ diff --git a/packages/extension/src/providers/ethereum/networks/icons/caga.webp b/packages/extension/src/providers/ethereum/networks/icons/caga.webp deleted file mode 100644 index bdb574f5e..000000000 Binary files a/packages/extension/src/providers/ethereum/networks/icons/caga.webp and /dev/null differ diff --git a/packages/extension/src/providers/ethereum/networks/icons/canto.webp b/packages/extension/src/providers/ethereum/networks/icons/canto.webp deleted file mode 100644 index 11f60f37a..000000000 Binary files a/packages/extension/src/providers/ethereum/networks/icons/canto.webp and /dev/null differ diff --git a/packages/extension/src/providers/ethereum/networks/icons/nibiru.webp b/packages/extension/src/providers/ethereum/networks/icons/nibiru.webp new file mode 100644 index 000000000..242b8da76 Binary files /dev/null and b/packages/extension/src/providers/ethereum/networks/icons/nibiru.webp differ diff --git a/packages/extension/src/providers/ethereum/networks/icons/tac.webp b/packages/extension/src/providers/ethereum/networks/icons/tac.webp new file mode 100644 index 000000000..f4673fafe Binary files /dev/null and b/packages/extension/src/providers/ethereum/networks/icons/tac.webp differ diff --git a/packages/extension/src/providers/ethereum/networks/icons/zcd.webp b/packages/extension/src/providers/ethereum/networks/icons/zcd.webp deleted file mode 100644 index 9eda52edd..000000000 Binary files a/packages/extension/src/providers/ethereum/networks/icons/zcd.webp and /dev/null differ diff --git a/packages/extension/src/providers/ethereum/networks/index.ts b/packages/extension/src/providers/ethereum/networks/index.ts index 993dac3ce..470e73a72 100755 --- a/packages/extension/src/providers/ethereum/networks/index.ts +++ b/packages/extension/src/providers/ethereum/networks/index.ts @@ -10,11 +10,10 @@ import okcNode from './okc'; import shidenEvmNode from './sdn'; import astarEvmNode from './astr'; import optimismNode from './op'; -import cantoNode from './canto'; import rootstockNode from './rsk'; import rootstockTestnetNode from './rsk-testnet'; import edgeEvmNode from './edg'; -import zkGoerliNode from './zkgoerli'; +import zkSepoliaNode from './zksepolia'; import vicNode from './vic'; import zkSyncNode from './zksync'; import arbNode from './arb'; @@ -32,20 +31,15 @@ import sepoliaNode from './sepolia'; import baseNode from './base'; import celoNode from './celo'; import shibNode from './shib'; -import formTestnet from './form-testnet'; -import formNode from './form'; import syscoinNEVMTestNode from './syscoin/nevm-testnet'; import syscoinNEVMNode from './syscoin/nevm'; import rolluxTestNode from './syscoin/rollux-testnet'; import rolluxNode from './syscoin/rollux'; -import cagaAnkara from './cagaAnkara'; import sonicNode from './sonic'; import telosNode from './tlos'; import blastNode from './blast'; import sankoNode from './dmt'; import degenNode from './degen'; -import hamNode from './ham'; -import zcdNode from './zcd'; import immutableZkevmNode from './immutable-zkevm'; import rariNode from './rari'; import formaNode from './forma'; @@ -56,9 +50,8 @@ import mantaPacificNode from './manta-pacific'; import modeNode from './mode'; import opbnbNode from './op-bnb'; import palmNode from './palm'; -import proofOfPlayApexNode from './pop-apex'; import scrollNode from './scroll'; -import cotiDevnetNode from './coti-devnet'; +import cotiTestnetNode from './coti-testnet'; import hoodiNode from './hoodi'; import bitrockNode from './bitrock'; import fraxtalNode from './fraxtal'; @@ -78,6 +71,9 @@ import conflux from './conflux'; import hemi from './hemi'; import coredao from './coredao'; import appLayerTestnet from './applayer-testnet'; +import nibiru from './nibiru'; +import nibiruTestnet from './nibiru-testnet'; +// import tac from './tac'; waiting for RPC fix export default { sepolia: sepoliaNode, @@ -93,11 +89,10 @@ export default { shidenEvm: shidenEvmNode, astarEvm: astarEvmNode, op: optimismNode, - canto: cantoNode, rootstock: rootstockNode, rootstockTestnet: rootstockTestnetNode, edgeEvm: edgeEvmNode, - zkGoerli: zkGoerliNode, + zkSepolia: zkSepoliaNode, vic: vicNode, zkSync: zkSyncNode, skaleEuropa: skale.europaNode, @@ -108,7 +103,6 @@ export default { skaleExorde: skale.exordeNode, skaleNebula: skale.nebulaNode, skaleTitan: skale.titanNode, - skaleChaos: skale.chaosNode, ontEVM: ontEVMNode, arbitrum: arbNode, arbitrumNova: arbNovaNode, @@ -121,20 +115,15 @@ export default { base: baseNode, celo: celoNode, shib: shibNode, - formTestnet: formTestnet, - form: formNode, syscoinNEVMTest: syscoinNEVMTestNode, syscoinNEVM: syscoinNEVMNode, rolluxTest: rolluxTestNode, rollux: rolluxNode, - cagaAnkara: cagaAnkara, sonic: sonicNode, telos: telosNode, blast: blastNode, sanko: sankoNode, degen: degenNode, - ham: hamNode, - zcd: zcdNode, immutableZkevm: immutableZkevmNode, rari: rariNode, forma: formaNode, @@ -145,9 +134,8 @@ export default { mode: modeNode, opbnb: opbnbNode, palm: palmNode, - popApex: proofOfPlayApexNode, scroll: scrollNode, - cotiDevnet: cotiDevnetNode, + cotiTestnetNode: cotiTestnetNode, hoodi: hoodiNode, bitrock: bitrockNode, frax: fraxtalNode, @@ -167,5 +155,8 @@ export default { conflux: conflux, hemi: hemi, coredao: coredao, + nibiru: nibiru, + nibiruTestnet: nibiruTestnet, appLayerTestnet: appLayerTestnet, + // tac: tac, waiting for RPC fix }; diff --git a/packages/extension/src/providers/ethereum/networks/nibiru-testnet.ts b/packages/extension/src/providers/ethereum/networks/nibiru-testnet.ts new file mode 100644 index 000000000..e508307e5 --- /dev/null +++ b/packages/extension/src/providers/ethereum/networks/nibiru-testnet.ts @@ -0,0 +1,24 @@ +import icon from './icons/nibiru.webp'; +import { NetworkNames } from '@enkryptcom/types'; +import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; +import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; +import { RoutescanActivity } from '../libs/activity-handlers'; + +const nibiruTestnetOptions: EvmNetworkOptions = { + name: NetworkNames.NibiruTestnet, + name_long: 'Nibiru Testnet', + homePage: 'https://nibiru.fi', + blockExplorerTX: 'https://testnet.nibiscan.io/tx/[[txHash]]', + blockExplorerAddr: 'https://testnet.nibiscan.io/address/[[address]]', + chainID: '0x1AFF', + isTestNetwork: true, + currencyName: 'NIBI', + currencyNameLong: 'Nibiru', + node: 'https://evm-rpc.testnet-2.nibiru.fi', + icon, + activityHandler: wrapActivityHandler(RoutescanActivity), +}; + +const nibiruTestnet = new EvmNetwork(nibiruTestnetOptions); + +export default nibiruTestnet; diff --git a/packages/extension/src/providers/ethereum/networks/nibiru.ts b/packages/extension/src/providers/ethereum/networks/nibiru.ts new file mode 100644 index 000000000..65915b489 --- /dev/null +++ b/packages/extension/src/providers/ethereum/networks/nibiru.ts @@ -0,0 +1,26 @@ +import icon from './icons/nibiru.webp'; +import { CoingeckoPlatform, NetworkNames } from '@enkryptcom/types'; +import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; +import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; +import { RoutescanActivity } from '../libs/activity-handlers'; + +const nibiruOptions: EvmNetworkOptions = { + name: NetworkNames.Nibiru, + name_long: 'Nibiru', + homePage: 'https://nibiru.fi', + blockExplorerTX: 'https://nibiscan.io/tx/[[txHash]]', + blockExplorerAddr: 'https://nibiscan.io/address/[[address]]', + chainID: '0x1AF4', + isTestNetwork: false, + currencyName: 'NIBI', + currencyNameLong: 'Nibiru', + node: 'https://evm-rpc.nibiru.fi', + icon, + coingeckoID: 'nibiru', + coingeckoPlatform: CoingeckoPlatform.Nibiru, + activityHandler: wrapActivityHandler(RoutescanActivity), +}; + +const nibiru = new EvmNetwork(nibiruOptions); + +export default nibiru; diff --git a/packages/extension/src/providers/ethereum/networks/okc.ts b/packages/extension/src/providers/ethereum/networks/okc.ts index e211bbbe3..4c2f5e5ba 100644 --- a/packages/extension/src/providers/ethereum/networks/okc.ts +++ b/packages/extension/src/providers/ethereum/networks/okc.ts @@ -2,7 +2,6 @@ import icon from './icons/okc.webp'; import { CoingeckoPlatform, NetworkNames } from '@enkryptcom/types'; import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; -import assetsInfoHandler from '@/providers/ethereum/libs/assets-handlers/assetinfo-mew'; const okcOptions: EvmNetworkOptions = { name: NetworkNames.Okc, @@ -18,7 +17,6 @@ const okcOptions: EvmNetworkOptions = { icon, coingeckoID: 'oec-token', coingeckoPlatform: CoingeckoPlatform.Okc, - assetsInfoHandler, activityHandler: wrapActivityHandler(() => Promise.resolve([])), }; diff --git a/packages/extension/src/providers/ethereum/networks/palm.ts b/packages/extension/src/providers/ethereum/networks/palm.ts index 84481ee12..ce8c68df6 100644 --- a/packages/extension/src/providers/ethereum/networks/palm.ts +++ b/packages/extension/src/providers/ethereum/networks/palm.ts @@ -16,7 +16,7 @@ const palmNetworkOptions: EvmNetworkOptions = { isTestNetwork: false, currencyName: 'PALM', currencyNameLong: 'PALM', - node: 'https://palm-mainnet.public.blastapi.io', + node: 'https://palm-mainnet.infura.io/v3/3a961d6501e54add9a41aa53f15de99b', icon, coingeckoID: 'palm-ai', activityHandler: wrapActivityHandler(() => Promise.resolve([])), diff --git a/packages/extension/src/providers/ethereum/networks/pop-apex.ts b/packages/extension/src/providers/ethereum/networks/pop-apex.ts deleted file mode 100644 index 6af47aac8..000000000 --- a/packages/extension/src/providers/ethereum/networks/pop-apex.ts +++ /dev/null @@ -1,28 +0,0 @@ -import icon from './icons/apex.webp'; -import { NetworkNames } from '@enkryptcom/types'; -import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; -import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; -import { EtherscanActivity } from '../libs/activity-handlers'; -import assetsInfoHandler from '@/providers/ethereum/libs/assets-handlers/assetinfo-mew'; - -const apexOptions: EvmNetworkOptions = { - name: NetworkNames.ProofOfPlayApex, - name_long: 'Proof of Play Apex', - homePage: 'https://www.proofofplay.com/', - blockExplorerTX: 'https://explorer.apex.proofofplay.com/tx/[[txHash]]', - blockExplorerAddr: - 'https://explorer.apex.proofofplay.com/address/[[address]]', - chainID: '0x1142c', - isTestNetwork: false, - currencyName: 'ETH', - currencyNameLong: 'Ethereum', - node: 'https://rpc.apex.proofofplay.com', - icon, - coingeckoID: 'ethereum', - assetsInfoHandler, - activityHandler: wrapActivityHandler(EtherscanActivity), -}; - -const apex = new EvmNetwork(apexOptions); - -export default apex; diff --git a/packages/extension/src/providers/ethereum/networks/skale/chaos.ts b/packages/extension/src/providers/ethereum/networks/skale/chaos.ts deleted file mode 100644 index 987136761..000000000 --- a/packages/extension/src/providers/ethereum/networks/skale/chaos.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { NetworkNames } from '@enkryptcom/types'; -import { - SkaleParams, - createSkaleEvmNetwork, - ICustomSKALEAsset, -} from './skale-base'; - -const skaleOptions: SkaleParams = { - name: NetworkNames.SkaleChaos, - name_long: 'CHAOS chain | SKALE', - chainName: 'staging-fast-active-bellatrix', - chainID: '0x50877ed6', - isTestNetwork: true, -}; - -const assets: ICustomSKALEAsset[] = [ - { - name: 'Ethereum Clone', - symbol: 'ETHC', - address: '0xD2Aaa00700000000000000000000000000000000', - coingeckoID: 'ethereum', - }, -]; - -export default createSkaleEvmNetwork(skaleOptions, assets); diff --git a/packages/extension/src/providers/ethereum/networks/skale/index.ts b/packages/extension/src/providers/ethereum/networks/skale/index.ts index 7e8083008..3a4e07979 100644 --- a/packages/extension/src/providers/ethereum/networks/skale/index.ts +++ b/packages/extension/src/providers/ethereum/networks/skale/index.ts @@ -6,7 +6,6 @@ import exordeNode from './exorde'; import europaNode from './europa'; import nebulaNode from './nebula'; import titanNode from './titan'; -import chaosNode from './chaos'; export { blockBrawlersNode, @@ -17,5 +16,4 @@ export { europaNode, nebulaNode, titanNode, - chaosNode, }; diff --git a/packages/extension/src/providers/ethereum/networks/story.ts b/packages/extension/src/providers/ethereum/networks/story.ts index 6c01dea9b..143cdc803 100644 --- a/packages/extension/src/providers/ethereum/networks/story.ts +++ b/packages/extension/src/providers/ethereum/networks/story.ts @@ -10,7 +10,7 @@ const storyOptions: EvmNetworkOptions = { homePage: 'https://www.story.foundation/', blockExplorerTX: 'https://www.storyscan.xyz/tx/[[txHash]]', blockExplorerAddr: 'https://www.storyscan.xyz/address/[[address]]', - chainID: '0x5EF', + chainID: '0x5ea', isTestNetwork: false, currencyName: 'IP', currencyNameLong: 'IP', diff --git a/packages/extension/src/providers/ethereum/networks/tac.ts b/packages/extension/src/providers/ethereum/networks/tac.ts new file mode 100644 index 000000000..db8711788 --- /dev/null +++ b/packages/extension/src/providers/ethereum/networks/tac.ts @@ -0,0 +1,25 @@ +import icon from './icons/tac.webp'; +import { NetworkNames } from '@enkryptcom/types'; +import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; +import { EtherscanActivity } from '../libs/activity-handlers'; +import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; + +const tacOptions: EvmNetworkOptions = { + name: NetworkNames.TAC, + name_long: 'TAC', + homePage: 'https://tac.build', + blockExplorerTX: 'https://explorer.tac.build/tx/[[txHash]]', + blockExplorerAddr: 'https://explorer.tac.build/address/[[address]]', + chainID: '0xef', + isTestNetwork: false, + currencyName: 'TAC', + currencyNameLong: 'TAC', + node: 'https://rpc.ankr.com/tac', + icon, + coingeckoID: 'tac', + activityHandler: wrapActivityHandler(EtherscanActivity), +}; + +const tac = new EvmNetwork(tacOptions); + +export default tac; diff --git a/packages/extension/src/providers/ethereum/networks/xlayer.ts b/packages/extension/src/providers/ethereum/networks/xlayer.ts index 29f0882d6..7609ea7ae 100644 --- a/packages/extension/src/providers/ethereum/networks/xlayer.ts +++ b/packages/extension/src/providers/ethereum/networks/xlayer.ts @@ -2,7 +2,6 @@ import icon from './icons/xlayer.webp'; import { NetworkNames, CoingeckoPlatform } from '@enkryptcom/types'; import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; -import assetsInfoHandler from '@/providers/ethereum/libs/assets-handlers/assetinfo-mew'; const xlayerOptions: EvmNetworkOptions = { name: NetworkNames.XLayer, @@ -15,11 +14,10 @@ const xlayerOptions: EvmNetworkOptions = { isTestNetwork: false, currencyName: 'OKB', currencyNameLong: 'OKB', - node: 'wss://ws.xlayer.tech', + node: 'https://xlayerrpc.okx.com', icon, coingeckoID: 'okb', coingeckoPlatform: CoingeckoPlatform.XLayer, - assetsInfoHandler, activityHandler: wrapActivityHandler(() => Promise.resolve([])), }; diff --git a/packages/extension/src/providers/ethereum/networks/zcd.ts b/packages/extension/src/providers/ethereum/networks/zcd.ts deleted file mode 100644 index 27d09fd6f..000000000 --- a/packages/extension/src/providers/ethereum/networks/zcd.ts +++ /dev/null @@ -1,24 +0,0 @@ -import icon from './icons/zcd.webp'; -import { NetworkNames } from '@enkryptcom/types'; -import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; -import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; - -const zcdOptions: EvmNetworkOptions = { - name: NetworkNames.ZChains, - name_long: 'ZChains', - homePage: 'https://www.zchains.com', - blockExplorerTX: 'https://scan.zchains.com/tx/[[txHash]]', - blockExplorerAddr: 'https://scan.zchains.com/address/[[address]]', - chainID: '0x290e8', - isTestNetwork: false, - currencyName: 'ZCD', - currencyNameLong: 'ZChains', - node: 'https://rpc.zchains.com', - icon, - coingeckoID: 'zchains', - activityHandler: wrapActivityHandler(() => Promise.resolve([])), -}; - -const zcd = new EvmNetwork(zcdOptions); - -export default zcd; diff --git a/packages/extension/src/providers/ethereum/networks/zkgoerli.ts b/packages/extension/src/providers/ethereum/networks/zkgoerli.ts deleted file mode 100644 index 592c2bf0d..000000000 --- a/packages/extension/src/providers/ethereum/networks/zkgoerli.ts +++ /dev/null @@ -1,24 +0,0 @@ -import icon from './icons/zksync.webp'; -import { NetworkNames } from '@enkryptcom/types'; -import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; -import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; -import { EtherscanActivity } from '../libs/activity-handlers'; - -const zkgoerliOptions: EvmNetworkOptions = { - name: NetworkNames.ZkSyncGoerli, - name_long: 'zkSync Goerli', - homePage: 'https://zksync.io/', - blockExplorerTX: 'https://goerli.explorer.zksync.io/tx/[[txHash]]', - blockExplorerAddr: 'https://goerli.explorer.zksync.io/address/[[address]]', - chainID: '0x118', - isTestNetwork: true, - currencyName: 'GöETH', - currencyNameLong: 'zkSync Goerli', - node: 'wss://testnet.era.zksync.dev/ws', - icon, - activityHandler: wrapActivityHandler(EtherscanActivity), -}; - -const zkgoerli = new EvmNetwork(zkgoerliOptions); - -export default zkgoerli; diff --git a/packages/extension/src/providers/ethereum/networks/zksepolia.ts b/packages/extension/src/providers/ethereum/networks/zksepolia.ts new file mode 100644 index 000000000..9e538f1ab --- /dev/null +++ b/packages/extension/src/providers/ethereum/networks/zksepolia.ts @@ -0,0 +1,23 @@ +import icon from './icons/zksync.webp'; +import { NetworkNames } from '@enkryptcom/types'; +import { EvmNetwork, EvmNetworkOptions } from '../types/evm-network'; +import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; + +const zkgoerliOptions: EvmNetworkOptions = { + name: NetworkNames.zkSyncSepolia, + name_long: 'zkSync Sepolia', + homePage: 'https://zksync.io/', + blockExplorerTX: 'https://sepolia.explorer.zksync.io/tx/[[txHash]]', + blockExplorerAddr: 'https://sepolia.explorer.zksync.io/address/[[address]]', + chainID: '0x12c', + isTestNetwork: true, + currencyName: 'ETH', + currencyNameLong: 'ETH ZKSepolia', + node: 'wss://sepolia.era.zksync.dev/ws', + icon, + activityHandler: wrapActivityHandler(() => Promise.resolve([])), +}; + +const zkgoerli = new EvmNetwork(zkgoerliOptions); + +export default zkgoerli; diff --git a/packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue b/packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue index accbda2b7..0101b340b 100644 --- a/packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue +++ b/packages/extension/src/providers/ethereum/ui/eth-verify-transaction.vue @@ -234,7 +234,7 @@ onBeforeMount(async () => { Request.value.params![0] as EthereumTransaction, network.value as EvmNetwork, ).then(decoded => { - const realToAddress = decoded.tokenTo || decoded.toAddress; + const realToAddress = decoded.tokenTo || decoded.toAddress || ''; identiconTo.value = network.value.identicon(realToAddress!.toLowerCase()); if (decoded.decoded && decoded.dataHex.startsWith(TokenSigs.approve)) { isApproval.value = true; diff --git a/packages/extension/src/providers/index.ts b/packages/extension/src/providers/index.ts index f1b8e6106..90498059e 100644 --- a/packages/extension/src/providers/index.ts +++ b/packages/extension/src/providers/index.ts @@ -3,6 +3,7 @@ import PolkadotProvider from '@/providers/polkadot'; import BitcoinProvider from '@/providers/bitcoin'; import KadenaProvider from '@/providers/kadena'; import SolanaProvider from '@/providers/solana'; +import MassaProvider from '@/providers/massa'; import { ProviderName } from '@/types/provider'; export default { @@ -11,4 +12,5 @@ export default { [ProviderName.bitcoin]: BitcoinProvider, [ProviderName.kadena]: KadenaProvider, [ProviderName.solana]: SolanaProvider, + [ProviderName.massa]: MassaProvider, }; diff --git a/packages/extension/src/providers/kadena/networks/index.ts b/packages/extension/src/providers/kadena/networks/index.ts index a588e5e48..3cf48f798 100644 --- a/packages/extension/src/providers/kadena/networks/index.ts +++ b/packages/extension/src/providers/kadena/networks/index.ts @@ -1,7 +1,6 @@ import kadena from './kadena'; -import kadenaTestnet from './kadena-testnet'; +// import kadenaTestnet from './kadena-testnet'; export default { kadena, - kadenaTestnet, }; diff --git a/packages/extension/src/providers/kadena/networks/kadena.ts b/packages/extension/src/providers/kadena/networks/kadena.ts index 1ebbc8423..9d50dacd9 100644 --- a/packages/extension/src/providers/kadena/networks/kadena.ts +++ b/packages/extension/src/providers/kadena/networks/kadena.ts @@ -9,16 +9,17 @@ const kadenaOptions: KadenaNetworkOptions = { name: NetworkNames.Kadena, name_long: 'Kadena', homePage: 'https://kadena.io/', - blockExplorerTX: 'https://explorer.chainweb.com/mainnet/tx/[[txHash]]', + blockExplorerTX: + 'https://explorer.chainweb-community.org/mainnet/tx/[[txHash]]', blockExplorerAddr: - 'https://explorer.chainweb.com/mainnet/account/[[address]]?token=coin', + 'https://explorer.chainweb-community.org/mainnet/account/[[address]]?token=coin', isTestNetwork: false, currencyName: 'KDA', currencyNameLong: 'Kadena', icon, decimals: 12, prefix: 0, - node: 'https://api.chainweb.com/chainweb/0.0', + node: 'https://api.chainweb-community.org/chainweb/0.0', kadenaApiOptions: { networkId: 'mainnet01', chainId: '1', diff --git a/packages/extension/src/providers/massa/index.ts b/packages/extension/src/providers/massa/index.ts new file mode 100644 index 000000000..08b81486b --- /dev/null +++ b/packages/extension/src/providers/massa/index.ts @@ -0,0 +1,92 @@ +import { BaseNetwork } from '@/types/base-network'; +import getRequestProvider, { RequestClass } from '@enkryptcom/request'; +import { MiddlewareFunction, OnMessageResponse } from '@enkryptcom/types'; +import Middlewares from './methods'; +import EventEmitter from 'eventemitter3'; +import { + BackgroundProviderInterface, + ProviderName, + ProviderRPCRequest, +} from '@/types/provider'; +import GetUIPath from '@/libs/utils/get-ui-path'; +import PublicKeyRing from '@/libs/keyring/public-keyring'; +import UIRoutes from './ui/routes/names'; +import { RoutesType } from '@/types/ui'; +import massaNetworks from './networks'; +import { NetworkNames } from '@enkryptcom/types'; + +export default class MassaProvider + extends EventEmitter + implements BackgroundProviderInterface +{ + public network: BaseNetwork; + requestProvider: RequestClass; + middlewares: MiddlewareFunction[] = []; + namespace: string; + KeyRing: PublicKeyRing; + UIRoutes: RoutesType; + toWindow: (message: string) => void; + + constructor( + toWindow: (message: string) => void, + network: BaseNetwork = massaNetworks[NetworkNames.Massa], + ) { + super(); + this.network = network; + this.toWindow = toWindow; + this.setMiddleWares(); + this.requestProvider = getRequestProvider(network.node, this.middlewares); + this.requestProvider.on('notification', (notif: any) => { + this.sendNotification(JSON.stringify(notif)); + }); + this.namespace = ProviderName.massa; + this.KeyRing = new PublicKeyRing(); + + this.UIRoutes = UIRoutes; + } + + private setMiddleWares(): void { + this.middlewares = Middlewares(this).map(mw => mw.bind(this)); + } + + setRequestProvider(network: BaseNetwork): void { + const prevURL = new URL(this.network.node); + const newURL = new URL(network.node); + this.network = network; + if (prevURL.protocol === newURL.protocol) + this.requestProvider.changeNetwork(network.node); + else + this.requestProvider = getRequestProvider(network.node, this.middlewares); + } + + async isPersistentEvent(): Promise { + return false; + } + + async sendNotification(notif: string): Promise { + return this.toWindow(notif); + } + + request(request: ProviderRPCRequest): Promise { + return this.requestProvider + .request(request) + .then(res => { + return { + result: JSON.stringify(res), + }; + }) + .catch(e => { + return { + error: JSON.stringify(e.message), + }; + }); + } + + getUIPath(page: string): string { + return GetUIPath(page, this.namespace); + } + + getCurrentNetwork(): BaseNetwork { + return this.network; + } +} diff --git a/packages/extension/src/providers/massa/libs/activity-handlers/index.ts b/packages/extension/src/providers/massa/libs/activity-handlers/index.ts new file mode 100644 index 000000000..301f4ec93 --- /dev/null +++ b/packages/extension/src/providers/massa/libs/activity-handlers/index.ts @@ -0,0 +1,3 @@ +import MassaActivity from './massa'; + +export { MassaActivity }; diff --git a/packages/extension/src/providers/massa/libs/activity-handlers/massa.ts b/packages/extension/src/providers/massa/libs/activity-handlers/massa.ts new file mode 100644 index 000000000..15dde2e7a --- /dev/null +++ b/packages/extension/src/providers/massa/libs/activity-handlers/massa.ts @@ -0,0 +1,27 @@ +import { BaseNetwork } from '@/types/base-network'; +import { Activity } from '@/types/activity'; +import { ActivityHandlerType } from '@/libs/activity-state/types'; +import ActivityState from '@/libs/activity-state'; + +const MassaActivity: ActivityHandlerType = async ( + network: BaseNetwork, + address: string, +): Promise => { + try { + // Get activities from local storage + const activityState = new ActivityState(); + const activities = await activityState.getAllActivities({ + address, + network: network.name, + }); + + // For now, return local activities + // In the future, this can be extended to fetch from Massa explorer API + return activities; + } catch (error) { + console.error('Error fetching Massa activities:', error); + return []; + } +}; + +export default MassaActivity; diff --git a/packages/extension/src/providers/massa/libs/api.ts b/packages/extension/src/providers/massa/libs/api.ts new file mode 100644 index 000000000..28bead2d2 --- /dev/null +++ b/packages/extension/src/providers/massa/libs/api.ts @@ -0,0 +1,60 @@ +import { ProviderAPIInterface } from '@/types/provider'; +import { + JsonRpcPublicProvider, + MRC20, + NodeStatusInfo, + OperationStatus, +} from '@massalabs/massa-web3'; + +export default class MassaAPI extends ProviderAPIInterface { + public provider: JsonRpcPublicProvider; + public node: string; + + constructor(node: string) { + super(node); + this.node = node; + this.provider = JsonRpcPublicProvider.fromRPCUrl( + node, + ) as JsonRpcPublicProvider; + } + + public get api() { + return this; + } + + async init(): Promise {} + + async getBalance(address: string): Promise { + const [account] = await this.provider.balanceOf([address], false); + if (!account) return '0'; + return account.balance.toString(); + } + + async getBalanceMRC20(address: string, contract: string): Promise { + const mrc20 = new MRC20(this.provider, contract); + const balance = await mrc20.balanceOf(address); + return balance.toString(); + } + + async getMinimalFee(): Promise { + try { + const networkInfo = await this.provider.networkInfos(); + return networkInfo.minimalFee.toString(); + } catch { + // Return a default minimal fee if network info is not available + return '10000000'; // 0.01 MAS in base units (9 decimals) + } + } + + async getTransactionStatus(opId: string): Promise { + try { + return this.provider.getOperationStatus(opId); + } catch { + return null; + } + } + + async getNodeStatus(): Promise { + return this.provider.getNodeStatus(); + } +} diff --git a/packages/extension/src/providers/massa/methods/index.ts b/packages/extension/src/providers/massa/methods/index.ts new file mode 100644 index 000000000..f82148695 --- /dev/null +++ b/packages/extension/src/providers/massa/methods/index.ts @@ -0,0 +1,20 @@ +import { MiddlewareFunction } from '@enkryptcom/types'; +import { BackgroundProviderInterface } from '@/types/provider'; +import massa_getBalance from './massa_getBalance'; +import massa_getNetwork from './massa_getNetwork'; +import massa_setNetwork from './massa_setNetwork'; + +export default ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _provider: BackgroundProviderInterface, +): MiddlewareFunction[] => { + return [ + massa_getBalance, + massa_getNetwork, + massa_setNetwork, + async (request, response, next) => { + // Add any additional Massa-specific middleware logic here + return next(); + }, + ]; +}; diff --git a/packages/extension/src/providers/massa/methods/massa_getBalance.ts b/packages/extension/src/providers/massa/methods/massa_getBalance.ts new file mode 100644 index 000000000..f86d5d882 --- /dev/null +++ b/packages/extension/src/providers/massa/methods/massa_getBalance.ts @@ -0,0 +1,33 @@ +import { MiddlewareFunction } from '@enkryptcom/types'; +import { ProviderRPCRequest } from '@/types/provider'; +import { getCustomError } from '@/libs/error'; +import MassaProvider from '..'; +import { MassaNetwork } from '../networks/massa-base'; + +const method: MiddlewareFunction = async function ( + this: MassaProvider, + payload: ProviderRPCRequest, + res, + next, +): Promise { + if (payload.method !== 'massa_getBalance') return next(); + else { + try { + const address = payload.params?.[0]; + const network = this.network as MassaNetwork; + if (!address || !network.isValidAddress(address)) { + res(getCustomError('Please enter a valid Massa address')); + return; + } + + const api = await network.api(); + const balance = await api.getBalance(address); + + res(null, balance); + } catch { + res(getCustomError('Could not fetch balance from network')); + } + } +}; + +export default method; diff --git a/packages/extension/src/providers/massa/methods/massa_getNetwork.ts b/packages/extension/src/providers/massa/methods/massa_getNetwork.ts new file mode 100644 index 000000000..1c4451c0f --- /dev/null +++ b/packages/extension/src/providers/massa/methods/massa_getNetwork.ts @@ -0,0 +1,22 @@ +import { MiddlewareFunction } from '@enkryptcom/types'; +import { ProviderRPCRequest } from '@/types/provider'; +import { NetworkNames } from '@enkryptcom/types'; +import MassaProvider from '..'; + +const method: MiddlewareFunction = async function ( + this: MassaProvider, + payload: ProviderRPCRequest, + res, + next, +): Promise { + if (payload.method !== 'massa_getNetwork') return next(); + else { + try { + res(null, this.network.name); + } catch { + res(null, NetworkNames.Massa); + } + } +}; + +export default method; diff --git a/packages/extension/src/providers/massa/methods/massa_setNetwork.ts b/packages/extension/src/providers/massa/methods/massa_setNetwork.ts new file mode 100644 index 000000000..d8d895d51 --- /dev/null +++ b/packages/extension/src/providers/massa/methods/massa_setNetwork.ts @@ -0,0 +1,55 @@ +import { MiddlewareFunction } from '@enkryptcom/types'; +import { ProviderRPCRequest } from '@/types/provider'; +import { getCustomError } from '@/libs/error'; +import massaNetworks from '../networks'; +import MassaProvider from '..'; + +const method: MiddlewareFunction = async function ( + this: MassaProvider, + payload: ProviderRPCRequest, + res, + next, +): Promise { + if (payload.method !== 'massa_setNetwork') return next(); + else { + try { + const networkName = payload.params?.[0]; + + if (!networkName) { + res(getCustomError('Network name is required')); + return; + } + + // Check if the network exists + const availableNetworks = Object.keys(massaNetworks); + + if (!availableNetworks.includes(networkName)) { + res( + getCustomError( + `Invalid network name. Available networks: ${availableNetworks.join(', ')}`, + ), + ); + return; + } + + // Get the network object + const network = massaNetworks[networkName as keyof typeof massaNetworks]; + + // Set the network in the provider + if (this.setRequestProvider) { + this.setRequestProvider(network); + res(null, { success: true, network: network.name }); + } else { + res(getCustomError('Network switching not supported')); + } + } catch (error) { + res( + getCustomError( + `Network switching failed: ${(error as Error).message || 'Unknown error'}`, + ), + ); + } + } +}; + +export default method; diff --git a/packages/extension/src/providers/massa/networks/buildnet.ts b/packages/extension/src/providers/massa/networks/buildnet.ts new file mode 100644 index 000000000..81c3feab8 --- /dev/null +++ b/packages/extension/src/providers/massa/networks/buildnet.ts @@ -0,0 +1,19 @@ +import { NetworkNames } from '@enkryptcom/types'; +import { MassaNetwork, createMassaNetworkOptions } from './massa-base'; +import { CHAIN_ID, PublicApiUrl } from '@massalabs/massa-web3'; + +const buildnetOptions = createMassaNetworkOptions({ + name: NetworkNames.MassaBuildnet, + name_long: 'Massa Buildnet', + blockExplorerTX: 'https://www.massexplo.com/tx/[[txHash]]?network=buildnet', + blockExplorerAddr: + 'https://www.massexplo.com/address/[[address]]?network=buildnet', + isTestNetwork: true, + node: PublicApiUrl.Buildnet, + chainId: CHAIN_ID.Buildnet, + coingeckoID: 'massa', +}); + +const buildnet = new MassaNetwork(buildnetOptions); + +export default buildnet; diff --git a/packages/extension/src/providers/massa/networks/icons/Massa_logo.webp b/packages/extension/src/providers/massa/networks/icons/Massa_logo.webp new file mode 100644 index 000000000..8ab091f59 Binary files /dev/null and b/packages/extension/src/providers/massa/networks/icons/Massa_logo.webp differ diff --git a/packages/extension/src/providers/massa/networks/index.ts b/packages/extension/src/providers/massa/networks/index.ts new file mode 100644 index 000000000..b14e25172 --- /dev/null +++ b/packages/extension/src/providers/massa/networks/index.ts @@ -0,0 +1,8 @@ +import mainnet from './mainnet'; +import buildnet from './buildnet'; +import { NetworkNames } from '@enkryptcom/types'; + +export default { + [NetworkNames.Massa]: mainnet, + [NetworkNames.MassaBuildnet]: buildnet, +}; diff --git a/packages/extension/src/providers/massa/networks/mainnet.ts b/packages/extension/src/providers/massa/networks/mainnet.ts new file mode 100644 index 000000000..0896b6cdc --- /dev/null +++ b/packages/extension/src/providers/massa/networks/mainnet.ts @@ -0,0 +1,18 @@ +import { NetworkNames } from '@enkryptcom/types'; +import { CHAIN_ID, PublicApiUrl } from '@massalabs/massa-web3'; +import { MassaNetwork, createMassaNetworkOptions } from './massa-base'; + +const mainnetOptions = createMassaNetworkOptions({ + name: NetworkNames.Massa, + name_long: 'Massa', + blockExplorerTX: 'https://explorer.massa.net/mainnet/operation/[[txHash]]', + blockExplorerAddr: 'https://explorer.massa.net/mainnet/address/[[address]]', + isTestNetwork: false, + node: PublicApiUrl.Mainnet, + chainId: CHAIN_ID.Mainnet, + coingeckoID: 'massa', +}); + +const mainnet = new MassaNetwork(mainnetOptions); + +export default mainnet; diff --git a/packages/extension/src/providers/massa/networks/massa-base.ts b/packages/extension/src/providers/massa/networks/massa-base.ts new file mode 100644 index 000000000..bc12d4cf1 --- /dev/null +++ b/packages/extension/src/providers/massa/networks/massa-base.ts @@ -0,0 +1,285 @@ +import { NetworkNames } from '@enkryptcom/types'; +import { BaseNetwork } from '@/types/base-network'; +import MassaAPI from '../libs/api'; +import { SignerType } from '@enkryptcom/types'; +import { ProviderName } from '@/types/provider'; +import { MassaNetworkOptions } from '../types'; +import { Activity } from '@/types/activity'; +import { AssetsType } from '@/types/provider'; +import { fromBase } from '@enkryptcom/utils'; +import { formatFloatingPointValue } from '@/libs/utils/number-formatter'; +import MarketData from '@/libs/market-data'; +import BigNumber from 'bignumber.js'; +import icon from './icons/Massa_logo.webp'; +import createIcon from '../../ethereum/libs/blockies'; +import { TokensState } from '@/libs/tokens-state'; +import { CustomMassaToken, TokenType } from '@/libs/tokens-state/types'; +import Sparkline from '@/libs/sparkline'; +import { MassaActivity } from '../libs/activity-handlers'; +import wrapActivityHandler from '@/libs/activity-state/wrap-activity-handler'; +import { Address } from '@massalabs/massa-web3'; + +export class MassaNetwork extends BaseNetwork { + chainId: bigint; + private activityHandler?: ( + network: BaseNetwork, + address: string, + ) => Promise; + + constructor(options: MassaNetworkOptions) { + super(options); + this.chainId = options.chainId!; + this.activityHandler = + options.activityHandler || wrapActivityHandler(MassaActivity); + } + + async getAllTokens(): Promise { + return []; + } + + async getAllTokenInfo(address: string): Promise { + try { + // Get native MAS balance + const api = (await this.api()) as MassaAPI; + const balance = await api.getBalance(address); + const balanceFormatted = fromBase(balance, this.decimals); + const balanceDisplayFormatted = + formatFloatingPointValue(balanceFormatted).value; + + // Get MAS price from CoinGecko + let price = '0'; + let priceChangePercentage = 0; + let sparklineData = ''; + + try { + if (this.coingeckoID) { + const marketData = new MarketData(); + const tokenPrice = await marketData.getTokenPrice(this.coingeckoID); + const marketInfos = await marketData.getMarketData([ + this.coingeckoID, + ]); + const marketInfo = marketInfos[0]; + + if (tokenPrice) { + price = tokenPrice; + } + + if (marketInfo) { + priceChangePercentage = marketInfo.price_change_percentage_24h || 0; + if (marketInfo.sparkline_in_24h?.price) { + // Convert sparkline data to string format expected by UI + sparklineData = JSON.stringify( + marketInfo.sparkline_in_24h.price.slice(-25), + ); // Last 25 points + } + } + } + } catch { + // Price data not available, continue with default values + } + + // Calculate USD values + const balanceUSD = new BigNumber(balanceDisplayFormatted) + .times(price) + .toNumber(); + const balanceUSDf = new BigNumber(balanceDisplayFormatted) + .times(price) + .toString(); + const priceFormatted = formatFloatingPointValue(price).value; + + const nativeTokenAsset: AssetsType = { + name: this.currencyNameLong, + symbol: this.currencyName, + icon: this.icon, + balance, + balancef: balanceDisplayFormatted, + balanceUSD, + balanceUSDf, + value: price, + valuef: priceFormatted, + decimals: this.decimals, + sparkline: sparklineData, + priceChangePercentage, + }; + + const assets = [nativeTokenAsset]; + + // Add custom tokens support + const tokensState = new TokensState(); + const customTokens = await tokensState + .getTokensByNetwork(this.name) + .then(tokens => { + const erc20Tokens = tokens.filter(token => { + if (token.type !== TokenType.ERC20) { + return false; + } + + for (const a of assets) { + if ( + a.contract && + (token as CustomMassaToken).address && + a.contract.toLowerCase() === + (token as CustomMassaToken).address.toLowerCase() + ) { + return false; + } + } + + return true; + }) as CustomMassaToken[]; + + return erc20Tokens.map( + ({ name, symbol, address, icon, decimals }) => { + return { + name, + symbol, + contract: address, + icon, + decimals, + balance: '0', // Will be fetched below + }; + }, + ); + }); + + // Fetch balances for custom tokens + const balancePromises = customTokens.map(async token => { + try { + return api.getBalanceMRC20(address, token.contract); + } catch { + return '0'; + } + }); + + const balances = await Promise.all(balancePromises); + + // Update token balances with fetched values + customTokens.forEach((token, index) => { + token.balance = balances[index]; + }); + + const marketData = new MarketData(); + const marketInfos = await marketData.getMarketInfoByContracts( + customTokens.map(token => token.contract.toLowerCase()), + this.coingeckoPlatform!, + ); + + const customAssets: AssetsType[] = customTokens.map(token => { + const asset: AssetsType = { + name: token.name, + symbol: token.symbol, + balance: token.balance ?? '0', + balancef: formatFloatingPointValue( + fromBase(token.balance ?? '0', token.decimals), + ).value, + contract: token.contract, + balanceUSD: 0, + balanceUSDf: '0', + value: '0', + valuef: '0', + decimals: token.decimals, + sparkline: '', + priceChangePercentage: 0, + icon: token.icon, + }; + + // Check if token is a stablecoin (contains DAI or USD in symbol) + const isStablecoin = + token.symbol.toUpperCase().includes('DAI') || + token.symbol.toUpperCase().includes('USD'); + + if (isStablecoin) { + // Use $1 price for stablecoins + const usdBalance = new BigNumber( + fromBase(token.balance ?? '0', token.decimals), + ).times(1); + asset.balanceUSD = usdBalance.toNumber(); + asset.balanceUSDf = usdBalance.toString(); + asset.value = '1'; + asset.valuef = '1'; + asset.priceChangePercentage = 0; + } else { + // Use real market data for other tokens + const marketInfo = marketInfos[token.contract.toLowerCase()]; + + if (marketInfo) { + const usdBalance = new BigNumber( + fromBase(token.balance ?? '0', token.decimals), + ).times(marketInfo.current_price ?? 0); + asset.balanceUSD = usdBalance.toNumber(); + asset.balanceUSDf = usdBalance.toString(); + asset.value = marketInfo.current_price?.toString() ?? '0'; + asset.valuef = marketInfo.current_price?.toString() ?? '0'; + asset.sparkline = new Sparkline( + marketInfo.sparkline_in_24h.price, + 25, + ).dataValues; + asset.priceChangePercentage = + marketInfo.price_change_percentage_24h_in_currency || 0; + } + } + + return asset; + }); + + return [...assets, ...customAssets]; + } catch { + return []; + } + } + + async getAllActivity(address: string): Promise { + if (this.activityHandler) { + return this.activityHandler(this, address); + } + return []; + } + + isValidAddress = (address: string): boolean => { + try { + Address.fromString(address); + } catch { + return false; + } + return true; + }; +} + +// Helper function to create standard Massa network options +export function createMassaNetworkOptions(config: { + name: NetworkNames; + name_long: string; + blockExplorerTX: string; + blockExplorerAddr: string; + isTestNetwork: boolean; + node: string; + chainId: bigint; + coingeckoID?: string; +}): MassaNetworkOptions { + return { + name: config.name, + name_long: config.name_long, + homePage: 'https://massa.net/', + blockExplorerTX: config.blockExplorerTX, + blockExplorerAddr: config.blockExplorerAddr, + isTestNetwork: config.isTestNetwork, + currencyName: 'MAS', + currencyNameLong: 'Massa', + node: config.node, + icon, + decimals: 9, + signer: [SignerType.ed25519mas], + displayAddress: (address: string) => address, + provider: ProviderName.massa, + identicon: createIcon, + basePath: "m/44'/632'", + chainId: config.chainId, + coingeckoID: config.coingeckoID, + customTokens: true, + api: async () => { + const api = new MassaAPI(config.node); + await api.init(); + return api; + }, + }; +} diff --git a/packages/extension/src/providers/massa/types/index.ts b/packages/extension/src/providers/massa/types/index.ts new file mode 100644 index 000000000..08d37ad26 --- /dev/null +++ b/packages/extension/src/providers/massa/types/index.ts @@ -0,0 +1,31 @@ +import { NetworkName, CHAIN_ID } from '@massalabs/massa-web3'; +import { BaseNetworkOptions } from '@/types/base-network'; +import { ToTokenData } from '@/ui/action/types/token'; +import { BaseNetwork } from '@/types/base-network'; +import { Activity } from '@/types/activity'; + +export const MassaNetworks = NetworkName; + +export interface MassaNetworkOptions extends BaseNetworkOptions { + chainId?: (typeof CHAIN_ID)[keyof typeof CHAIN_ID]; + activityHandler?: ( + network: BaseNetwork, + address: string, + ) => Promise; +} + +export interface TxFeeInfo { + nativeValue: string; + fiatValue: string; + nativeSymbol: string; + fiatSymbol: string; +} + +export interface VerifyTransactionParams { + fromAddress: string; + fromAddressName: string; + toAddress: string; + toToken: ToTokenData; + toTokenAddress?: string; + txFee: TxFeeInfo; +} diff --git a/packages/extension/src/providers/massa/ui/index.ts b/packages/extension/src/providers/massa/ui/index.ts new file mode 100644 index 000000000..9d0e66586 --- /dev/null +++ b/packages/extension/src/providers/massa/ui/index.ts @@ -0,0 +1,9 @@ +import { ProviderName, UIExportOptions } from '@/types/provider'; +import getRoutes from './routes'; + +const uiExport: UIExportOptions = { + providerName: ProviderName.massa, + routes: getRoutes(ProviderName.massa), +}; + +export default uiExport; diff --git a/packages/extension/src/providers/massa/ui/libs/signer.ts b/packages/extension/src/providers/massa/ui/libs/signer.ts new file mode 100644 index 000000000..69dab7896 --- /dev/null +++ b/packages/extension/src/providers/massa/ui/libs/signer.ts @@ -0,0 +1,132 @@ +import { InternalMethods, InternalOnMessageResponse } from '@/types/messenger'; +import { bufferToHex, hexToBuffer } from '@enkryptcom/utils'; +import sendUsingInternalMessengers from '@/libs/messenger/internal-messenger'; +import { BaseNetwork } from '@/types/base-network'; +import { EnkryptAccount } from '@enkryptcom/types'; +import { + Address, + CallOperation, + MAX_GAS_CALL, + OperationManager, + OperationType, + PublicKey, + TransferOperation, +} from '@massalabs/massa-web3'; +import { MassaNetworkOptions } from '../../types'; + +export interface MassaTransactionOptions { + account: EnkryptAccount; + network: BaseNetwork; + payload: { + type: OperationType; + from: string; + to: string; + amount: string; + fee: string; + expirePeriod: number; + data?: string; + maxGas?: string; + coins?: string; + func?: string; + }; +} + +export interface MassaSignedTransaction { + from: string; + to: string; + amount: string; + fee: string; + expirePeriod: number; + signature: string; + publicKey: string; + serializedHex: string; +} + +/** + * Sign a Massa transaction + */ +export const MassaTransactionSigner = ( + options: MassaTransactionOptions, +): Promise => { + const { account, payload, network } = options; + + let operationDetails: TransferOperation | CallOperation; + if (payload.type === OperationType.Transaction) { + operationDetails = { + type: payload.type, + amount: BigInt(payload.amount), + recipientAddress: Address.fromString(payload.to), + fee: BigInt(payload.fee), + expirePeriod: payload.expirePeriod, + }; + } else if (payload.type === OperationType.CallSmartContractFunction) { + if (!payload.func) { + throw new Error('Invalid payload, target function is required'); + } + operationDetails = { + type: payload.type, + parameter: hexToBuffer(payload.data ?? ''), + fee: BigInt(payload.fee), + expirePeriod: payload.expirePeriod, + maxGas: BigInt(payload.maxGas ?? MAX_GAS_CALL), + coins: BigInt(payload.coins ?? '0'), + address: payload.to, + func: payload.func, + }; + } else { + throw new Error(`Unsupported operation type: ${payload.type}`); + } + + const chainId = (network as MassaNetworkOptions).chainId; + const publicKey = PublicKey.fromString(account.publicKey); + const serialized = OperationManager.canonicalize( + chainId!, + operationDetails, + publicKey, + ); + const bufferTosign = bufferToHex(serialized); + + return sendUsingInternalMessengers({ + method: InternalMethods.sign, + params: [bufferTosign, account], + }).then(res => { + if (res.error) { + return Promise.reject(res); + } else { + const signature = JSON.parse(res.result as string) || ''; + + const signedTx: MassaSignedTransaction = { + ...payload, + signature, + publicKey: account.publicKey, + serializedHex: bufferToHex( + OperationManager.serialize(operationDetails), + ), + }; + + return signedTx; + } + }); +}; + +/** + * Sign a Massa message + */ +export const MassaMessageSigner = (options: { + account: EnkryptAccount; + network: BaseNetwork; + payload: Buffer; +}): Promise => { + const { account, payload } = options; + + const msgHash = bufferToHex(payload); + return sendUsingInternalMessengers({ + method: InternalMethods.sign, + params: [msgHash, account], + }).then(res => { + if (res.error) return res; + return { + result: res.result, + }; + }); +}; diff --git a/packages/extension/src/providers/massa/ui/routes/index.ts b/packages/extension/src/providers/massa/ui/routes/index.ts new file mode 100644 index 000000000..a248cd380 --- /dev/null +++ b/packages/extension/src/providers/massa/ui/routes/index.ts @@ -0,0 +1,12 @@ +import { RouteRecordRaw } from 'vue-router'; +import RouteNames from './names'; + +const routes = Object.assign({}, RouteNames); + +export default (namespace: string): RouteRecordRaw[] => { + return Object.values(routes).map(route => { + route.path = `/${namespace}/${route.path}`; + route.name = `${namespace}-${String(route.name)}`; + return route; + }); +}; diff --git a/packages/extension/src/providers/massa/ui/routes/names.ts b/packages/extension/src/providers/massa/ui/routes/names.ts new file mode 100644 index 000000000..7ab9121ba --- /dev/null +++ b/packages/extension/src/providers/massa/ui/routes/names.ts @@ -0,0 +1,16 @@ +import { RouteRecordRaw } from 'vue-router'; + +const routes: Record = { + send: { + path: 'send', + name: 'massa-send', + component: () => import('../send-transaction/index.vue'), + }, + verify: { + path: 'verify', + name: 'massa-verify', + component: () => import('../send-transaction/verify-transaction/index.vue'), + }, +}; + +export default routes; diff --git a/packages/extension/src/providers/massa/ui/send-transaction/components/send-address-input.vue b/packages/extension/src/providers/massa/ui/send-transaction/components/send-address-input.vue new file mode 100644 index 000000000..df422e02c --- /dev/null +++ b/packages/extension/src/providers/massa/ui/send-transaction/components/send-address-input.vue @@ -0,0 +1,217 @@ + + + + + diff --git a/packages/extension/src/providers/massa/ui/send-transaction/components/send-token-select.vue b/packages/extension/src/providers/massa/ui/send-transaction/components/send-token-select.vue new file mode 100644 index 000000000..998a8de9e --- /dev/null +++ b/packages/extension/src/providers/massa/ui/send-transaction/components/send-token-select.vue @@ -0,0 +1,118 @@ + + + + + diff --git a/packages/extension/src/providers/massa/ui/send-transaction/index.vue b/packages/extension/src/providers/massa/ui/send-transaction/index.vue new file mode 100644 index 000000000..2f6a94fe5 --- /dev/null +++ b/packages/extension/src/providers/massa/ui/send-transaction/index.vue @@ -0,0 +1,717 @@ + + + + + diff --git a/packages/extension/src/providers/massa/ui/send-transaction/verify-transaction/index.vue b/packages/extension/src/providers/massa/ui/send-transaction/verify-transaction/index.vue new file mode 100644 index 000000000..d341b1e4c --- /dev/null +++ b/packages/extension/src/providers/massa/ui/send-transaction/verify-transaction/index.vue @@ -0,0 +1,472 @@ + + + + + diff --git a/packages/extension/src/providers/polkadot/networks/index.ts b/packages/extension/src/providers/polkadot/networks/index.ts index afd51dc77..283c243a8 100644 --- a/packages/extension/src/providers/polkadot/networks/index.ts +++ b/packages/extension/src/providers/polkadot/networks/index.ts @@ -8,7 +8,6 @@ import sdnNode from './astar/shiden'; import bncNode from './bifrost/polkadot'; import bncKusamaNode from './bifrost/kusama'; import edgNode from './edgeware'; -import opalNode from './unique/opal'; import quartzNode from './unique/quartz'; import uniqueNode from './unique/unique'; import penNode from './pendulum/pendulum'; @@ -30,7 +29,6 @@ export default { bifrost: bncNode, bifrostKusama: bncKusamaNode, edgeware: edgNode, - opal: opalNode, quartz: quartzNode, unique: uniqueNode, pendulum: penNode, diff --git a/packages/extension/src/providers/polkadot/networks/unique/opal.ts b/packages/extension/src/providers/polkadot/networks/unique/opal.ts deleted file mode 100644 index 909b634f8..000000000 --- a/packages/extension/src/providers/polkadot/networks/unique/opal.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { NetworkNames } from '@enkryptcom/types'; -import { - SubstrateNetwork, - SubstrateNetworkOptions, -} from '../../types/substrate-network'; -import { getActivityHandler } from './libs/activity-handler'; -import { toBN } from 'web3-utils'; -import icon from '../icons/opal.webp'; - -const GRAPHQL_ENDPOINT = 'https://api-opal.uniquescan.io/v1/graphql'; - -const opalOptions: SubstrateNetworkOptions = { - name: NetworkNames.Opal, - name_long: 'Opal', - homePage: 'https://unique.network/', - blockExplorerTX: 'https://uniquescan.io/opal/extrinsic/[[txHash]]', - blockExplorerAddr: 'https://uniquescan.io/opal/account/[[address]]', - isTestNetwork: true, - currencyName: 'OPL', - currencyNameLong: 'Opal', - icon, - decimals: 18, - prefix: 42, - node: 'wss://ws-opal.unique.network', - genesisHash: - '0xc87870ef90a438d574b8e320f17db372c50f62beb52e479c8ff6ee5b460670b9', - existentialDeposit: toBN(0), - activityHandler: getActivityHandler(GRAPHQL_ENDPOINT), -}; - -const opal = new SubstrateNetwork(opalOptions); - -export default opal; diff --git a/packages/extension/src/types/activity.ts b/packages/extension/src/types/activity.ts index 48eb4fe84..b13efcab1 100644 --- a/packages/extension/src/types/activity.ts +++ b/packages/extension/src/types/activity.ts @@ -6,6 +6,7 @@ import { StatusOptionsResponse, } from '@enkryptcom/swap'; import { ICommandResult } from '@kadena/client'; +import { OperationStatus } from '@massalabs/massa-web3'; interface BTCIns { address: string; @@ -91,6 +92,8 @@ interface KadenaDBInfo { token: string; } +type MassaRawInfo = OperationStatus; + enum ActivityStatus { pending = 'pending', success = 'success', @@ -128,7 +131,8 @@ interface Activity { | BTCRawInfo | SwapRawInfo | KadenaRawInfo - | SOLRawInfo; + | SOLRawInfo + | MassaRawInfo; } export { @@ -143,4 +147,5 @@ export { KadenaRawInfo, KadenaDBInfo, SOLRawInfo, + MassaRawInfo, }; diff --git a/packages/extension/src/types/base-network.ts b/packages/extension/src/types/base-network.ts index d876a0c99..3ca1af7a2 100644 --- a/packages/extension/src/types/base-network.ts +++ b/packages/extension/src/types/base-network.ts @@ -8,6 +8,7 @@ import { CoingeckoPlatform, SignerType, NetworkNames } from '@enkryptcom/types'; import { Activity } from './activity'; import { BaseToken } from './base-token'; import { BNType } from '@/providers/common/types'; +import MassaAPI from '../providers/massa/libs/api'; export interface SubNetworkOptions { id: string; @@ -38,7 +39,8 @@ export interface BaseNetworkOptions { | Promise | Promise | Promise - | Promise; + | Promise + | Promise; customTokens?: boolean; } @@ -80,7 +82,8 @@ export abstract class BaseNetwork { | Promise | Promise | Promise - | Promise; + | Promise + | Promise; public customTokens: boolean; constructor(options: BaseNetworkOptions) { diff --git a/packages/extension/src/types/provider.ts b/packages/extension/src/types/provider.ts index 0f831c71b..b43819ba4 100644 --- a/packages/extension/src/types/provider.ts +++ b/packages/extension/src/types/provider.ts @@ -23,6 +23,7 @@ import { SubscanExtrinsicInfo, KadenaRawInfo, SOLRawInfo, + MassaRawInfo, } from './activity'; export enum ProviderName { @@ -32,6 +33,7 @@ export enum ProviderName { polkadot = 'polkadot', kadena = 'kadena', solana = 'solana', + massa = 'massa', } export enum InternalStorageNamespace { keyring = 'KeyRing', @@ -68,6 +70,7 @@ export enum ProviderType { bitcoin, kadena, solana, + massa, } export type SendMessageHandler = ( @@ -144,6 +147,7 @@ export abstract class ProviderAPIInterface { | BTCRawInfo | KadenaRawInfo | SOLRawInfo + | MassaRawInfo | null >; } diff --git a/packages/extension/src/ui/action/App.vue b/packages/extension/src/ui/action/App.vue index 4b1b6728e..bcd79762f 100644 --- a/packages/extension/src/ui/action/App.vue +++ b/packages/extension/src/ui/action/App.vue @@ -1,83 +1,91 @@ @@ -113,6 +121,7 @@ import AddNetwork from './views/add-network/index.vue'; import ModalRate from './views/modal-rate/index.vue'; import Settings from './views/settings/index.vue'; import ModalUpdates from './views/updates/index.vue'; +import Restricted from './views/restricted/index.vue'; import { KadenaNetwork } from '@/providers/kadena/types/kadena-network'; import { EnkryptProviderEventMethods, ProviderName } from '@/types/provider'; import RateState from '@/libs/rate-state'; @@ -128,6 +137,7 @@ import BackupState from '@/libs/backup-state'; import { useMenuStore } from './store/menu-store'; import { useCurrencyStore, type Currency } from './views/settings/store'; import { useRateStore } from './store/rate-store'; +import { isGeoRestricted, isWalletRestricted } from '@/libs/utils/screening'; const domainState = new DomainState(); const rateState = new RateState(); @@ -153,6 +163,8 @@ const updateShow = ref(false); const isLoading = ref(true); const currentVersion = __PACKAGE_VERSION__; const latestVersion = ref(''); +const geoRestricted = ref(false); +const isWalletInitialized = ref(false); /** ------------------- * Rate @@ -211,6 +223,8 @@ const openBuyPage = () => { case NetworkNames.SyscoinNEVMTest: case NetworkNames.RolluxTest: return (currentNetwork.value as EvmNetwork).options.buyLink; + case NetworkNames.Massa: + return 'https://www.massa.net/get-mas'; default: return `https://ccswap.myetherwallet.com/?to=${currentNetwork.value.displayAddress( accountHeaderData.value.selectedAccount!.address, @@ -265,7 +279,10 @@ const fetchAndSetRates = async () => { }; onMounted(async () => { + geoRestricted.value = await isGeoRestricted(); const isInitialized = await kr.isInitialized(); + isWalletInitialized.value = isInitialized; + if (geoRestricted.value) return; if (isInitialized) { const _isLocked = await isKeyRingLocked(); if (_isLocked) { @@ -316,11 +333,12 @@ const setNetwork = async (network: BaseNetwork) => { currentSubNetwork.value = ''; } const activeAccounts = await getAccountsByNetworkName(network.name); - const inactiveAccounts = await kr.getAccounts( getOtherSigners(network.signer), ); + const selectedAddress = await domainState.getSelectedAddress(); + let selectedAccount = activeAccounts[0]; if (selectedAddress) { const found = activeAccounts.find(acc => acc.address === selectedAddress); @@ -333,7 +351,11 @@ const setNetwork = async (network: BaseNetwork) => { selectedAccount, activeBalances: activeAccounts.map(() => '~'), }; + currentNetwork.value = network; + + checkAddresses(activeAccounts); + router.push({ name: 'assets', params: { id: network.name } }); const tabId = await domainState.getCurrentTabId(); const curSavedNetwork = await domainState.getSelectedNetWork(); @@ -418,6 +440,19 @@ const setNetwork = async (network: BaseNetwork) => { } }; +const foundRestrictedAddress = ref(false); + +const checkAddresses = async ( + activeAccounts: AccountsHeaderData['activeAccounts'], +) => { + const promises: Promise[] = activeAccounts.map(ac => + isWalletRestricted(currentNetwork.value.displayAddress(ac.address)), + ); + await Promise.all(promises).then(results => { + if (results.includes(true)) foundRestrictedAddress.value = true; + }); +}; + const onSelectedSubnetworkChange = async (id: string) => { await domainState.setSelectedSubNetwork(id); currentSubNetwork.value = id; @@ -493,12 +528,15 @@ body { overflow: hidden; font-family: 'Roboto', sans-serif; } + .collapsed { width: 516px; } + .expanded { width: 800px; } + .app { height: 600px; overflow: hidden; @@ -544,14 +582,17 @@ body { width: 460px; height: 600px; position: relative; + &-expand { padding-left: 340px; } + &-collapse { padding-left: 56px; } } } + .slide-left-enter-active, .slide-left-leave-active, .slide-right-enter-active, @@ -561,14 +602,21 @@ body { transition-timing-function: cubic-bezier(0.55, 0, 0.1, 1); overflow: hidden; } + .slide-left-enter, .slide-right-leave-active { opacity: 0; transform: translate(2em, 0); } + .slide-left-leave-active, .slide-right-enter { opacity: 0; transform: translate(-2em, 0); } + +.restricted-container { + width: 800px; + height: 600px; +} diff --git a/packages/extension/src/ui/action/components/app-menu/components/solana-staking-banner.vue b/packages/extension/src/ui/action/components/app-menu/components/solana-staking-banner.vue index cc7b07303..3ddd65741 100644 --- a/packages/extension/src/ui/action/components/app-menu/components/solana-staking-banner.vue +++ b/packages/extension/src/ui/action/components/app-menu/components/solana-staking-banner.vue @@ -31,7 +31,7 @@ const close = () => { emit('close'); }; const openStakingLink = async () => { - trackSolanaStakingBanner(SolanaStakingBannerEvents.SolanaWalletClicked); + trackSolanaStakingBanner(SolanaStakingBannerEvents.NetworkListClicked); setTimeout(() => { openLink('https://staking.enkrypt.com'); }, 1000); diff --git a/packages/extension/src/ui/action/components/app-menu/components/survey-popup.vue b/packages/extension/src/ui/action/components/app-menu/components/survey-popup.vue new file mode 100644 index 000000000..8e142c764 --- /dev/null +++ b/packages/extension/src/ui/action/components/app-menu/components/survey-popup.vue @@ -0,0 +1,108 @@ + + + + + diff --git a/packages/extension/src/ui/action/components/app-menu/index.vue b/packages/extension/src/ui/action/components/app-menu/index.vue index 16e959037..085112ba9 100644 --- a/packages/extension/src/ui/action/components/app-menu/index.vue +++ b/packages/extension/src/ui/action/components/app-menu/index.vue @@ -158,10 +158,20 @@ - + + + + + + @@ -268,9 +278,7 @@ onMounted(async () => { newNetworksWithTags.value.swap = newSwaps.filter( net => !usedNetworks.swap.includes(net), ); - if (await bannersState.showSolanaStakingBanner()) { - isSolanaStakingBanner.value = true; - } + isSolanaStakingBanner.value = await bannersState.showSolanaStakingBanner(); }); /** ------------------- @@ -353,8 +361,8 @@ const sortNetworks = (networks: BaseNetwork[], sortBy: NetworkSort) => { return networks.sort((a, b) => { if (sortBy.name === NetworkSortOption.Name) { return sortBy.direction === NetworkSortDirection.Asc - ? a.name.localeCompare(b.name) - : b.name.localeCompare(a.name); + ? a.name_long.localeCompare(b.name_long) + : b.name_long.localeCompare(a.name_long); } return 0; }); @@ -542,6 +550,7 @@ const updateGradient = (newGradient: string) => { * Banners ------------------*/ const isSolanaStakingBanner = ref(false); + const bannersState = new BannersState(); const closeSolanaStakingBanner = () => { @@ -553,6 +562,20 @@ const closeSolanaStakingBanner = () => { diff --git a/packages/extension/src/ui/action/views/network-assets/index.vue b/packages/extension/src/ui/action/views/network-assets/index.vue index a4dea7119..56d443572 100644 --- a/packages/extension/src/ui/action/views/network-assets/index.vue +++ b/packages/extension/src/ui/action/views/network-assets/index.vue @@ -59,9 +59,13 @@ /> - + + @@ -83,7 +87,9 @@ import scrollSettings from '@/libs/utils/scroll-settings'; import Deposit from '@action/views/deposit/index.vue'; import BaseButton from '@action/components/base-button/index.vue'; import CustomEvmToken from './components/custom-evm-token.vue'; +import CustomMassaToken from './components/custom-massa-token.vue'; import { EvmNetwork } from '@/providers/ethereum/types/evm-network'; +import { ProviderName } from '@/types/provider'; import NetworkAssetsSolanaStakingBanner from './components/network-assets-solana-staking-banner.vue'; import BannersState from '@/libs/banners-state'; @@ -146,6 +152,14 @@ const showAddCustomTokens = ref(false); const isSolanaStakingBanner = ref(false); const bannersState = new BannersState(); +// Network type checks +const isEvmNetwork = computed( + () => props.network.provider === ProviderName.ethereum, +); +const isMassaNetwork = computed( + () => props.network.provider === ProviderName.massa, +); + watch([selectedAddress, selectedNetworkName, selectedSubnetwork], updateAssets); onMounted(async () => { updateAssets(); diff --git a/packages/extension/src/ui/action/views/restricted/index.vue b/packages/extension/src/ui/action/views/restricted/index.vue new file mode 100644 index 000000000..83008fc5c --- /dev/null +++ b/packages/extension/src/ui/action/views/restricted/index.vue @@ -0,0 +1,275 @@ + + + + diff --git a/packages/extension/src/ui/action/views/send-transaction/index.vue b/packages/extension/src/ui/action/views/send-transaction/index.vue index 5e3e90ffe..4a796a729 100644 --- a/packages/extension/src/ui/action/views/send-transaction/index.vue +++ b/packages/extension/src/ui/action/views/send-transaction/index.vue @@ -12,6 +12,7 @@ import SendTransactionEVM from '@/providers/ethereum/ui/send-transaction/index.v import SendTransactionBTC from '@/providers/bitcoin/ui/send-transaction/index.vue'; import SendTransactionKadena from '@/providers/kadena/ui/send-transaction/index.vue'; import SendTransactionSolana from '@/providers/solana/ui/send-transaction/index.vue'; +import SendTransactionMassa from '@/providers/massa/ui/send-transaction/index.vue'; import { useRoute } from 'vue-router'; import { ProviderName } from '@/types/provider'; import { getNetworkByName } from '@/libs/utils/networks'; @@ -25,6 +26,7 @@ const sendLayouts: Record = { [ProviderName.bitcoin]: SendTransactionBTC, [ProviderName.kadena]: SendTransactionKadena, [ProviderName.solana]: SendTransactionSolana, + [ProviderName.massa]: SendTransactionMassa, [ProviderName.enkrypt]: null, }; diff --git a/packages/extension/src/ui/action/views/settings/components/settings-inner-header.vue b/packages/extension/src/ui/action/views/settings/components/settings-inner-header.vue index 4e95041d2..91ed4a748 100644 --- a/packages/extension/src/ui/action/views/settings/components/settings-inner-header.vue +++ b/packages/extension/src/ui/action/views/settings/components/settings-inner-header.vue @@ -1,6 +1,6 @@