diff --git a/packages/atlas/atlas.config.yml b/packages/atlas/atlas.config.yml index ad4db4cb70..906ac34eec 100644 --- a/packages/atlas/atlas.config.yml +++ b/packages/atlas/atlas.config.yml @@ -276,6 +276,8 @@ features: name: Atlas description: Web3 video streaming platform icons: ['https://dev.gleev.xyz/favicon.ico'] + metamask: + snapId: '$VITE_METAMASK_SNAP_ID' # Snap ID for Metamask - npm:@chainsafe/polkadot-snap or (`local:http://localhost:8081` for local development) playback: playbackRates: [2, 1.5, 1.25, 1, 0.5, 0.25] # Playback rates available in the player comments: diff --git a/packages/atlas/src/.env b/packages/atlas/src/.env index 713b2cc03c..48abda15e1 100644 --- a/packages/atlas/src/.env +++ b/packages/atlas/src/.env @@ -18,6 +18,7 @@ VITE_GEOLOCATION_SERVICE_URL=https://geolocation.joystream.org VITE_HCAPTCHA_SITE_KEY=41cae189-7676-4f6b-aa56-635be26d3ceb VITE_CHANGENOW_PUBLIC_API_KEY=0d8a58104f82b860a70e9460bccf62ae1e0fca4a93fd7e0c27c90448187b988f VITE_WALLET_CONNECT_PROJECT_ID=33b2609463e399daee8c51726546c8dd +VITE_METAMASK_SNAP_ID=npm:@chainsafe/polkadot-snap # YPP configuration VITE_GOOGLE_CONSOLE_CLIENT_ID=246331758613-rc1psegmsr9l4e33nqu8rre3gno5dsca.apps.googleusercontent.com diff --git a/packages/atlas/src/config/configSchema.ts b/packages/atlas/src/config/configSchema.ts index 27133b9733..e186a284c6 100644 --- a/packages/atlas/src/config/configSchema.ts +++ b/packages/atlas/src/config/configSchema.ts @@ -130,6 +130,9 @@ export const configSchema = z.object({ icons: z.array(z.string()).nullable(), }), }), + metamask: z.object({ + snapId: z.string().nullable(), + }), playback: z.object({ playbackRates: z.array(z.number()) }), comments: z.object({ reactions: z.array(z.object({ id: z.number(), emoji: z.string(), name: z.string() })), diff --git a/packages/atlas/src/joystream-lib/config.ts b/packages/atlas/src/joystream-lib/config.ts index a95001028e..48e7ec5366 100644 --- a/packages/atlas/src/joystream-lib/config.ts +++ b/packages/atlas/src/joystream-lib/config.ts @@ -4,6 +4,7 @@ export const NFT_DEFAULT_EXTENSION_PERIOD = 5 export const PERBILL_ONE_PERCENT = 10_000_000 export const PERMILL_PER_PERCENT = 10_000 export const JOYSTREAM_SS58_PREFIX = 126 -export const HAPI_TO_JOY_RATE = 10 ** 10 +export const JOY_DECIMALS = 10 +export const HAPI_TO_JOY_RATE = 10 ** JOY_DECIMALS export const AMM_DESCO_CURVE_CONST = 0.4522 diff --git a/packages/atlas/src/providers/wallet/tmpwallet/metamask.ts b/packages/atlas/src/providers/wallet/tmpwallet/metamask.ts new file mode 100644 index 0000000000..96a9f61ca8 --- /dev/null +++ b/packages/atlas/src/providers/wallet/tmpwallet/metamask.ts @@ -0,0 +1,85 @@ +import { enablePolkadotSnap } from '@chainsafe/metamask-polkadot-adapter' +import { MetamaskSnapApi } from '@chainsafe/metamask-polkadot-adapter/build/types' +import { SnapNetworks } from '@chainsafe/metamask-polkadot-types' +import { Signer } from '@polkadot/types/types' +import { BaseDotsamaWallet, SubscriptionFn, WalletAccount } from '@talismn/connect-wallets' + +import { atlasConfig } from '@/config' +import { NODE_HTTP_URL } from '@/config/env' +import { JOY_DECIMALS } from '@/joystream-lib/config' + +import { JOYSTREAM_SS58_PREFIX } from './consts' + +const networkName = 'joystream' as SnapNetworks +const addressPrefix = JOYSTREAM_SS58_PREFIX +const unit = { symbol: atlasConfig.joystream.tokenTicker, decimals: JOY_DECIMALS } + +export class MetamaskWallet extends BaseDotsamaWallet { + protected _snapId: string + protected _snapApi: MetamaskSnapApi | undefined + protected _accounts: WalletAccount[] | undefined + protected _txId = 0 + + public get installed(): boolean { + return '_metamask' in window.ethereum + } + + constructor(snapId: string) { + super() + + this.extensionName = 'Metamask' + this.title = 'Metamask' + this.logo = { src: 'https://metamask.io/images/metamask-logo.png', alt: 'Metamask Logo' } + + this._snapId = snapId + } + + public enable = async (): Promise => { + const snap = await enablePolkadotSnap({ networkName, wsRpcUrl: NODE_HTTP_URL, addressPrefix, unit }, this._snapId) + + this._snapApi = await snap.getMetamaskSnapApi() + const address = await this._snapApi.getAddress() + this._accounts = [ + { + name: 'Metamask account', + address, + source: this.extensionName, + }, + ] + + this._snapApi.signPayloadJSON + } + + public getAccounts = async (): Promise => { + return this._accounts ?? [] + } + + public subscribeAccounts: (callback: SubscriptionFn) => Promise<() => void> = (callback) => { + callback(this._accounts ?? []) + return Promise.resolve(() => undefined) + } + + public get signer(): Signer { + return { + signPayload: async (payload) => { + if (!this._snapApi) { + throw Error('Metamask was accessed before it was enabled') + } + + const signature = (await this._snapApi.signPayloadJSON(payload)) as `0x${string}` + + return { id: this._txId++, signature } + }, + + signRaw: async (raw) => { + if (!this._snapApi) { + throw Error('Metamask was accessed before it was enabled') + } + + const signature = (await this._snapApi.signPayloadRaw(raw)) as `0x${string}` + + return { id: this._txId++, signature } + }, + } + } +} diff --git a/packages/atlas/src/providers/wallet/wallet.helpers.ts b/packages/atlas/src/providers/wallet/wallet.helpers.ts index b25c309248..a80834c934 100644 --- a/packages/atlas/src/providers/wallet/wallet.helpers.ts +++ b/packages/atlas/src/providers/wallet/wallet.helpers.ts @@ -2,6 +2,8 @@ import { BaseDotsamaWallet, Wallet, getWallets } from '@talismn/connect-wallets' import { atlasConfig } from '@/config' +import { MetamaskWallet } from './tmpwallet/metamask' + export const getWalletsList = () => { const supportedWallets = getWallets() const supportedWalletsNames = supportedWallets.map((wallet) => wallet.extensionName) @@ -26,10 +28,13 @@ export const getWalletsList = () => { installed: true, } as Wallet + const metamaskSnapId = atlasConfig.features.metamask.snapId + return [ ...supportedWallets, ...unknownWallets, ...(atlasConfig.features.walletConnect.walletConnectProjectId ? [wcWallet] : []), + ...(metamaskSnapId ? [new MetamaskWallet(metamaskSnapId)] : []), ] } diff --git a/packages/atlas/src/providers/wallet/wallet.provider.tsx b/packages/atlas/src/providers/wallet/wallet.provider.tsx index 4c023d6403..46f91354db 100644 --- a/packages/atlas/src/providers/wallet/wallet.provider.tsx +++ b/packages/atlas/src/providers/wallet/wallet.provider.tsx @@ -99,9 +99,7 @@ export const WalletProvider: FC = ({ children }) => { await selectedWallet.enable(atlasConfig.general.appName) - // taken from https://github.com/TalismanSociety/talisman-connect/blob/47cfefee9f1333326c0605c159d6ee8ebfba3e84/libs/wallets/src/lib/base-dotsama-wallet/index.ts#L98-L107 - // should be part of future talisman-connect release - const accounts = await selectedWallet.extension.accounts.get() + const accounts = await selectedWallet.getAccounts() const accountsWithWallet = accounts .filter(filterUnsupportedAccounts)