From 4559f596d71758bbce9c072e7d3767ae9c33bc96 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Mon, 4 Nov 2024 19:26:57 -0300 Subject: [PATCH 01/34] refactor: add params in getNonce function --- packages/siwx/src/core/SIWXMessenger.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/siwx/src/core/SIWXMessenger.ts b/packages/siwx/src/core/SIWXMessenger.ts index 41a730ea8c..b743c7ca9f 100644 --- a/packages/siwx/src/core/SIWXMessenger.ts +++ b/packages/siwx/src/core/SIWXMessenger.ts @@ -38,7 +38,7 @@ export abstract class SIWXMessenger { uri: this.uri, statement: this.statement, resources: this.resources, - nonce: await this.getNonce(), + nonce: await this.getNonce(input), requestId: await this.getRequestId?.(), expirationTime: this.getExpirationTime(input), issuedAt: this.getIssuedAt(), @@ -86,7 +86,7 @@ export namespace SIWXMessenger { /** * Getter function for message nonce value */ - getNonce: () => Promise + getNonce: (params: SIWXMessageInput) => Promise /** * Getter function for message request ID * If not provided, the request ID will be omitted From 4938fdb93398c032361bb439a82895fe275a0c55 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Mon, 4 Nov 2024 19:28:04 -0300 Subject: [PATCH 02/34] feat: add map to siwx function --- packages/siwe/exports/index.ts | 1 + packages/siwe/package.json | 1 + packages/siwe/src/mapToSIWX.ts | 86 ++++++++++++++++++++++++++++++++++ pnpm-lock.yaml | 15 +++--- 4 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 packages/siwe/src/mapToSIWX.ts diff --git a/packages/siwe/exports/index.ts b/packages/siwe/exports/index.ts index 07219eb3b3..a97e752f44 100644 --- a/packages/siwe/exports/index.ts +++ b/packages/siwe/exports/index.ts @@ -17,3 +17,4 @@ export function createSIWEConfig(siweConfig: SIWEConfig) { export * from '../scaffold/partials/w3m-connecting-siwe/index.js' export * from '../scaffold/views/w3m-connecting-siwe-view/index.js' +export * from '../src/mapToSIWX.js' diff --git a/packages/siwe/package.json b/packages/siwe/package.json index c74b7dc9f0..7cb756a87a 100644 --- a/packages/siwe/package.json +++ b/packages/siwe/package.json @@ -22,6 +22,7 @@ "@reown/appkit-common": "workspace:*", "@reown/appkit-wallet": "workspace:*", "@reown/appkit-utils": "workspace:*", + "@reown/appkit-siwx": "workspace:*", "valtio": "1.11.2", "lit": "3.1.0" }, diff --git a/packages/siwe/src/mapToSIWX.ts b/packages/siwe/src/mapToSIWX.ts new file mode 100644 index 0000000000..3b278c6606 --- /dev/null +++ b/packages/siwe/src/mapToSIWX.ts @@ -0,0 +1,86 @@ +import type { SIWXConfig, SIWXMessage, SIWXSession } from '@reown/appkit-core' +import type { SIWEConfig } from '../exports/index.js' +import { DefaultSIWX, InformalMessenger } from '@reown/appkit-siwx' +import { NetworkUtil } from '@reown/appkit-common' + +export async function mapToSIWX(siwe: SIWEConfig): Promise { + const params = await siwe.getMessageParams?.() + + const domain = params?.domain || 'Unknown Domain' + const uri = params?.uri || 'Unknown URI' + + const messenger = new InformalMessenger({ + domain, + uri, + expiration: params?.expiry, + getNonce: ({ accountAddress }) => siwe.getNonce(accountAddress) + }) + + return new DefaultSIWX({ + messenger, + + verifiers: [ + { + chainNamespace: 'eip155', + shouldVerify: session => session.message.chainId.startsWith('eip155'), + verify: async session => { + const success = await siwe.verifyMessage({ + message: session.message.toString(), + signature: session.signature + }) + + return success + } + } + ], + + storage: { + add: async session => { + const chainId = NetworkUtil.parseEvmChainId(session.message.chainId) + + if (!chainId) { + throw new Error('Invalid chain ID!') + } + + siwe.onSignIn?.({ + address: session.message.accountAddress, + chainId + }) + + return Promise.resolve() + }, + + get: async () => { + try { + const siweSession = await siwe.getSession() + if (!siweSession) { + return [] + } + + // How should we parse the session? + const session: SIWXSession = { + message: { + accountAddress: siweSession.address, + chainId: `eip155:${siweSession.chainId}` + } as SIWXMessage, + signature: '' + } + + return [session] + } catch { + return [] + } + }, + + set: async () => Promise.resolve(), + + delete: async () => { + if (await siwe.signOut()) { + return Promise.resolve() + } + + throw new Error('Failed to sign out!') + } + } + }) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ac49e41fa..47b7c1509b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1418,6 +1418,9 @@ importers: '@reown/appkit-core': specifier: workspace:* version: link:../core + '@reown/appkit-siwx': + specifier: workspace:* + version: link:../siwx '@reown/appkit-ui': specifier: workspace:* version: link:../ui @@ -23740,7 +23743,7 @@ snapshots: eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0))(eslint@8.56.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0))(eslint@8.56.0))(eslint@8.56.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.56.0) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.56.0) eslint-plugin-react: 7.37.1(eslint@8.56.0) eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.56.0) @@ -23759,7 +23762,7 @@ snapshots: eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@6.18.1(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.18.1(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.0) eslint-plugin-react: 7.37.1(eslint@8.57.0) eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.57.0) @@ -23794,7 +23797,7 @@ snapshots: is-bun-module: 1.2.1 is-glob: 4.0.3 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0))(eslint@8.56.0))(eslint@8.56.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.56.0) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node @@ -23813,7 +23816,7 @@ snapshots: is-bun-module: 1.2.1 is-glob: 4.0.3 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.18.1(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node @@ -23842,7 +23845,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint@8.56.0))(eslint@8.56.0))(eslint@8.56.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.56.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -23871,7 +23874,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.18.1(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.56.0)(typescript@5.3.3))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.18.1(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 From 2ce57a2e912cdaeb8f99785b3b3a0e27969e70cb Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Mon, 4 Nov 2024 19:46:55 -0300 Subject: [PATCH 03/34] refactor: apply siwx over siwe --- packages/adapters/ethers/src/client.ts | 6 - packages/adapters/ethers5/src/client.ts | 6 - .../solana/src/providers/AuthProvider.ts | 2 +- .../src/providers/WalletConnectProvider.ts | 8 +- .../src/providers/WalletStandardProvider.ts | 2 +- packages/adapters/wagmi/src/client.ts | 99 ---------------- packages/appkit/exports/constants.ts | 2 +- packages/appkit/src/client.ts | 9 +- .../appkit/src/universal-adapter/client.ts | 107 +----------------- .../scaffold-ui/src/modal/w3m-modal/index.ts | 80 +------------ .../src/partials/w3m-header/index.ts | 16 +-- packages/scaffold-ui/src/utils/NetworkUtil.ts | 19 +--- 12 files changed, 29 insertions(+), 327 deletions(-) diff --git a/packages/adapters/ethers/src/client.ts b/packages/adapters/ethers/src/client.ts index 4aa3e36ce4..ddcd3eb22e 100644 --- a/packages/adapters/ethers/src/client.ts +++ b/packages/adapters/ethers/src/client.ts @@ -102,8 +102,6 @@ export class EthersAdapter { public connectionControllerClient?: ConnectionControllerClient - public siweControllerClient = this.options?.siweConfig - public tokens = HelpersUtil.getCaipTokens(this.options?.tokens) public defaultCaipNetwork: CaipNetwork | undefined = undefined @@ -329,10 +327,6 @@ export class EthersAdapter { const providerId = ProviderUtil.state.providerIds['eip155'] this.appKit?.setClientId(null) - if (this.options?.siweConfig?.options?.signOutOnDisconnect) { - const { SIWEController } = await import('@reown/appkit-siwe') - await SIWEController.signOut() - } const disconnectConfig = { [ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID]: async () => diff --git a/packages/adapters/ethers5/src/client.ts b/packages/adapters/ethers5/src/client.ts index f4088f7568..d0532c6213 100644 --- a/packages/adapters/ethers5/src/client.ts +++ b/packages/adapters/ethers5/src/client.ts @@ -102,8 +102,6 @@ export class Ethers5Adapter { public connectionControllerClient?: ConnectionControllerClient - public siweControllerClient = this.options?.siweConfig - public tokens = HelpersUtil.getCaipTokens(this.options?.tokens) public defaultCaipNetwork: CaipNetwork | undefined = undefined @@ -329,10 +327,6 @@ export class Ethers5Adapter { const providerId = ProviderUtil.state.providerIds['eip155'] this.appKit?.setClientId(null) - if (this.options?.siweConfig?.options?.signOutOnDisconnect) { - const { SIWEController } = await import('@reown/appkit-siwe') - await SIWEController.signOut() - } const disconnectConfig = { [ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID]: async () => diff --git a/packages/adapters/solana/src/providers/AuthProvider.ts b/packages/adapters/solana/src/providers/AuthProvider.ts index b4fd951489..1d8db81e6f 100644 --- a/packages/adapters/solana/src/providers/AuthProvider.ts +++ b/packages/adapters/solana/src/providers/AuthProvider.ts @@ -213,7 +213,7 @@ export class AuthProvider extends ProviderEventEmitter implements Provider, Prov } private serializeTransaction(transaction: AnyTransaction) { - return base58.encode(transaction.serialize({ verifySignatures: false })) + return base58.encode(Uint8Array.from(transaction.serialize({ verifySignatures: false }))) } private bindEvents() { diff --git a/packages/adapters/solana/src/providers/WalletConnectProvider.ts b/packages/adapters/solana/src/providers/WalletConnectProvider.ts index 9068b34449..b60a55635c 100644 --- a/packages/adapters/solana/src/providers/WalletConnectProvider.ts +++ b/packages/adapters/solana/src/providers/WalletConnectProvider.ts @@ -145,13 +145,13 @@ export class WalletConnectProvider extends ProviderEventEmitter implements Provi if ('signature' in result) { transaction.addSignature( new PublicKey(this.getAccount(true).publicKey), - Buffer.from(base58.decode(result.signature)) + Buffer.from(base58.decode(result.signature)) as Uint8Array & Buffer ) return transaction } - const decodedTransaction = Buffer.from(result.transaction, 'base64') + const decodedTransaction = Uint8Array.from(Buffer.from(result.transaction, 'base64')) if (isVersionedTransaction(transaction)) { return VersionedTransaction.deserialize(decodedTransaction) as T @@ -203,7 +203,7 @@ export class WalletConnectProvider extends ProviderEventEmitter implements Provi throw new Error('Invalid transactions response') } - const decodedTransaction = Buffer.from(serializedTransaction, 'base64') + const decodedTransaction = Uint8Array.from(Buffer.from(serializedTransaction, 'base64')) if (isVersionedTransaction(transaction)) { return VersionedTransaction.deserialize(decodedTransaction) @@ -336,7 +336,7 @@ export class WalletConnectProvider extends ProviderEventEmitter implements Provi return { feePayer: transaction.feePayer?.toBase58() ?? '', instructions: transaction.instructions.map(instruction => ({ - data: base58.encode(instruction.data), + data: base58.encode(Uint8Array.from(instruction.data)), keys: instruction.keys.map(key => ({ isWritable: key.isWritable, isSigner: key.isSigner, diff --git a/packages/adapters/solana/src/providers/WalletStandardProvider.ts b/packages/adapters/solana/src/providers/WalletStandardProvider.ts index 91289eee06..40978d3203 100644 --- a/packages/adapters/solana/src/providers/WalletStandardProvider.ts +++ b/packages/adapters/solana/src/providers/WalletStandardProvider.ts @@ -220,7 +220,7 @@ export class WalletStandardProvider extends ProviderEventEmitter implements Prov // -- Private ------------------------------------------- // private serializeTransaction(transaction: AnyTransaction) { - return transaction.serialize({ verifySignatures: false }) + return Uint8Array.from(transaction.serialize({ verifySignatures: false })) } private getAccount( diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index 61beae5f57..24786dfc71 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -90,30 +90,6 @@ export interface AdapterOptions defaultNetwork?: Chain } -const OPTIONAL_METHODS = [ - 'eth_accounts', - 'eth_requestAccounts', - 'eth_sendRawTransaction', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - 'eth_sendTransaction', - 'personal_sign', - 'wallet_switchEthereumChain', - 'wallet_addEthereumChain', - 'wallet_getPermissions', - 'wallet_requestPermissions', - 'wallet_registerOnboarding', - 'wallet_watchAsset', - 'wallet_scanQRCode', - 'wallet_getCallsStatus', - 'wallet_sendCalls', - 'wallet_getCapabilities', - 'wallet_grantPermissions' -] - // @ts-expect-error: Overridden state type is correct interface AppKitState extends PublicStateControllerState { selectedNetworkId: number | undefined @@ -307,77 +283,6 @@ export class WagmiAdapter implements ChainAdapter { throw new Error('connectionControllerClient:getWalletConnectUri - connector is undefined') } - const provider = (await connector.getProvider()) as Awaited< - ReturnType<(typeof UniversalProvider)['init']> - > - - const siweParams = await this.options?.siweConfig?.getMessageParams?.() - - const isSiweEnabled = this.options?.siweConfig?.options?.enabled - const isProviderSupported = typeof provider?.authenticate === 'function' - const isSiweParamsValid = siweParams && Object.keys(siweParams || {}).length > 0 - const siweConfig = this.options?.siweConfig - - if (isSiweEnabled && isProviderSupported && isSiweParamsValid && siweConfig) { - // @ts-expect-error - setting requested chains beforehand avoids wagmi auto disconnecting the session when `connect` is called because it things chains are stale - await connector.setRequestedChainsIds(siweParams.chains) - - const { SIWEController, getDidChainId, getDidAddress } = await import( - '@reown/appkit-siwe' - ) - - const chains = this.caipNetworks - ?.filter(network => network.chainNamespace === 'eip155') - .map(chain => chain.caipNetworkId) as string[] - - siweParams.chains = this.caipNetworks - ?.filter(network => network.chainNamespace === 'eip155') - .map(chain => chain.id) as number[] - - const result = await provider.authenticate({ - nonce: await siweConfig.getNonce(), - methods: [...OPTIONAL_METHODS], - ...siweParams, - chains - }) - // Auths is an array of signed CACAO objects https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-74.md - const signedCacao = result?.auths?.[0] - - if (signedCacao) { - const { p, s } = signedCacao - const cacaoChainId = getDidChainId(p.iss) - const address = getDidAddress(p.iss) - if (address && cacaoChainId) { - SIWEController.setSession({ - address, - chainId: parseInt(cacaoChainId, 10) - }) - } - - try { - // Kicks off verifyMessage and populates external states - const message = provider.client.formatAuthMessage({ - request: p, - iss: p.iss - }) - - await SIWEController.verifyMessage({ - message, - signature: s.s, - cacao: signedCacao - }) - } catch (error) { - // eslint-disable-next-line no-console - console.error('Error verifying message', error) - // eslint-disable-next-line no-console - await provider.disconnect().catch(console.error) - // eslint-disable-next-line no-console - await SIWEController.signOut().catch(console.error) - throw error - } - } - } - const chainId = this.appKit?.getCaipNetworkId() await connect(this.wagmiConfig, { connector, chainId }) }, @@ -428,10 +333,6 @@ export class WagmiAdapter implements ChainAdapter { }, disconnect: async () => { await disconnect(this.wagmiConfig) - if (this.options?.siweConfig?.options?.signOutOnDisconnect) { - const { SIWEController } = await import('@reown/appkit-siwe') - await SIWEController.signOut() - } SafeLocalStorage.removeItem(SafeLocalStorageKeys.WALLET_ID) SafeLocalStorage.removeItem(SafeLocalStorageKeys.CONNECTED_CONNECTOR) SafeLocalStorage.removeItem(SafeLocalStorageKeys.WALLET_NAME) diff --git a/packages/appkit/exports/constants.ts b/packages/appkit/exports/constants.ts index c255be9da0..b9b53e16d7 100644 --- a/packages/appkit/exports/constants.ts +++ b/packages/appkit/exports/constants.ts @@ -1 +1 @@ -export const PACKAGE_VERSION = '1.2.0' +export const PACKAGE_VERSION = '1.2.1' diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index 947ff36613..5ca31afe68 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -534,8 +534,13 @@ export class AppKit { // Set the SIWE client for EVM chains if (evmAdapter) { if (options.siweConfig) { - const { SIWEController } = await import('@reown/appkit-siwe') - SIWEController.setSIWEClient(options.siweConfig) + if (options.siwx) { + throw new Error('Cannot set both siweConfig and siwx') + } + + const { mapToSIWX } = await import('@reown/appkit-siwe') + const siwx = await mapToSIWX(options.siweConfig) + OptionsController.setSIWX(siwx) } } } diff --git a/packages/appkit/src/universal-adapter/client.ts b/packages/appkit/src/universal-adapter/client.ts index e7432082f3..6eb7bd4861 100644 --- a/packages/appkit/src/universal-adapter/client.ts +++ b/packages/appkit/src/universal-adapter/client.ts @@ -32,33 +32,6 @@ type Metadata = { icons: string[] } -const OPTIONAL_METHODS = [ - 'eth_accounts', - 'eth_requestAccounts', - 'eth_sendRawTransaction', - 'eth_sign', - 'eth_signTransaction', - 'eth_signTypedData', - 'eth_signTypedData_v3', - 'eth_signTypedData_v4', - 'eth_sendTransaction', - 'personal_sign', - 'wallet_switchEthereumChain', - 'wallet_addEthereumChain', - 'wallet_getPermissions', - 'wallet_requestPermissions', - 'wallet_registerOnboarding', - 'wallet_watchAsset', - 'wallet_scanQRCode', - // EIP-5792 - 'wallet_getCallsStatus', - 'wallet_sendCalls', - 'wallet_getCapabilities', - // EIP-7715 - 'wallet_grantPermissions', - 'wallet_revokePermissions' -] - // -- Client -------------------------------------------------------------------- export class UniversalAdapterClient { private walletConnectProviderInitPromise?: Promise @@ -86,7 +59,7 @@ export class UniversalAdapterClient { public reportErrors = true public constructor(options: AppKitOptionsWithCaipNetworks) { - const { siweConfig, metadata } = options + const { metadata } = options this.caipNetworks = options.networks @@ -144,77 +117,8 @@ export class UniversalAdapterClient { await adapter?.connectionControllerClient?.connectWalletConnect?.(onUri) this.setWalletConnectProvider() } else { - const siweParams = await siweConfig?.getMessageParams?.() - const isSiweEnabled = siweConfig?.options?.enabled - const isProviderSupported = typeof WalletConnectProvider?.authenticate === 'function' - const isSiweParamsValid = siweParams && Object.keys(siweParams || {}).length > 0 - - if ( - siweConfig && - isSiweEnabled && - siweParams && - isProviderSupported && - isSiweParamsValid && - ChainController.state.activeChain === CommonConstantsUtil.CHAIN.EVM - ) { - const { SIWEController, getDidChainId, getDidAddress } = await import( - '@reown/appkit-siwe' - ) - - const chains = this.caipNetworks - ?.filter(network => network.chainNamespace === CommonConstantsUtil.CHAIN.EVM) - .map(chain => chain.caipNetworkId) as string[] - - siweParams.chains = this.caipNetworks - ?.filter(network => network.chainNamespace === CommonConstantsUtil.CHAIN.EVM) - .map(chain => chain.id) as number[] - - const result = await WalletConnectProvider.authenticate({ - nonce: await siweConfig?.getNonce?.(), - methods: [...OPTIONAL_METHODS], - ...siweParams, - chains - }) - // Auths is an array of signed CACAO objects https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-74.md - const signedCacao = result?.auths?.[0] - - if (signedCacao) { - const { p, s } = signedCacao - const cacaoChainId = getDidChainId(p.iss) - const address = getDidAddress(p.iss) - if (address && cacaoChainId) { - SIWEController.setSession({ - address, - chainId: parseInt(cacaoChainId, 10) - }) - } - - try { - // Kicks off verifyMessage and populates external states - const message = WalletConnectProvider.client.formatAuthMessage({ - request: p, - iss: p.iss - }) - - await SIWEController.verifyMessage({ - message, - signature: s.s, - cacao: signedCacao - }) - } catch (error) { - // eslint-disable-next-line no-console - console.error('Error verifying message', error) - // eslint-disable-next-line no-console - await WalletConnectProvider.disconnect().catch(console.error) - // eslint-disable-next-line no-console - await SIWEController.signOut().catch(console.error) - throw error - } - } - } else { - const optionalNamespaces = WcHelpersUtil.createNamespaces(this.caipNetworks) - await WalletConnectProvider.connect({ optionalNamespaces }) - } + const optionalNamespaces = WcHelpersUtil.createNamespaces(this.caipNetworks) + await WalletConnectProvider.connect({ optionalNamespaces }) this.setWalletConnectProvider() } }, @@ -222,11 +126,6 @@ export class UniversalAdapterClient { disconnect: async () => { SafeLocalStorage.removeItem(SafeLocalStorageKeys.WALLET_ID) - if (siweConfig?.options?.signOutOnDisconnect) { - const { SIWEController } = await import('@reown/appkit-siwe') - await SIWEController.signOut() - } - await this.walletConnectProvider?.disconnect() this.appKit?.resetAccount(CommonConstantsUtil.CHAIN.EVM) diff --git a/packages/scaffold-ui/src/modal/w3m-modal/index.ts b/packages/scaffold-ui/src/modal/w3m-modal/index.ts index b0b281ef66..169ec64a8c 100644 --- a/packages/scaffold-ui/src/modal/w3m-modal/index.ts +++ b/packages/scaffold-ui/src/modal/w3m-modal/index.ts @@ -14,12 +14,7 @@ import { UiHelperUtil, customElement, initializeTheming } from '@reown/appkit-ui import { LitElement, html } from 'lit' import { state } from 'lit/decorators.js' import styles from './styles.js' -import { - ConstantsUtil, - type CaipAddress, - type CaipNetwork, - type SIWEStatus -} from '@reown/appkit-common' +import { type CaipAddress, type CaipNetwork, type SIWEStatus } from '@reown/appkit-common' // -- Helpers --------------------------------------------- // const SCROLL_LOCK = 'scroll-lock' @@ -97,20 +92,9 @@ export class W3mModal extends LitElement { } private async handleClose() { - const isSiweSignScreen = RouterController.state.view === 'ConnectingSiwe' - const isApproveSignScreen = RouterController.state.view === 'ApproveTransaction' + ModalController.close() - if (this.isSiweEnabled) { - const { SIWEController } = await import('@reown/appkit-siwe') - const isUnauthenticated = SIWEController.state.status !== 'success' - if (isUnauthenticated && (isSiweSignScreen || isApproveSignScreen)) { - ModalController.shake() - } else { - ModalController.close() - } - } else { - ModalController.close() - } + return Promise.resolve() } private initializeTheming() { @@ -188,41 +172,17 @@ export class W3mModal extends LitElement { } } - private async onNewAddress(caipAddress?: CaipAddress) { - const prevCaipAddress = this.caipAddress - const prevConnected = prevCaipAddress - ? CoreHelperUtil.getPlainAddress(prevCaipAddress) - : undefined + private onNewAddress(caipAddress?: CaipAddress) { const nextConnected = caipAddress ? CoreHelperUtil.getPlainAddress(caipAddress) : undefined - const isSameAddress = prevConnected === nextConnected this.caipAddress = caipAddress - if (nextConnected && !isSameAddress && this.isSiweEnabled) { - try { - const { SIWEController } = await import('@reown/appkit-siwe') - const signed = AccountController.state.siweStatus === 'success' - - if (!prevConnected && nextConnected) { - this.onSiweNavigation() - } else if (signed && prevConnected && nextConnected && prevConnected !== nextConnected) { - if (SIWEController.state._client?.options.signOutOnAccountChange) { - await SIWEController.signOut() - this.onSiweNavigation() - } - } - } catch (err) { - this.caipAddress = prevCaipAddress - throw err - } - } - if (!nextConnected) { ModalController.close() } } - private async onNewNetwork(nextCaipNetwork: CaipNetwork | undefined) { + private onNewNetwork(nextCaipNetwork: CaipNetwork | undefined) { if (!this.caipAddress) { this.caipNetwork = nextCaipNetwork RouterController.goBack() @@ -234,37 +194,9 @@ export class W3mModal extends LitElement { const nextNetworkId = nextCaipNetwork?.caipNetworkId?.toString() if (prevCaipNetworkId && nextNetworkId && prevCaipNetworkId !== nextNetworkId) { - if (this.isSiweEnabled) { - const { SIWEController } = await import('@reown/appkit-siwe') - - if (SIWEController.state._client?.options.signOutOnNetworkChange) { - await SIWEController.signOut() - this.onSiweNavigation() - } else { - RouterController.goBack() - } - } else { - RouterController.goBack() - } - } - this.caipNetwork = nextCaipNetwork - } - - private onSiweNavigation() { - const isEIP155Namespace = ChainController.state.activeChain === ConstantsUtil.CHAIN.EVM - const authenticated = AccountController.state.siweStatus === 'success' - - if (!authenticated && isEIP155Namespace) { - if (this.open) { - RouterController.replace('ConnectingSiwe') - } else { - ModalController.open({ - view: 'ConnectingSiwe' - }) - } - } else { RouterController.goBack() } + this.caipNetwork = nextCaipNetwork } } diff --git a/packages/scaffold-ui/src/partials/w3m-header/index.ts b/packages/scaffold-ui/src/partials/w3m-header/index.ts index 05c3c28bd9..5038541080 100644 --- a/packages/scaffold-ui/src/partials/w3m-header/index.ts +++ b/packages/scaffold-ui/src/partials/w3m-header/index.ts @@ -153,19 +153,9 @@ export class W3mHeader extends LitElement { } private async onClose() { - if (this.isSiweEnabled) { - const { SIWEController } = await import('@reown/appkit-siwe') - const isApproveSignScreen = RouterController.state.view === 'ApproveTransaction' - const isUnauthenticated = SIWEController.state.status !== 'success' - - if (isUnauthenticated && isApproveSignScreen) { - RouterController.popTransactionStack(true) - } else { - ModalController.close() - } - } else { - ModalController.close() - } + ModalController.close() + + return Promise.resolve() } private rightHeaderTemplate() { diff --git a/packages/scaffold-ui/src/utils/NetworkUtil.ts b/packages/scaffold-ui/src/utils/NetworkUtil.ts index da3751b102..d0286fe91a 100644 --- a/packages/scaffold-ui/src/utils/NetworkUtil.ts +++ b/packages/scaffold-ui/src/utils/NetworkUtil.ts @@ -1,22 +1,9 @@ -import { ConstantsUtil } from '@reown/appkit-common' -import { ChainController, OptionsController, RouterUtil } from '@reown/appkit-core' +import { RouterUtil } from '@reown/appkit-core' export const NetworkUtil = { onNetworkChange: async () => { - const isEIP155Namespace = ChainController.state.activeChain === ConstantsUtil.CHAIN.EVM + RouterUtil.navigateAfterNetworkSwitch() - if (OptionsController.state.isSiweEnabled) { - const { SIWEController } = await import('@reown/appkit-siwe') - const shouldSignOut = - SIWEController.state._client?.options?.signOutOnNetworkChange && isEIP155Namespace - - if (shouldSignOut) { - await SIWEController.signOut() - } - - RouterUtil.navigateAfterNetworkSwitch() - } else { - RouterUtil.navigateAfterNetworkSwitch() - } + return Promise.resolve() } } From 6e4cbed35dc9533899cf507054db026ec35ffd53 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 7 Nov 2024 11:17:37 -0300 Subject: [PATCH 04/34] fix: issues after rebase --- packages/adapters/wagmi/src/client.ts | 2 -- packages/scaffold-ui/src/modal/w3m-modal/index.ts | 6 +----- packages/siwe/src/mapToSIWX.ts | 11 ++++++----- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index 24786dfc71..4293eedaaa 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -119,8 +119,6 @@ export class WagmiAdapter implements ChainAdapter { public tokens = HelpersUtil.getCaipTokens(this.options?.tokens) - public siweControllerClient = this.options?.siweConfig - public adapterType: AdapterType = 'wagmi' public constructor( diff --git a/packages/scaffold-ui/src/modal/w3m-modal/index.ts b/packages/scaffold-ui/src/modal/w3m-modal/index.ts index 169ec64a8c..31d43c33ea 100644 --- a/packages/scaffold-ui/src/modal/w3m-modal/index.ts +++ b/packages/scaffold-ui/src/modal/w3m-modal/index.ts @@ -5,7 +5,6 @@ import { CoreHelperUtil, EventsController, ModalController, - OptionsController, RouterController, SnackController, ThemeController @@ -35,8 +34,6 @@ export class W3mModal extends LitElement { @state() private caipNetwork = ChainController.state.activeCaipNetwork - @state() private isSiweEnabled = OptionsController.state.isSiweEnabled - @state() private shake = ModalController.state.shake public constructor() { @@ -49,8 +46,7 @@ export class W3mModal extends LitElement { ModalController.subscribeKey('shake', val => (this.shake = val)), AccountController.subscribeKey('siweStatus', val => this.onSiweStatusChange(val), 'eip155'), ChainController.subscribeKey('activeCaipNetwork', val => this.onNewNetwork(val)), - ChainController.subscribeKey('activeCaipAddress', val => this.onNewAddress(val)), - OptionsController.subscribeKey('isSiweEnabled', val => (this.isSiweEnabled = val)) + ChainController.subscribeKey('activeCaipAddress', val => this.onNewAddress(val)) ] ) EventsController.sendEvent({ type: 'track', event: 'MODAL_LOADED' }) diff --git a/packages/siwe/src/mapToSIWX.ts b/packages/siwe/src/mapToSIWX.ts index 3b278c6606..a9ac5352bc 100644 --- a/packages/siwe/src/mapToSIWX.ts +++ b/packages/siwe/src/mapToSIWX.ts @@ -22,7 +22,7 @@ export async function mapToSIWX(siwe: SIWEConfig): Promise { verifiers: [ { chainNamespace: 'eip155', - shouldVerify: session => session.message.chainId.startsWith('eip155'), + shouldVerify: session => session.data.chainId.startsWith('eip155'), verify: async session => { const success = await siwe.verifyMessage({ message: session.message.toString(), @@ -36,14 +36,14 @@ export async function mapToSIWX(siwe: SIWEConfig): Promise { storage: { add: async session => { - const chainId = NetworkUtil.parseEvmChainId(session.message.chainId) + const chainId = NetworkUtil.parseEvmChainId(session.data.chainId) if (!chainId) { throw new Error('Invalid chain ID!') } siwe.onSignIn?.({ - address: session.message.accountAddress, + address: session.data.accountAddress, chainId }) @@ -59,10 +59,11 @@ export async function mapToSIWX(siwe: SIWEConfig): Promise { // How should we parse the session? const session: SIWXSession = { - message: { + data: { accountAddress: siweSession.address, chainId: `eip155:${siweSession.chainId}` - } as SIWXMessage, + } as SIWXMessage.Data, + message: '', signature: '' } From 2e01a07dc5cbe5f594720d779f6b2a687a59f896 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 7 Nov 2024 11:31:16 -0300 Subject: [PATCH 05/34] chore: revert ts issue changes on solana adapter --- packages/adapters/solana/src/providers/AuthProvider.ts | 2 +- .../solana/src/providers/WalletConnectProvider.ts | 8 ++++---- .../solana/src/providers/WalletStandardProvider.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/adapters/solana/src/providers/AuthProvider.ts b/packages/adapters/solana/src/providers/AuthProvider.ts index 1d8db81e6f..b4fd951489 100644 --- a/packages/adapters/solana/src/providers/AuthProvider.ts +++ b/packages/adapters/solana/src/providers/AuthProvider.ts @@ -213,7 +213,7 @@ export class AuthProvider extends ProviderEventEmitter implements Provider, Prov } private serializeTransaction(transaction: AnyTransaction) { - return base58.encode(Uint8Array.from(transaction.serialize({ verifySignatures: false }))) + return base58.encode(transaction.serialize({ verifySignatures: false })) } private bindEvents() { diff --git a/packages/adapters/solana/src/providers/WalletConnectProvider.ts b/packages/adapters/solana/src/providers/WalletConnectProvider.ts index b60a55635c..9068b34449 100644 --- a/packages/adapters/solana/src/providers/WalletConnectProvider.ts +++ b/packages/adapters/solana/src/providers/WalletConnectProvider.ts @@ -145,13 +145,13 @@ export class WalletConnectProvider extends ProviderEventEmitter implements Provi if ('signature' in result) { transaction.addSignature( new PublicKey(this.getAccount(true).publicKey), - Buffer.from(base58.decode(result.signature)) as Uint8Array & Buffer + Buffer.from(base58.decode(result.signature)) ) return transaction } - const decodedTransaction = Uint8Array.from(Buffer.from(result.transaction, 'base64')) + const decodedTransaction = Buffer.from(result.transaction, 'base64') if (isVersionedTransaction(transaction)) { return VersionedTransaction.deserialize(decodedTransaction) as T @@ -203,7 +203,7 @@ export class WalletConnectProvider extends ProviderEventEmitter implements Provi throw new Error('Invalid transactions response') } - const decodedTransaction = Uint8Array.from(Buffer.from(serializedTransaction, 'base64')) + const decodedTransaction = Buffer.from(serializedTransaction, 'base64') if (isVersionedTransaction(transaction)) { return VersionedTransaction.deserialize(decodedTransaction) @@ -336,7 +336,7 @@ export class WalletConnectProvider extends ProviderEventEmitter implements Provi return { feePayer: transaction.feePayer?.toBase58() ?? '', instructions: transaction.instructions.map(instruction => ({ - data: base58.encode(Uint8Array.from(instruction.data)), + data: base58.encode(instruction.data), keys: instruction.keys.map(key => ({ isWritable: key.isWritable, isSigner: key.isSigner, diff --git a/packages/adapters/solana/src/providers/WalletStandardProvider.ts b/packages/adapters/solana/src/providers/WalletStandardProvider.ts index 40978d3203..91289eee06 100644 --- a/packages/adapters/solana/src/providers/WalletStandardProvider.ts +++ b/packages/adapters/solana/src/providers/WalletStandardProvider.ts @@ -220,7 +220,7 @@ export class WalletStandardProvider extends ProviderEventEmitter implements Prov // -- Private ------------------------------------------- // private serializeTransaction(transaction: AnyTransaction) { - return Uint8Array.from(transaction.serialize({ verifySignatures: false })) + return transaction.serialize({ verifySignatures: false }) } private getAccount( From 04a1c904106847da29ca9727a9848889468561b5 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 7 Nov 2024 11:47:41 -0300 Subject: [PATCH 06/34] fix: formating issue --- packages/siwe/src/mapToSIWX.ts | 174 ++++++++++++++++----------------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/packages/siwe/src/mapToSIWX.ts b/packages/siwe/src/mapToSIWX.ts index a9ac5352bc..39b208925d 100644 --- a/packages/siwe/src/mapToSIWX.ts +++ b/packages/siwe/src/mapToSIWX.ts @@ -1,87 +1,87 @@ -import type { SIWXConfig, SIWXMessage, SIWXSession } from '@reown/appkit-core' -import type { SIWEConfig } from '../exports/index.js' -import { DefaultSIWX, InformalMessenger } from '@reown/appkit-siwx' -import { NetworkUtil } from '@reown/appkit-common' - -export async function mapToSIWX(siwe: SIWEConfig): Promise { - const params = await siwe.getMessageParams?.() - - const domain = params?.domain || 'Unknown Domain' - const uri = params?.uri || 'Unknown URI' - - const messenger = new InformalMessenger({ - domain, - uri, - expiration: params?.expiry, - getNonce: ({ accountAddress }) => siwe.getNonce(accountAddress) - }) - - return new DefaultSIWX({ - messenger, - - verifiers: [ - { - chainNamespace: 'eip155', - shouldVerify: session => session.data.chainId.startsWith('eip155'), - verify: async session => { - const success = await siwe.verifyMessage({ - message: session.message.toString(), - signature: session.signature - }) - - return success - } - } - ], - - storage: { - add: async session => { - const chainId = NetworkUtil.parseEvmChainId(session.data.chainId) - - if (!chainId) { - throw new Error('Invalid chain ID!') - } - - siwe.onSignIn?.({ - address: session.data.accountAddress, - chainId - }) - - return Promise.resolve() - }, - - get: async () => { - try { - const siweSession = await siwe.getSession() - if (!siweSession) { - return [] - } - - // How should we parse the session? - const session: SIWXSession = { - data: { - accountAddress: siweSession.address, - chainId: `eip155:${siweSession.chainId}` - } as SIWXMessage.Data, - message: '', - signature: '' - } - - return [session] - } catch { - return [] - } - }, - - set: async () => Promise.resolve(), - - delete: async () => { - if (await siwe.signOut()) { - return Promise.resolve() - } - - throw new Error('Failed to sign out!') - } - } - }) -} +import type { SIWXConfig, SIWXMessage, SIWXSession } from '@reown/appkit-core' +import type { SIWEConfig } from '../exports/index.js' +import { DefaultSIWX, InformalMessenger } from '@reown/appkit-siwx' +import { NetworkUtil } from '@reown/appkit-common' + +export async function mapToSIWX(siwe: SIWEConfig): Promise { + const params = await siwe.getMessageParams?.() + + const domain = params?.domain || 'Unknown Domain' + const uri = params?.uri || 'Unknown URI' + + const messenger = new InformalMessenger({ + domain, + uri, + expiration: params?.expiry, + getNonce: ({ accountAddress }) => siwe.getNonce(accountAddress) + }) + + return new DefaultSIWX({ + messenger, + + verifiers: [ + { + chainNamespace: 'eip155', + shouldVerify: session => session.data.chainId.startsWith('eip155'), + verify: async session => { + const success = await siwe.verifyMessage({ + message: session.message.toString(), + signature: session.signature + }) + + return success + } + } + ], + + storage: { + add: async session => { + const chainId = NetworkUtil.parseEvmChainId(session.data.chainId) + + if (!chainId) { + throw new Error('Invalid chain ID!') + } + + siwe.onSignIn?.({ + address: session.data.accountAddress, + chainId + }) + + return Promise.resolve() + }, + + get: async () => { + try { + const siweSession = await siwe.getSession() + if (!siweSession) { + return [] + } + + // How should we parse the session? + const session: SIWXSession = { + data: { + accountAddress: siweSession.address, + chainId: `eip155:${siweSession.chainId}` + } as SIWXMessage.Data, + message: '', + signature: '' + } + + return [session] + } catch { + return [] + } + }, + + set: async () => Promise.resolve(), + + delete: async () => { + if (await siwe.signOut()) { + return Promise.resolve() + } + + throw new Error('Failed to sign out!') + } + } + }) +} From 36598e9ea13adca1b6f87838a9dd42a31fdca45f Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 7 Nov 2024 17:08:24 -0300 Subject: [PATCH 07/34] fix: missing siwx initialization --- packages/scaffold-ui/src/modal/w3m-modal/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/scaffold-ui/src/modal/w3m-modal/index.ts b/packages/scaffold-ui/src/modal/w3m-modal/index.ts index 31d43c33ea..5c2a96cefc 100644 --- a/packages/scaffold-ui/src/modal/w3m-modal/index.ts +++ b/packages/scaffold-ui/src/modal/w3m-modal/index.ts @@ -2,6 +2,7 @@ import { AccountController, ApiController, ChainController, + ConnectionController, CoreHelperUtil, EventsController, ModalController, @@ -168,11 +169,13 @@ export class W3mModal extends LitElement { } } - private onNewAddress(caipAddress?: CaipAddress) { + private async onNewAddress(caipAddress?: CaipAddress) { const nextConnected = caipAddress ? CoreHelperUtil.getPlainAddress(caipAddress) : undefined this.caipAddress = caipAddress + await ConnectionController.initializeSWIXIfAvailable() + if (!nextConnected) { ModalController.close() } From edb0fe58a89ed0cd09556fbba3549cc45edc8d56 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 7 Nov 2024 17:28:21 -0300 Subject: [PATCH 08/34] refactor: move validation to LocalStorage to keep independent from siwe config --- packages/siwe/src/mapToSIWX.ts | 7 ++++--- packages/siwx/src/core/SIWXConfig.ts | 21 ++------------------ packages/siwx/src/core/SIWXStorage.ts | 4 ++-- packages/siwx/src/storages/LocalStorage.ts | 23 +++++++++++++++++++--- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/packages/siwe/src/mapToSIWX.ts b/packages/siwe/src/mapToSIWX.ts index 39b208925d..14afcf0004 100644 --- a/packages/siwe/src/mapToSIWX.ts +++ b/packages/siwe/src/mapToSIWX.ts @@ -50,10 +50,11 @@ export async function mapToSIWX(siwe: SIWEConfig): Promise { return Promise.resolve() }, - get: async () => { + get: async (chainId, address) => { try { const siweSession = await siwe.getSession() - if (!siweSession) { + const siweCaipNetworkId = `eip155:${siweSession?.chainId}` + if (!siweSession || siweSession.address !== address || siweCaipNetworkId !== chainId) { return [] } @@ -61,7 +62,7 @@ export async function mapToSIWX(siwe: SIWEConfig): Promise { const session: SIWXSession = { data: { accountAddress: siweSession.address, - chainId: `eip155:${siweSession.chainId}` + chainId: siweCaipNetworkId } as SIWXMessage.Data, message: '', signature: '' diff --git a/packages/siwx/src/core/SIWXConfig.ts b/packages/siwx/src/core/SIWXConfig.ts index d387fc8af1..99efc98da7 100644 --- a/packages/siwx/src/core/SIWXConfig.ts +++ b/packages/siwx/src/core/SIWXConfig.ts @@ -44,27 +44,10 @@ export abstract class SIWXConfig implements SIWXConfigInterface { } public async getSessions(chainId: CaipNetworkId, address: string): Promise { - const allSessions = await this.storage.get(chainId) - - return allSessions.filter(session => { - const isSameChain = session.data.chainId === chainId - const isSameAddress = session.data.accountAddress === address - - const startsAt = session.data.notBefore || session.data.issuedAt - if (!startsAt || Date.parse(startsAt) > Date.now()) { - return false - } - - const endsAt = session.data.expirationTime - if (endsAt && Date.now() > Date.parse(endsAt)) { - return false - } - - return isSameChain && isSameAddress - }) + return this.storage.get(chainId, address) } - public async revokeSession(chainId: string, address: string): Promise { + public async revokeSession(chainId: CaipNetworkId, address: string): Promise { return this.storage.delete(chainId, address) } diff --git a/packages/siwx/src/core/SIWXStorage.ts b/packages/siwx/src/core/SIWXStorage.ts index 3300e08ebe..c5011b480f 100644 --- a/packages/siwx/src/core/SIWXStorage.ts +++ b/packages/siwx/src/core/SIWXStorage.ts @@ -3,7 +3,7 @@ import type { SIWXSession } from '@reown/appkit-core' export interface SIWXStorage { add(session: SIWXSession): Promise - delete(chainId: string, address: string): Promise - get(chainId: CaipNetworkId): Promise + delete(chainId: CaipNetworkId, address: string): Promise + get(chainId: CaipNetworkId, address: string): Promise set(sessions: SIWXSession[]): Promise } diff --git a/packages/siwx/src/storages/LocalStorage.ts b/packages/siwx/src/storages/LocalStorage.ts index 740e2d9927..24cf6b06c9 100644 --- a/packages/siwx/src/storages/LocalStorage.ts +++ b/packages/siwx/src/storages/LocalStorage.ts @@ -23,10 +23,27 @@ export class LocalStorage implements SIWXStorage { return Promise.resolve() } - get(chainId: CaipNetworkId): Promise { - const sessions = this.getSessions().filter(session => session.data.chainId === chainId) + get(chainId: CaipNetworkId, address: string): Promise { + const allSessions = this.getSessions().filter(session => session.data.chainId === chainId) - return Promise.resolve(sessions) + const validSessions = allSessions.filter(session => { + const isSameChain = session.data.chainId === chainId + const isSameAddress = session.data.accountAddress === address + + const startsAt = session.data.notBefore || session.data.issuedAt + if (!startsAt || Date.parse(startsAt) > Date.now()) { + return false + } + + const endsAt = session.data.expirationTime + if (endsAt && Date.now() > Date.parse(endsAt)) { + return false + } + + return isSameChain && isSameAddress + }) + + return Promise.resolve(validSessions) } delete(chainId: string, address: string): Promise { From b72b68da060947ba5ca59d480b154f6dd512585a Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 7 Nov 2024 18:12:01 -0300 Subject: [PATCH 09/34] fix: fix LocalStorage validation --- packages/siwx/src/storages/LocalStorage.ts | 4 ++-- packages/siwx/tests/storages/LocalStorage.test.ts | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/siwx/src/storages/LocalStorage.ts b/packages/siwx/src/storages/LocalStorage.ts index 24cf6b06c9..3242346c9b 100644 --- a/packages/siwx/src/storages/LocalStorage.ts +++ b/packages/siwx/src/storages/LocalStorage.ts @@ -24,14 +24,14 @@ export class LocalStorage implements SIWXStorage { } get(chainId: CaipNetworkId, address: string): Promise { - const allSessions = this.getSessions().filter(session => session.data.chainId === chainId) + const allSessions = this.getSessions() const validSessions = allSessions.filter(session => { const isSameChain = session.data.chainId === chainId const isSameAddress = session.data.accountAddress === address const startsAt = session.data.notBefore || session.data.issuedAt - if (!startsAt || Date.parse(startsAt) > Date.now()) { + if (startsAt && Date.parse(startsAt) > Date.now()) { return false } diff --git a/packages/siwx/tests/storages/LocalStorage.test.ts b/packages/siwx/tests/storages/LocalStorage.test.ts index eacbd62e70..df6140a28f 100644 --- a/packages/siwx/tests/storages/LocalStorage.test.ts +++ b/packages/siwx/tests/storages/LocalStorage.test.ts @@ -28,13 +28,17 @@ describe('LocalStorage', () => { }) test('should get sessions empty', async () => { - const sessions = await storage.get('eip155:1') + const sessions = await storage.get('eip155:1', '0x1234567890abcdef') expect(sessions).toEqual([]) }) test('should get sessions', async () => { - getItem.mockImplementation(() => JSON.stringify([mockSession()])) - const sessions = await storage.get('eip155:1') + getItem.mockImplementation(() => + JSON.stringify([ + mockSession({ data: { accountAddress: '0x1234567890abcdef', chainId: 'eip155:1' } }) + ]) + ) + const sessions = await storage.get('eip155:1', '0x1234567890abcdef') expect(getItem).toHaveBeenCalledWith(key) expect(sessions).toHaveLength(1) @@ -55,7 +59,7 @@ describe('LocalStorage', () => { }) ]) ) - expect(await storage.get('eip155:1')).toHaveLength(1) + expect(await storage.get('eip155:1', '0x1234567890abcdef')).toHaveLength(1) await storage.delete('eip155:1', '0x1234567890abcdef') expect(getItem).toHaveBeenCalledWith(key) From 7bec91c76ed602e897ffc034ef28f53e33ab37f2 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Fri, 8 Nov 2024 17:01:47 -0300 Subject: [PATCH 10/34] fix: missing setClientId --- packages/appkit/src/universal-adapter/client.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/appkit/src/universal-adapter/client.ts b/packages/appkit/src/universal-adapter/client.ts index c4953b6aae..92bebe07f7 100644 --- a/packages/appkit/src/universal-adapter/client.ts +++ b/packages/appkit/src/universal-adapter/client.ts @@ -117,12 +117,14 @@ export class UniversalAdapterClient { ) { const adapter = ChainController.state.chains.get(ChainController.state.activeChain) await adapter?.connectionControllerClient?.connectWalletConnect?.(onUri) - this.setWalletConnectProvider() } else { const optionalNamespaces = WcHelpersUtil.createNamespaces(this.caipNetworks) await WalletConnectProvider.connect({ optionalNamespaces }) - this.setWalletConnectProvider() } + + this.appKit?.setClientId(await WalletConnectProvider.client.core.crypto.getClientId()) + + this.setWalletConnectProvider() }, disconnect: async () => { From 192067be0f3941c87223dcc3f9bb79e093b7b658 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Wed, 13 Nov 2024 15:12:00 -0300 Subject: [PATCH 11/34] fix: siwx on handleClose --- packages/scaffold-ui/src/modal/w3m-modal/index.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/scaffold-ui/src/modal/w3m-modal/index.ts b/packages/scaffold-ui/src/modal/w3m-modal/index.ts index fb2132d5cb..807968a7ad 100644 --- a/packages/scaffold-ui/src/modal/w3m-modal/index.ts +++ b/packages/scaffold-ui/src/modal/w3m-modal/index.ts @@ -89,23 +89,15 @@ export class W3mModal extends LitElement { } private async handleClose() { - const isSiweSignScreen = RouterController.state.view === 'ConnectingSiwe' - const isApproveSignScreen = RouterController.state.view === 'ApproveTransaction' const isUnsupportedChain = RouterController.state.view === 'UnsupportedChain' - if (this.isSiweEnabled) { - const { SIWEController } = await import('@reown/appkit-siwe') - const isUnauthenticated = SIWEController.state.status !== 'success' - if (isUnauthenticated && (isSiweSignScreen || isApproveSignScreen)) { - ModalController.shake() - } else { - ModalController.close() - } - } else if (isUnsupportedChain) { + if (isUnsupportedChain) { ModalController.shake() } else { ModalController.close() } + + return Promise.resolve() } private initializeTheming() { From b40dc5f16927965c63f272debdb228c23558c1a2 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Wed, 13 Nov 2024 16:03:52 -0300 Subject: [PATCH 12/34] fix: solana response for signMessage --- packages/adapters/solana/src/client.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/adapters/solana/src/client.ts b/packages/adapters/solana/src/client.ts index 5bdae738b7..623c2081d9 100644 --- a/packages/adapters/solana/src/client.ts +++ b/packages/adapters/solana/src/client.ts @@ -32,6 +32,7 @@ import type { WalletStandardProvider } from './providers/WalletStandardProvider. import { handleMobileWalletRedirection } from './utils/handleMobileWalletRedirection.js' import type { BaseWalletAdapter } from '@solana/wallet-adapter-base' import { WalletConnectProvider } from './providers/WalletConnectProvider.js' +import bs58 from 'bs58' export interface AdapterOptions { connectionSettings?: Commitment | ConnectionConfig @@ -175,7 +176,7 @@ export class SolanaAdapter extends AdapterBlueprint { ) return { - signature: new TextDecoder().decode(signature) + signature: bs58.encode(signature) } } From 92326a556307ccee23547ee7648e69925a10af83 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Wed, 13 Nov 2024 17:06:46 -0300 Subject: [PATCH 13/34] fix: correct solana signature for universal adapter --- .../appkit/src/universal-adapter/client.ts | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/packages/appkit/src/universal-adapter/client.ts b/packages/appkit/src/universal-adapter/client.ts index cc84396965..0d622510d8 100644 --- a/packages/appkit/src/universal-adapter/client.ts +++ b/packages/appkit/src/universal-adapter/client.ts @@ -1,6 +1,9 @@ import type UniversalProvider from '@walletconnect/universal-provider' import { AdapterBlueprint } from '../adapters/ChainAdapterBlueprint.js' import { WcHelpersUtil } from '../utils/index.js' +import { ChainController } from '@reown/appkit-core' +import bs58 from 'bs58' +import { ConstantsUtil } from '@reown/appkit-common' export class UniversalAdapter extends AdapterBlueprint { public async connectWalletConnect(onUri: (uri: string) => void) { @@ -60,12 +63,32 @@ export class UniversalAdapter extends AdapterBlueprint { throw new Error('UniversalAdapter:signMessage - provider is undefined') } - const signature = await provider.request({ - method: 'personal_sign', - params: [message, address] - }) + let signature = '' + + if (ChainController.state.activeCaipNetwork?.chainNamespace === ConstantsUtil.CHAIN.SOLANA) { + const response = await provider.request( + { + method: 'solana_signMessage', + params: { + message: bs58.encode(new TextEncoder().encode(message)), + pubkey: address + } + }, + ChainController.state.activeCaipNetwork?.caipNetworkId + ) + + signature = (response as { signature: string }).signature + } else { + signature = await provider.request( + { + method: 'personal_sign', + params: [message, address] + }, + ChainController.state.activeCaipNetwork?.caipNetworkId + ) + } - return { signature: signature as `0x${string}` } + return { signature } } // -- Transaction methods --------------------------------------------------- From 5791611ecc30f6fc8566569b32c1e2e5c2c34eaa Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Wed, 13 Nov 2024 17:07:47 -0300 Subject: [PATCH 14/34] feat: handle siwx error --- packages/core/src/controllers/ConnectionController.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/core/src/controllers/ConnectionController.ts b/packages/core/src/controllers/ConnectionController.ts index be565be3e0..fbe6ffbf9d 100644 --- a/packages/core/src/controllers/ConnectionController.ts +++ b/packages/core/src/controllers/ConnectionController.ts @@ -17,6 +17,7 @@ import { ConnectorController } from './ConnectorController.js' import { EventsController } from './EventsController.js' import type { CaipNetwork, ChainNamespace } from '@reown/appkit-common' import { OptionsController } from './OptionsController.js' +import { SnackController } from './SnackController.js' // -- Types --------------------------------------------- // export interface ConnectExternalOptions { @@ -322,10 +323,9 @@ export const ConnectionController = { } catch (error: unknown) { // eslint-disable-next-line no-console console.error('Failed to initialize SIWX', error) - ModalController.setLoading(true) - await client?.disconnect().finally(() => { - ModalController.setLoading(false) - }) + await client?.disconnect() + await ModalController.open({ view: 'Connect' }) + SnackController.showError('It was not possible to verify the message signature') } } } From adce84e03c7eba5d8c478c0952c942a5bf8c5c4a Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Wed, 13 Nov 2024 17:12:15 -0300 Subject: [PATCH 15/34] refactor: change siwe condition to siwx --- .../scaffold-ui/src/views/w3m-connecting-wc-view/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/scaffold-ui/src/views/w3m-connecting-wc-view/index.ts b/packages/scaffold-ui/src/views/w3m-connecting-wc-view/index.ts index 260fd7128a..cdc08aa4f8 100644 --- a/packages/scaffold-ui/src/views/w3m-connecting-wc-view/index.ts +++ b/packages/scaffold-ui/src/views/w3m-connecting-wc-view/index.ts @@ -28,7 +28,7 @@ export class W3mConnectingWcView extends LitElement { @state() private platforms: Platform[] = [] - @state() private isSiweEnabled = OptionsController.state.isSiweEnabled + @state() private isSiwxEnabled = Boolean(OptionsController.state.siwx) public constructor() { super() @@ -71,7 +71,7 @@ export class W3mConnectingWcView extends LitElement { if (retry || CoreHelperUtil.isPairingExpired(wcPairingExpiry) || status === 'connecting') { await ConnectionController.connectWalletConnect() this.finalizeConnection() - if (!this.isSiweEnabled) { + if (!this.isSiwxEnabled) { ModalController.close() } } From 1f216f1f0fea2d4ec9d6e17118571b6d51e669c1 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Wed, 13 Nov 2024 18:30:27 -0300 Subject: [PATCH 16/34] feat: add SIWXUtils functions and enable one click auth --- packages/appkit/src/client.ts | 138 ++++++++---------- packages/core/exports/index.ts | 3 +- .../src/controllers/ConnectionController.ts | 60 -------- packages/core/src/utils/SIWXUtil.ts | 87 +++++++++++ .../scaffold-ui/src/modal/w3m-modal/index.ts | 9 +- .../src/partials/w3m-header/index.ts | 21 +-- 6 files changed, 156 insertions(+), 162 deletions(-) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index c33da86012..2dab1e3e68 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -19,7 +19,9 @@ import { type SendTransactionArgs, type EstimateGasTransactionArgs, type AccountControllerState, - type AdapterNetworkState + type AdapterNetworkState, + type SIWXSession, + SIWXUtil } from '@reown/appkit-core' import { AccountController, @@ -651,11 +653,15 @@ export class AppKit { if (evmAdapter) { if (options.siweConfig) { if (options.siwx) { - throw new Error('Cannot set both siweConfig and siwx') + throw new Error('Cannot set both `siweConfig` and `siwx` options') } - const { mapToSIWX } = await import('@reown/appkit-siwe') - const siwx = await mapToSIWX(options.siweConfig) + const siwe = await import('@reown/appkit-siwe') + if (typeof siwe.mapToSIWX !== 'function') { + throw new Error('Please update the `@reown/appkit-siwe` package to the latest version') + } + + const siwx = await siwe.mapToSIWX(options.siweConfig) OptionsController.setSIWX(siwx) } } @@ -707,76 +713,59 @@ export class AppKit { onUri(uri) }) - if (this.options.siweConfig) { - const siweParams = await this.options.siweConfig?.getMessageParams?.() - const isSiweEnabled = this.options.siweConfig?.options?.enabled - const isProviderSupported = typeof this.universalProvider?.authenticate === 'function' - const isSiweParamsValid = siweParams && Object.keys(siweParams || {}).length > 0 - const clientId = await this.universalProvider?.client?.core?.crypto?.getClientId() - if (clientId) { - this.setClientId(clientId) - if ( - this.options.siweConfig && - isSiweEnabled && - siweParams && - isProviderSupported && - isSiweParamsValid && - ChainController.state.activeChain === ConstantsUtil.CHAIN.EVM - ) { - const { SIWEController, getDidChainId, getDidAddress } = await import( - '@reown/appkit-siwe' - ) - - const chains = this.caipNetworks - ?.filter(network => network.chainNamespace === ConstantsUtil.CHAIN.EVM) - .map(chain => chain.caipNetworkId) as string[] - - siweParams.chains = this.caipNetworks - ?.filter(network => network.chainNamespace === ConstantsUtil.CHAIN.EVM) - .map(chain => chain.id) as number[] - - const result = await this.universalProvider?.authenticate({ - nonce: await this.options.siweConfig?.getNonce?.(), - methods: [...OPTIONAL_METHODS], - ...siweParams, - chains + this.setClientId( + (await this.universalProvider?.client?.core?.crypto?.getClientId()) || null + ) + + const siwx = SIWXUtil.getSIWX() + + if (siwx) { + // Ignores chainId and account address to get other message data + const siwxMessage = await siwx.createMessage({ + chainId: '', + accountAddress: '' + }) + + const result = await this.universalProvider?.authenticate({ + nonce: siwxMessage.nonce, + domain: siwxMessage.domain, + uri: siwxMessage.uri, + exp: siwxMessage.expirationTime, + iat: siwxMessage.issuedAt, + nbf: siwxMessage.notBefore, + requestId: siwxMessage.requestId, + version: siwxMessage.version, + resources: siwxMessage.resources, + statement: siwxMessage.statement, + + methods: OPTIONAL_METHODS, + chains: this.caipNetworks?.map(network => network.caipNetworkId) || [] + }) + + if (result?.auths?.length) { + const sessions = result.auths.map(cacao => { + const message = this.universalProvider?.client.formatAuthMessage({ + request: cacao.p, + iss: cacao.p.iss }) - // Auths is an array of signed CACAO objects https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-74.md - const signedCacao = result?.auths?.[0] - - if (signedCacao) { - const { p, s } = signedCacao - const cacaoChainId = getDidChainId(p.iss) - const address = getDidAddress(p.iss) - if (address && cacaoChainId) { - SIWEController.setSession({ - address, - chainId: parseInt(cacaoChainId, 10) - }) - } - - try { - // Kicks off verifyMessage and populates external states - const message = this.universalProvider?.client.formatAuthMessage({ - request: p, - iss: p.iss - }) - - await SIWEController.verifyMessage({ - message: message as string, - signature: s.s, - cacao: signedCacao - }) - } catch (error) { - // eslint-disable-next-line no-console - console.error('Error verifying message', error) - // eslint-disable-next-line no-console - await this.universalProvider?.disconnect().catch(console.error) - // eslint-disable-next-line no-console - await SIWEController.signOut().catch(console.error) - throw error - } + + return { + data: siwxMessage, + message, + signature: cacao.s.s, + cacao } + }) + + try { + await siwx.setSessions(sessions) + this.close() + } catch (error) { + // eslint-disable-next-line no-console + console.error('Error verifying message', error) + // eslint-disable-next-line no-console + await this.universalProvider?.disconnect().catch(console.error) + throw error } } } else { @@ -832,11 +821,6 @@ export class AppKit { ChainController.state.activeChain as ChainNamespace ) - if (this.options.siweConfig?.options?.signOutOnDisconnect) { - const { SIWEController } = await import('@reown/appkit-siwe') - await SIWEController.signOut() - } - const providerType = ProviderUtil.state.providerIds[ChainController.state.activeChain as ChainNamespace] diff --git a/packages/core/exports/index.ts b/packages/core/exports/index.ts index 11b0dcb949..5130bfec1d 100644 --- a/packages/core/exports/index.ts +++ b/packages/core/exports/index.ts @@ -74,6 +74,7 @@ export { CoreHelperUtil } from '../src/utils/CoreHelperUtil.js' export { StorageUtil } from '../src/utils/StorageUtil.js' export { RouterUtil } from '../src/utils/RouterUtil.js' export { OptionsUtil } from '../src/utils/OptionsUtil.js' +export { SIWXUtil } from '../src/utils/SIWXUtil.js' export type * from '../src/utils/TypeUtil.js' -export type * from '../src/utils/SIWXUtil.js' +export type * from '../src/utils/TypeUtil.js' diff --git a/packages/core/src/controllers/ConnectionController.ts b/packages/core/src/controllers/ConnectionController.ts index fbe6ffbf9d..2b7a1fb738 100644 --- a/packages/core/src/controllers/ConnectionController.ts +++ b/packages/core/src/controllers/ConnectionController.ts @@ -267,65 +267,5 @@ export const ConnectionController = { } catch (error) { throw new Error('Failed to disconnect') } - }, - - /** - * @experimental - This is an experimental feature and may be subject to change. - * Initializes SIWX if available. - * This is not yet considering One Click Auth. - */ - async initializeSWIXIfAvailable() { - const siwx = OptionsController.state.siwx - const address = CoreHelperUtil.getPlainAddress(ChainController.getActiveCaipAddress()) - const network = ChainController.getActiveCaipNetwork() - - if (!(siwx && address && network)) { - return - } - - if (OptionsController.state.isSiweEnabled) { - console.warn('SIWE is enabled skipping experimental SIWX initialization') - - return - } - - const client = this._getClient() - - try { - const sessions = await siwx.getSessions(network.caipNetworkId, address) - if (sessions.length) { - return - } - - await ModalController.open({ - view: - StorageUtil.getConnectedConnector() === 'ID_AUTH' - ? 'ApproveTransaction' - : 'SIWXSignMessage' - }) - - const siwxMessage = await siwx.createMessage({ - chainId: network.caipNetworkId, - accountAddress: address - }) - - const message = siwxMessage.toString() - - const signature = await client?.signMessage(message) - - await siwx.addSession({ - data: siwxMessage, - message, - signature: signature as `0x${string}` - }) - - ModalController.close() - } catch (error: unknown) { - // eslint-disable-next-line no-console - console.error('Failed to initialize SIWX', error) - await client?.disconnect() - await ModalController.open({ view: 'Connect' }) - SnackController.showError('It was not possible to verify the message signature') - } } } diff --git a/packages/core/src/utils/SIWXUtil.ts b/packages/core/src/utils/SIWXUtil.ts index cce4c94093..a49d9ddf16 100644 --- a/packages/core/src/utils/SIWXUtil.ts +++ b/packages/core/src/utils/SIWXUtil.ts @@ -1,4 +1,91 @@ import type { CaipNetworkId } from '@reown/appkit-common' +import { OptionsController } from '../controllers/OptionsController.js' +import { CoreHelperUtil } from './CoreHelperUtil.js' +import { ChainController } from '../controllers/ChainController.js' +import { ConnectionController } from '../controllers/ConnectionController.js' +import { ModalController } from '../controllers/ModalController.js' +import { StorageUtil } from './StorageUtil.js' +import { SnackController } from '../controllers/SnackController.js' +import { RouterController } from '../controllers/RouterController.js' + +export const SIWXUtil = { + getSIWX() { + return OptionsController.state.siwx + }, + async initializeIfEnabled() { + const siwx = OptionsController.state.siwx + const address = CoreHelperUtil.getPlainAddress(ChainController.getActiveCaipAddress()) + const network = ChainController.getActiveCaipNetwork() + + if (!(siwx && address && network)) { + return + } + + const client = ConnectionController._getClient() + + try { + const sessions = await siwx.getSessions(network.caipNetworkId, address) + if (sessions.length) { + return + } + + await ModalController.open({ + view: + StorageUtil.getConnectedConnector() === 'ID_AUTH' + ? 'ApproveTransaction' + : 'SIWXSignMessage' + }) + + const siwxMessage = await siwx.createMessage({ + chainId: network.caipNetworkId, + accountAddress: address + }) + + const message = siwxMessage.toString() + + const signature = await client?.signMessage(message) + + await siwx.addSession({ + data: siwxMessage, + message, + signature: signature as `0x${string}` + }) + + ModalController.close() + } catch (error: unknown) { + // eslint-disable-next-line no-console + console.error('Failed to initialize SIWX', error) + await client?.disconnect() + await ModalController.open({ view: 'Connect' }) + SnackController.showError('It was not possible to verify the message signature') + } + }, + async getSessions() { + const siwx = OptionsController.state.siwx + const address = CoreHelperUtil.getPlainAddress(ChainController.getActiveCaipAddress()) + const network = ChainController.getActiveCaipNetwork() + + if (!(siwx && address && network)) { + return [] + } + + return siwx.getSessions(network.caipNetworkId, address) + }, + async isSIWXCloseDisabled() { + const siwx = this.getSIWX() + + if (siwx) { + const isApproveSignScreen = RouterController.state.view === 'ApproveTransaction' + const isSiwxSignMessage = RouterController.state.view === 'SIWXSignMessage' + + if (isApproveSignScreen || isSiwxSignMessage) { + return (await this.getSessions()).length > 1 + } + } + + return false + } +} /** * @experimental - This is an experimental feature and it is not production ready diff --git a/packages/scaffold-ui/src/modal/w3m-modal/index.ts b/packages/scaffold-ui/src/modal/w3m-modal/index.ts index 807968a7ad..d1ef1b569a 100644 --- a/packages/scaffold-ui/src/modal/w3m-modal/index.ts +++ b/packages/scaffold-ui/src/modal/w3m-modal/index.ts @@ -2,11 +2,11 @@ import { AccountController, ApiController, ChainController, - ConnectionController, CoreHelperUtil, EventsController, ModalController, RouterController, + SIWXUtil, SnackController, ThemeController } from '@reown/appkit-core' @@ -90,14 +90,11 @@ export class W3mModal extends LitElement { private async handleClose() { const isUnsupportedChain = RouterController.state.view === 'UnsupportedChain' - - if (isUnsupportedChain) { + if (isUnsupportedChain || (await SIWXUtil.isSIWXCloseDisabled())) { ModalController.shake() } else { ModalController.close() } - - return Promise.resolve() } private initializeTheming() { @@ -180,7 +177,7 @@ export class W3mModal extends LitElement { this.caipAddress = caipAddress - await ConnectionController.initializeSWIXIfAvailable() + await SIWXUtil.initializeIfEnabled() if (!nextConnected) { ModalController.close() diff --git a/packages/scaffold-ui/src/partials/w3m-header/index.ts b/packages/scaffold-ui/src/partials/w3m-header/index.ts index 9e5d5c5558..45b9657bd8 100644 --- a/packages/scaffold-ui/src/partials/w3m-header/index.ts +++ b/packages/scaffold-ui/src/partials/w3m-header/index.ts @@ -7,7 +7,8 @@ import { EventsController, ModalController, OptionsController, - RouterController + RouterController, + SIWXUtil } from '@reown/appkit-core' import { customElement } from '@reown/appkit-ui' import { LitElement, html } from 'lit' @@ -155,17 +156,7 @@ export class W3mHeader extends LitElement { private async onClose() { const isUnsupportedChain = RouterController.state.view === 'UnsupportedChain' - if (this.isSiweEnabled) { - const { SIWEController } = await import('@reown/appkit-siwe') - const isApproveSignScreen = RouterController.state.view === 'ApproveTransaction' - const isUnauthenticated = SIWEController.state.status !== 'success' - - if (isUnauthenticated && isApproveSignScreen) { - RouterController.popTransactionStack(true) - } else { - ModalController.close() - } - } else if (isUnsupportedChain) { + if (isUnsupportedChain || (await SIWXUtil.isSIWXCloseDisabled())) { ModalController.shake() } else { ModalController.close() @@ -190,12 +181,6 @@ export class W3mHeader extends LitElement { } private closeButtonTemplate() { - const isSiweSignScreen = RouterController.state.view === 'ConnectingSiwe' - - if (this.isSiweEnabled && isSiweSignScreen) { - return html`
` - } - return html` Date: Wed, 13 Nov 2024 18:38:06 -0300 Subject: [PATCH 17/34] fix: siwx types export --- packages/appkit/src/client.ts | 6 +++--- packages/core/exports/index.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index 2dab1e3e68..d2803d5e50 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -719,14 +719,14 @@ export class AppKit { const siwx = SIWXUtil.getSIWX() - if (siwx) { + if (siwx && this.universalProvider) { // Ignores chainId and account address to get other message data const siwxMessage = await siwx.createMessage({ chainId: '', accountAddress: '' }) - const result = await this.universalProvider?.authenticate({ + const result = await this.universalProvider.authenticate({ nonce: siwxMessage.nonce, domain: siwxMessage.domain, uri: siwxMessage.uri, @@ -751,7 +751,7 @@ export class AppKit { return { data: siwxMessage, - message, + message: message || '', signature: cacao.s.s, cacao } diff --git a/packages/core/exports/index.ts b/packages/core/exports/index.ts index 5130bfec1d..8d6f7ae38c 100644 --- a/packages/core/exports/index.ts +++ b/packages/core/exports/index.ts @@ -77,4 +77,4 @@ export { OptionsUtil } from '../src/utils/OptionsUtil.js' export { SIWXUtil } from '../src/utils/SIWXUtil.js' export type * from '../src/utils/TypeUtil.js' -export type * from '../src/utils/TypeUtil.js' +export type * from '../src/utils/SIWXUtil.js' From dddf0bda8f52f49d98d03de09d3405aafc5e2236 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Wed, 13 Nov 2024 19:06:27 -0300 Subject: [PATCH 18/34] fix: cacao to siwx data parsing --- packages/appkit/src/client.ts | 17 +++++++++++++++-- packages/siwe/src/mapToSIWX.ts | 9 +-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index d2803d5e50..710fd7df2c 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -719,7 +719,7 @@ export class AppKit { const siwx = SIWXUtil.getSIWX() - if (siwx && this.universalProvider) { + if (siwx && this.universalProvider && this.chainNamespaces.length === 1) { // Ignores chainId and account address to get other message data const siwxMessage = await siwx.createMessage({ chainId: '', @@ -750,7 +750,20 @@ export class AppKit { }) return { - data: siwxMessage, + data: { + accountAddress: cacao.p.iss.split(':').slice(-1).join(''), + chainId: cacao.p.iss.split(':').slice(2, 3).join(''), + uri: cacao.p.aud, + domain: cacao.p.domain, + nonce: cacao.p.nonce, + version: cacao.p.version || siwxMessage.version, + expirationTime: cacao.p.exp, + statement: cacao.p.statement, + issuedAt: cacao.p.iat, + notBefore: cacao.p.nbf, + requestId: cacao.p.requestId, + resources: cacao.p.resources + }, message: message || '', signature: cacao.s.s, cacao diff --git a/packages/siwe/src/mapToSIWX.ts b/packages/siwe/src/mapToSIWX.ts index 14afcf0004..cda8de136f 100644 --- a/packages/siwe/src/mapToSIWX.ts +++ b/packages/siwe/src/mapToSIWX.ts @@ -23,14 +23,7 @@ export async function mapToSIWX(siwe: SIWEConfig): Promise { { chainNamespace: 'eip155', shouldVerify: session => session.data.chainId.startsWith('eip155'), - verify: async session => { - const success = await siwe.verifyMessage({ - message: session.message.toString(), - signature: session.signature - }) - - return success - } + verify: siwe.verifyMessage.bind(siwe) } ], From 28e21c5cb2e5beebcc2ed4c112ecefa7f7d98eca Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Wed, 13 Nov 2024 19:10:35 -0300 Subject: [PATCH 19/34] fix: remove unused import --- packages/core/src/controllers/ConnectionController.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core/src/controllers/ConnectionController.ts b/packages/core/src/controllers/ConnectionController.ts index 2b7a1fb738..79cee5c83f 100644 --- a/packages/core/src/controllers/ConnectionController.ts +++ b/packages/core/src/controllers/ConnectionController.ts @@ -17,7 +17,6 @@ import { ConnectorController } from './ConnectorController.js' import { EventsController } from './EventsController.js' import type { CaipNetwork, ChainNamespace } from '@reown/appkit-common' import { OptionsController } from './OptionsController.js' -import { SnackController } from './SnackController.js' // -- Types --------------------------------------------- // export interface ConnectExternalOptions { From d8335888d7a868967133a7ee82507b5c8db58e9c Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 14 Nov 2024 12:19:52 -0300 Subject: [PATCH 20/34] refactor: move universal provider authentication to SIWXUtils --- packages/appkit/src/client.ts | 73 ++++--------------------- packages/core/src/utils/SIWXUtil.ts | 83 +++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 64 deletions(-) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index afb7671472..02f5f37240 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -20,7 +20,6 @@ import { type EstimateGasTransactionArgs, type AccountControllerState, type AdapterNetworkState, - type SIWXSession, SIWXUtil } from '@reown/appkit-core' import { @@ -714,70 +713,16 @@ export class AppKit { (await this.universalProvider?.client?.core?.crypto?.getClientId()) || null ) - const siwx = SIWXUtil.getSIWX() + const isOneClickAuthenticated = + this.universalProvider && + (await SIWXUtil.universalProviderAuthenticate({ + universalProvider: this.universalProvider, + chains: this.caipNetworks?.map(network => network.caipNetworkId) || [], + methods: OPTIONAL_METHODS + })) - if (siwx && this.universalProvider && this.chainNamespaces.length === 1) { - // Ignores chainId and account address to get other message data - const siwxMessage = await siwx.createMessage({ - chainId: '', - accountAddress: '' - }) - - const result = await this.universalProvider.authenticate({ - nonce: siwxMessage.nonce, - domain: siwxMessage.domain, - uri: siwxMessage.uri, - exp: siwxMessage.expirationTime, - iat: siwxMessage.issuedAt, - nbf: siwxMessage.notBefore, - requestId: siwxMessage.requestId, - version: siwxMessage.version, - resources: siwxMessage.resources, - statement: siwxMessage.statement, - - methods: OPTIONAL_METHODS, - chains: this.caipNetworks?.map(network => network.caipNetworkId) || [] - }) - - if (result?.auths?.length) { - const sessions = result.auths.map(cacao => { - const message = this.universalProvider?.client.formatAuthMessage({ - request: cacao.p, - iss: cacao.p.iss - }) - - return { - data: { - accountAddress: cacao.p.iss.split(':').slice(-1).join(''), - chainId: cacao.p.iss.split(':').slice(2, 3).join(''), - uri: cacao.p.aud, - domain: cacao.p.domain, - nonce: cacao.p.nonce, - version: cacao.p.version || siwxMessage.version, - expirationTime: cacao.p.exp, - statement: cacao.p.statement, - issuedAt: cacao.p.iat, - notBefore: cacao.p.nbf, - requestId: cacao.p.requestId, - resources: cacao.p.resources - }, - message: message || '', - signature: cacao.s.s, - cacao - } - }) - - try { - await siwx.setSessions(sessions) - this.close() - } catch (error) { - // eslint-disable-next-line no-console - console.error('Error verifying message', error) - // eslint-disable-next-line no-console - await this.universalProvider?.disconnect().catch(console.error) - throw error - } - } + if (isOneClickAuthenticated) { + this.close() } else { await adapter?.connectWalletConnect(onUri, this.getCaipNetwork()?.id) } diff --git a/packages/core/src/utils/SIWXUtil.ts b/packages/core/src/utils/SIWXUtil.ts index a49d9ddf16..69d18e93f9 100644 --- a/packages/core/src/utils/SIWXUtil.ts +++ b/packages/core/src/utils/SIWXUtil.ts @@ -7,6 +7,7 @@ import { ModalController } from '../controllers/ModalController.js' import { StorageUtil } from './StorageUtil.js' import { SnackController } from '../controllers/SnackController.js' import { RouterController } from '../controllers/RouterController.js' +import UniversalProvider from '@walletconnect/universal-provider' export const SIWXUtil = { getSIWX() { @@ -83,6 +84,88 @@ export const SIWXUtil = { } } + return false + }, + async universalProviderAuthenticate({ + universalProvider, + chains, + methods + }: { + universalProvider: UniversalProvider + chains: CaipNetworkId[] + methods: string[] + }) { + const siwx = SIWXUtil.getSIWX() + + const namespaces = chains.map(chain => chain.split(':')[0]) + + if (!siwx || namespaces.length !== 1) { + return false + } + + // Ignores chainId and account address to get other message data + const siwxMessage = await siwx.createMessage({ + chainId: '', + accountAddress: '' + }) + + const result = await universalProvider.authenticate({ + nonce: siwxMessage.nonce, + domain: siwxMessage.domain, + uri: siwxMessage.uri, + exp: siwxMessage.expirationTime, + iat: siwxMessage.issuedAt, + nbf: siwxMessage.notBefore, + requestId: siwxMessage.requestId, + version: siwxMessage.version, + resources: siwxMessage.resources, + statement: siwxMessage.statement, + + methods, + chains + }) + + if (result?.auths?.length) { + const sessions = result.auths.map(cacao => { + const message = universalProvider.client.formatAuthMessage({ + request: cacao.p, + iss: cacao.p.iss + }) + + return { + data: { + accountAddress: cacao.p.iss.split(':').slice(-1).join(''), + chainId: cacao.p.iss.split(':').slice(2, 3).join(''), + uri: cacao.p.aud, + domain: cacao.p.domain, + nonce: cacao.p.nonce, + version: cacao.p.version || siwxMessage.version, + expirationTime: cacao.p.exp, + statement: cacao.p.statement, + issuedAt: cacao.p.iat, + notBefore: cacao.p.nbf, + requestId: cacao.p.requestId, + resources: cacao.p.resources + }, + message, + signature: cacao.s.s, + cacao + } + }) + + try { + await siwx.setSessions(sessions) + + return true + } catch (error) { + // eslint-disable-next-line no-console + console.error('Error verifying message', error) + // eslint-disable-next-line no-console + await universalProvider.disconnect().catch(console.error) + throw error + } + } + return false } } From 61431ca223d52a5c7f4869ff8554a314023fd2f0 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 14 Nov 2024 14:23:20 -0300 Subject: [PATCH 21/34] refactor: remove siwx package from siwe --- packages/appkit/src/client.ts | 3 +- packages/core/src/utils/SIWXUtil.ts | 15 ++- packages/siwe/package.json | 11 +-- packages/siwe/src/mapToSIWX.ts | 143 ++++++++++++++++------------ pnpm-lock.yaml | 3 - 5 files changed, 95 insertions(+), 80 deletions(-) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index 02f5f37240..763a6be01f 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -659,8 +659,7 @@ export class AppKit { throw new Error('Please update the `@reown/appkit-siwe` package to the latest version') } - const siwx = await siwe.mapToSIWX(options.siweConfig) - OptionsController.setSIWX(siwx) + OptionsController.setSIWX(siwe.mapToSIWX(options.siweConfig)) } } } diff --git a/packages/core/src/utils/SIWXUtil.ts b/packages/core/src/utils/SIWXUtil.ts index 69d18e93f9..adcb028ebd 100644 --- a/packages/core/src/utils/SIWXUtil.ts +++ b/packages/core/src/utils/SIWXUtil.ts @@ -56,7 +56,8 @@ export const SIWXUtil = { } catch (error: unknown) { // eslint-disable-next-line no-console console.error('Failed to initialize SIWX', error) - await client?.disconnect() + // eslint-disable-next-line no-console + await client?.disconnect().catch(console.error) await ModalController.open({ view: 'Connect' }) SnackController.showError('It was not possible to verify the message signature') } @@ -97,9 +98,9 @@ export const SIWXUtil = { }) { const siwx = SIWXUtil.getSIWX() - const namespaces = chains.map(chain => chain.split(':')[0]) + const namespaces = new Set(chains.map(chain => chain.split(':')[0])) - if (!siwx || namespaces.length !== 1) { + if (!siwx || namespaces.size !== 1) { return false } @@ -135,7 +136,7 @@ export const SIWXUtil = { return { data: { accountAddress: cacao.p.iss.split(':').slice(-1).join(''), - chainId: cacao.p.iss.split(':').slice(2, 3).join(''), + chainId: cacao.p.iss.split(':').slice(2, 4).join(':'), uri: cacao.p.aud, domain: cacao.p.domain, nonce: cacao.p.nonce, @@ -155,18 +156,16 @@ export const SIWXUtil = { try { await siwx.setSessions(sessions) - - return true } catch (error) { // eslint-disable-next-line no-console - console.error('Error verifying message', error) + console.error('SIWX:universalProviderAuth - failed to set sessions', error) // eslint-disable-next-line no-console await universalProvider.disconnect().catch(console.error) throw error } } - return false + return true } } diff --git a/packages/siwe/package.json b/packages/siwe/package.json index a627d7dc51..fe7eea9941 100644 --- a/packages/siwe/package.json +++ b/packages/siwe/package.json @@ -16,15 +16,14 @@ "lint": "eslint . --ext .js,.jsx,.ts,.tsx" }, "dependencies": { - "@walletconnect/utils": "2.17.0", + "@reown/appkit-common": "workspace:*", "@reown/appkit-core": "workspace:*", "@reown/appkit-ui": "workspace:*", - "@reown/appkit-common": "workspace:*", - "@reown/appkit-wallet": "workspace:*", "@reown/appkit-utils": "workspace:*", - "@reown/appkit-siwx": "workspace:*", - "valtio": "1.11.2", - "lit": "3.1.0" + "@reown/appkit-wallet": "workspace:*", + "@walletconnect/utils": "2.17.0", + "lit": "3.1.0", + "valtio": "1.11.2" }, "keywords": [ "web3", diff --git a/packages/siwe/src/mapToSIWX.ts b/packages/siwe/src/mapToSIWX.ts index cda8de136f..1b528b3025 100644 --- a/packages/siwe/src/mapToSIWX.ts +++ b/packages/siwe/src/mapToSIWX.ts @@ -1,81 +1,102 @@ import type { SIWXConfig, SIWXMessage, SIWXSession } from '@reown/appkit-core' import type { SIWEConfig } from '../exports/index.js' -import { DefaultSIWX, InformalMessenger } from '@reown/appkit-siwx' -import { NetworkUtil } from '@reown/appkit-common' - -export async function mapToSIWX(siwe: SIWEConfig): Promise { - const params = await siwe.getMessageParams?.() - - const domain = params?.domain || 'Unknown Domain' - const uri = params?.uri || 'Unknown URI' - - const messenger = new InformalMessenger({ - domain, - uri, - expiration: params?.expiry, - getNonce: ({ accountAddress }) => siwe.getNonce(accountAddress) - }) - - return new DefaultSIWX({ - messenger, - - verifiers: [ - { - chainNamespace: 'eip155', - shouldVerify: session => session.data.chainId.startsWith('eip155'), - verify: siwe.verifyMessage.bind(siwe) +import { NetworkUtil, type CaipNetworkId } from '@reown/appkit-common' + +export function mapToSIWX(siwe: SIWEConfig): SIWXConfig { + return { + async createMessage(input) { + const params = await siwe.getMessageParams?.() + + if (!params) { + throw new Error('Failed to get message params!') } - ], - storage: { - add: async session => { - const chainId = NetworkUtil.parseEvmChainId(session.data.chainId) + const nonce = await siwe.getNonce(input.accountAddress) + const issuedAt = params.iat || new Date().toISOString() + const version = '1' - if (!chainId) { - throw new Error('Invalid chain ID!') - } + return { + nonce, + version, + requestId: params.requestId, + accountAddress: input.accountAddress, + chainId: input.chainId, + domain: params.domain, + uri: params.uri, + notBefore: params.nbf, + resources: params.resources, + statement: params.statement, + expirationTime: params.exp, + issuedAt, + toString: () => + siwe.createMessage({ + ...params, + chainId: NetworkUtil.caipNetworkIdToNumber(input.chainId as CaipNetworkId) || 1, + address: `did:pkh:${input.chainId}:${input.accountAddress}`, + nonce, + version, + iat: issuedAt + }) + } + }, + + async addSession(session) { + const chainId = NetworkUtil.parseEvmChainId(session.data.chainId) + if (!chainId) { + throw new Error('Invalid chain ID!') + } + + if (await siwe.verifyMessage?.(session)) { siwe.onSignIn?.({ address: session.data.accountAddress, chainId }) return Promise.resolve() - }, - - get: async (chainId, address) => { - try { - const siweSession = await siwe.getSession() - const siweCaipNetworkId = `eip155:${siweSession?.chainId}` - if (!siweSession || siweSession.address !== address || siweCaipNetworkId !== chainId) { - return [] - } - - // How should we parse the session? - const session: SIWXSession = { - data: { - accountAddress: siweSession.address, - chainId: siweCaipNetworkId - } as SIWXMessage.Data, - message: '', - signature: '' - } - - return [session] - } catch { + } + + throw new Error('Failed to add session') + }, + + async revokeSession(_chainId, _address) { + if (await siwe.signOut()) { + return Promise.resolve() + } + + throw new Error('Failed to sign out') + }, + + async setSessions(sessions) { + const addingSessions = sessions.map(session => this.addSession(session)) + await Promise.all(addingSessions) + }, + + async getSessions(chainId, address) { + try { + const siweSession = await siwe.getSession() + + const siweCaipNetworkId = `eip155:${siweSession?.chainId}` + if (!siweSession || siweSession.address !== address || siweCaipNetworkId !== chainId) { return [] } - }, - set: async () => Promise.resolve(), - - delete: async () => { - if (await siwe.signOut()) { - return Promise.resolve() + const session: SIWXSession = { + data: { + accountAddress: siweSession.address, + chainId: siweCaipNetworkId + } as SIWXMessage.Data, + message: '', + signature: '' } - throw new Error('Failed to sign out!') + return [session] + } catch (error) { + // eslint-disable-next-line no-console + console.error('SIWE:getSessions - error:', error) + + return [] } } - }) + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f3e9308647..8b9d69edd7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1495,9 +1495,6 @@ importers: '@reown/appkit-core': specifier: workspace:* version: link:../core - '@reown/appkit-siwx': - specifier: workspace:* - version: link:../siwx '@reown/appkit-ui': specifier: workspace:* version: link:../ui From 499562d40c7a326dbae72fb537b0f55f40cffde9 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 14 Nov 2024 14:39:10 -0300 Subject: [PATCH 22/34] refactor: rename variable --- packages/appkit/src/client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index 763a6be01f..ba5577df79 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -712,7 +712,7 @@ export class AppKit { (await this.universalProvider?.client?.core?.crypto?.getClientId()) || null ) - const isOneClickAuthenticated = + const isAuthenticated = this.universalProvider && (await SIWXUtil.universalProviderAuthenticate({ universalProvider: this.universalProvider, @@ -720,7 +720,7 @@ export class AppKit { methods: OPTIONAL_METHODS })) - if (isOneClickAuthenticated) { + if (isAuthenticated) { this.close() } else { await adapter?.connectWalletConnect(onUri, this.getCaipNetwork()?.id) From 11b47e6e847653dec8d76497e2475fb84542b250 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 14 Nov 2024 15:04:45 -0300 Subject: [PATCH 23/34] refactor: setup siwx events instead of siwe events --- packages/core/src/utils/SIWXUtil.ts | 37 +++++++++++++++++++ packages/core/src/utils/TypeUtil.ts | 9 ++--- .../views/w3m-siwx-sign-message-view/index.ts | 14 ++----- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/packages/core/src/utils/SIWXUtil.ts b/packages/core/src/utils/SIWXUtil.ts index adcb028ebd..a9eeb8df94 100644 --- a/packages/core/src/utils/SIWXUtil.ts +++ b/packages/core/src/utils/SIWXUtil.ts @@ -8,6 +8,9 @@ import { StorageUtil } from './StorageUtil.js' import { SnackController } from '../controllers/SnackController.js' import { RouterController } from '../controllers/RouterController.js' import UniversalProvider from '@walletconnect/universal-provider' +import { EventsController } from '../controllers/EventsController.js' +import { AccountController } from '../controllers/AccountController.js' +import { W3mFrameRpcConstants } from '@reown/appkit-wallet' export const SIWXUtil = { getSIWX() { @@ -53,9 +56,22 @@ export const SIWXUtil = { }) ModalController.close() + + EventsController.sendEvent({ + type: 'track', + event: 'SIWX_AUTH_SUCCESS', + properties: SIWXUtil.getSIWXEventProperties() + }) } catch (error: unknown) { // eslint-disable-next-line no-console console.error('Failed to initialize SIWX', error) + + EventsController.sendEvent({ + type: 'track', + event: 'SIWX_AUTH_ERROR', + properties: SIWXUtil.getSIWXEventProperties() + }) + // eslint-disable-next-line no-console await client?.disconnect().catch(console.error) await ModalController.open({ view: 'Connect' }) @@ -156,9 +172,22 @@ export const SIWXUtil = { try { await siwx.setSessions(sessions) + + EventsController.sendEvent({ + type: 'track', + event: 'SIWX_AUTH_SUCCESS', + properties: SIWXUtil.getSIWXEventProperties() + }) } catch (error) { // eslint-disable-next-line no-console console.error('SIWX:universalProviderAuth - failed to set sessions', error) + + EventsController.sendEvent({ + type: 'track', + event: 'SIWX_AUTH_ERROR', + properties: SIWXUtil.getSIWXEventProperties() + }) + // eslint-disable-next-line no-console await universalProvider.disconnect().catch(console.error) throw error @@ -166,6 +195,14 @@ export const SIWXUtil = { } return true + }, + getSIWXEventProperties() { + return { + network: ChainController.state.activeCaipNetwork?.caipNetworkId || '', + isSmartAccount: + AccountController.state.preferredAccountType === + W3mFrameRpcConstants.ACCOUNT_TYPES.SMART_ACCOUNT + } } } diff --git a/packages/core/src/utils/TypeUtil.ts b/packages/core/src/utils/TypeUtil.ts index c08bf3e4cd..4fec7b8f7a 100644 --- a/packages/core/src/utils/TypeUtil.ts +++ b/packages/core/src/utils/TypeUtil.ts @@ -478,7 +478,7 @@ export type Event = } | { type: 'track' - event: 'CLICK_SIGN_SIWE_MESSAGE' + event: 'CLICK_SIGN_SIWX_MESSAGE' properties: { network: string isSmartAccount: boolean @@ -486,7 +486,7 @@ export type Event = } | { type: 'track' - event: 'CLICK_CANCEL_SIWE' + event: 'CLICK_CANCEL_SIWX' properties: { network: string isSmartAccount: boolean @@ -498,7 +498,7 @@ export type Event = } | { type: 'track' - event: 'SIWE_AUTH_SUCCESS' + event: 'SIWX_AUTH_SUCCESS' properties: { network: string isSmartAccount: boolean @@ -506,7 +506,7 @@ export type Event = } | { type: 'track' - event: 'SIWE_AUTH_ERROR' + event: 'SIWX_AUTH_ERROR' properties: { network: string isSmartAccount: boolean @@ -884,7 +884,6 @@ export type AdapterAccountState = { socialWindow?: Window farcasterUrl?: string status?: 'reconnecting' | 'connected' | 'disconnected' | 'connecting' - siweStatus?: 'uninitialized' | 'ready' | 'loading' | 'success' | 'rejected' | 'error' } export type ChainAdapter = { diff --git a/packages/scaffold-ui/src/views/w3m-siwx-sign-message-view/index.ts b/packages/scaffold-ui/src/views/w3m-siwx-sign-message-view/index.ts index 2187113545..1652f45eac 100644 --- a/packages/scaffold-ui/src/views/w3m-siwx-sign-message-view/index.ts +++ b/packages/scaffold-ui/src/views/w3m-siwx-sign-message-view/index.ts @@ -1,16 +1,15 @@ import { - AccountController, ChainController, ConnectionController, EventsController, ModalController, OptionsController, - RouterController + RouterController, + SIWXUtil } from '@reown/appkit-core' import { customElement } from '@reown/appkit-ui' import { LitElement, html } from 'lit' import { state } from 'lit/decorators.js' -import { W3mFrameRpcConstants } from '@reown/appkit-wallet' @customElement('w3m-siwx-sign-message-view') export class W3mSIWXSignMessageView extends LitElement { @@ -72,14 +71,9 @@ export class W3mSIWXSignMessageView extends LitElement { } this.isCancelling = false EventsController.sendEvent({ - event: 'CLICK_CANCEL_SIWE', + event: 'CLICK_CANCEL_SIWX', type: 'track', - properties: { - network: ChainController.state.activeCaipNetwork?.caipNetworkId || '', - isSmartAccount: - AccountController.state.preferredAccountType === - W3mFrameRpcConstants.ACCOUNT_TYPES.SMART_ACCOUNT - } + properties: SIWXUtil.getSIWXEventProperties() }) } } From 5ce726d1c9e1ed650dfb1997d009b3db71e5aa5a Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 14 Nov 2024 15:08:07 -0300 Subject: [PATCH 24/34] fix: remove siwe references on appkit --- packages/core/src/controllers/AccountController.ts | 5 ----- packages/scaffold-ui/src/modal/w3m-modal/index.ts | 10 +--------- packages/scaffold-ui/src/partials/w3m-header/index.ts | 2 -- .../src/views/w3m-email-verify-otp-view/index.ts | 2 +- packages/siwe/core/controller/SIWEController.ts | 5 ----- .../scaffold/views/w3m-connecting-siwe-view/index.ts | 8 ++++---- 6 files changed, 6 insertions(+), 26 deletions(-) diff --git a/packages/core/src/controllers/AccountController.ts b/packages/core/src/controllers/AccountController.ts index ee47ef7cd0..1fd82d4a9e 100644 --- a/packages/core/src/controllers/AccountController.ts +++ b/packages/core/src/controllers/AccountController.ts @@ -40,7 +40,6 @@ export interface AccountControllerState { farcasterUrl?: string provider?: UniversalProvider | Provider | CombinedProvider status?: 'reconnecting' | 'connected' | 'disconnected' | 'connecting' - siweStatus?: 'uninitialized' | 'ready' | 'loading' | 'success' | 'rejected' | 'error' lastRetry?: number } @@ -262,9 +261,5 @@ export const AccountController = { resetAccount(chain: ChainNamespace) { ChainController.resetAccount(chain) - }, - - setSiweStatus(status: AccountControllerState['siweStatus']) { - ChainController.setAccountProp('siweStatus', status, ChainController.state.activeChain) } } diff --git a/packages/scaffold-ui/src/modal/w3m-modal/index.ts b/packages/scaffold-ui/src/modal/w3m-modal/index.ts index d1ef1b569a..9f701854a0 100644 --- a/packages/scaffold-ui/src/modal/w3m-modal/index.ts +++ b/packages/scaffold-ui/src/modal/w3m-modal/index.ts @@ -1,5 +1,4 @@ import { - AccountController, ApiController, ChainController, CoreHelperUtil, @@ -14,7 +13,7 @@ import { UiHelperUtil, customElement, initializeTheming } from '@reown/appkit-ui import { LitElement, html } from 'lit' import { state } from 'lit/decorators.js' import styles from './styles.js' -import { type CaipAddress, type CaipNetwork, type SIWEStatus } from '@reown/appkit-common' +import { type CaipAddress, type CaipNetwork } from '@reown/appkit-common' // -- Helpers --------------------------------------------- // const SCROLL_LOCK = 'scroll-lock' @@ -45,7 +44,6 @@ export class W3mModal extends LitElement { ...[ ModalController.subscribeKey('open', val => (val ? this.onOpen() : this.onClose())), ModalController.subscribeKey('shake', val => (this.shake = val)), - AccountController.subscribeKey('siweStatus', val => this.onSiweStatusChange(val), 'eip155'), ChainController.subscribeKey('activeCaipNetwork', val => this.onNewNetwork(val)), ChainController.subscribeKey('activeCaipAddress', val => this.onNewAddress(val)) ] @@ -166,12 +164,6 @@ export class W3mModal extends LitElement { this.abortController = undefined } - private onSiweStatusChange(nextStatus: SIWEStatus | undefined) { - if (nextStatus === 'success') { - ModalController.close() - } - } - private async onNewAddress(caipAddress?: CaipAddress) { const nextConnected = caipAddress ? CoreHelperUtil.getPlainAddress(caipAddress) : undefined diff --git a/packages/scaffold-ui/src/partials/w3m-header/index.ts b/packages/scaffold-ui/src/partials/w3m-header/index.ts index 45b9657bd8..5d68fc7d9a 100644 --- a/packages/scaffold-ui/src/partials/w3m-header/index.ts +++ b/packages/scaffold-ui/src/partials/w3m-header/index.ts @@ -106,8 +106,6 @@ export class W3mHeader extends LitElement { @state() private showBack = false - @state() private isSiweEnabled = OptionsController.state.isSiweEnabled - @state() private prevHistoryLength = 1 @state() private view = RouterController.state.view diff --git a/packages/scaffold-ui/src/views/w3m-email-verify-otp-view/index.ts b/packages/scaffold-ui/src/views/w3m-email-verify-otp-view/index.ts index 084202e630..877c7d1ec6 100644 --- a/packages/scaffold-ui/src/views/w3m-email-verify-otp-view/index.ts +++ b/packages/scaffold-ui/src/views/w3m-email-verify-otp-view/index.ts @@ -32,7 +32,7 @@ export class W3mEmailVerifyOtpView extends W3mEmailOtpWidget { event: 'CONNECT_SUCCESS', properties: { method: 'email', name: this.authConnector.name || 'Unknown' } }) - if (!OptionsController.state.isSiweEnabled) { + if (!OptionsController.state.siwx) { ModalController.close() } } diff --git a/packages/siwe/core/controller/SIWEController.ts b/packages/siwe/core/controller/SIWEController.ts index 2f7c0bdf2c..af97278dec 100644 --- a/packages/siwe/core/controller/SIWEController.ts +++ b/packages/siwe/core/controller/SIWEController.ts @@ -6,7 +6,6 @@ import type { SIWECreateMessageArgs, SIWEVerifyMessageArgs } from '../utils/TypeUtils.js' -import { ChainController, OptionsController } from '@reown/appkit-core' import type { SIWEStatus } from '@reown/appkit-common' // -- Types --------------------------------------------- // @@ -127,8 +126,6 @@ export const SIWEController = { state._client = ref(client) state.session = await this.getSession() state.status = state.session ? 'success' : 'ready' - ChainController.setAccountProp('siweStatus', state.status, 'eip155') - OptionsController.setIsSiweEnabled(client.options.enabled) }, setNonce(nonce: SIWEControllerClientState['nonce']) { @@ -137,7 +134,6 @@ export const SIWEController = { setStatus(status: SIWEControllerClientState['status']) { state.status = status - ChainController.setAccountProp('siweStatus', state.status, 'eip155') }, setMessage(message: SIWEControllerClientState['message']) { @@ -147,6 +143,5 @@ export const SIWEController = { setSession(session: SIWEControllerClientState['session']) { state.session = session state.status = session ? 'success' : 'ready' - ChainController.setAccountProp('siweStatus', state.status, 'eip155') } } diff --git a/packages/siwe/scaffold/views/w3m-connecting-siwe-view/index.ts b/packages/siwe/scaffold/views/w3m-connecting-siwe-view/index.ts index 65a2fa9d29..6f2ad0b1b1 100644 --- a/packages/siwe/scaffold/views/w3m-connecting-siwe-view/index.ts +++ b/packages/siwe/scaffold/views/w3m-connecting-siwe-view/index.ts @@ -79,7 +79,7 @@ export class W3mConnectingSiweView extends LitElement { private async onSign() { this.isSigning = true EventsController.sendEvent({ - event: 'CLICK_SIGN_SIWE_MESSAGE', + event: 'CLICK_SIGN_SIWX_MESSAGE', type: 'track', properties: { network: ChainController.state.activeCaipNetwork?.caipNetworkId || '', @@ -93,7 +93,7 @@ export class W3mConnectingSiweView extends LitElement { const session = await SIWEController.signIn() SIWEController.setStatus('success') EventsController.sendEvent({ - event: 'SIWE_AUTH_SUCCESS', + event: 'SIWX_AUTH_SUCCESS', type: 'track', properties: { network: ChainController.state.activeCaipNetwork?.caipNetworkId || '', @@ -116,7 +116,7 @@ export class W3mConnectingSiweView extends LitElement { SIWEController.setStatus('error') return EventsController.sendEvent({ - event: 'SIWE_AUTH_ERROR', + event: 'SIWX_AUTH_ERROR', type: 'track', properties: { network: ChainController.state.activeCaipNetwork?.caipNetworkId || '', @@ -139,7 +139,7 @@ export class W3mConnectingSiweView extends LitElement { } this.isCancelling = false EventsController.sendEvent({ - event: 'CLICK_CANCEL_SIWE', + event: 'CLICK_CANCEL_SIWX', type: 'track', properties: { network: ChainController.state.activeCaipNetwork?.caipNetworkId || '', From be5f4fe07b90e802c8a573a153776463554365df Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 14 Nov 2024 18:52:22 -0300 Subject: [PATCH 25/34] refactor: bring back sign button --- packages/core/src/utils/SIWXUtil.ts | 71 ++++++++++++++----- .../views/w3m-siwx-sign-message-view/index.ts | 44 ++++++------ 2 files changed, 75 insertions(+), 40 deletions(-) diff --git a/packages/core/src/utils/SIWXUtil.ts b/packages/core/src/utils/SIWXUtil.ts index a9eeb8df94..492304006d 100644 --- a/packages/core/src/utils/SIWXUtil.ts +++ b/packages/core/src/utils/SIWXUtil.ts @@ -4,7 +4,6 @@ import { CoreHelperUtil } from './CoreHelperUtil.js' import { ChainController } from '../controllers/ChainController.js' import { ConnectionController } from '../controllers/ConnectionController.js' import { ModalController } from '../controllers/ModalController.js' -import { StorageUtil } from './StorageUtil.js' import { SnackController } from '../controllers/SnackController.js' import { RouterController } from '../controllers/RouterController.js' import UniversalProvider from '@walletconnect/universal-provider' @@ -25,8 +24,6 @@ export const SIWXUtil = { return } - const client = ConnectionController._getClient() - try { const sessions = await siwx.getSessions(network.caipNetworkId, address) if (sessions.length) { @@ -34,12 +31,35 @@ export const SIWXUtil = { } await ModalController.open({ - view: - StorageUtil.getConnectedConnector() === 'ID_AUTH' - ? 'ApproveTransaction' - : 'SIWXSignMessage' + view: 'SIWXSignMessage' + }) + } catch (error: unknown) { + // eslint-disable-next-line no-console + console.error('SIWXUtil:initializeIfEnabled', error) + + EventsController.sendEvent({ + type: 'track', + event: 'SIWX_AUTH_ERROR', + properties: this.getSIWXEventProperties() }) + // eslint-disable-next-line no-console + await ConnectionController._getClient()?.disconnect().catch(console.error) + RouterController.reset('Connect') + SnackController.showError('A problem occurred while trying initialize authentication') + } + }, + async requestSignMessage() { + const siwx = OptionsController.state.siwx + const address = CoreHelperUtil.getPlainAddress(ChainController.getActiveCaipAddress()) + const network = ChainController.getActiveCaipNetwork() + const client = ConnectionController._getClient() + + if (!(siwx && address && network && client)) { + throw new Error('SIWX is not enabled') + } + + try { const siwxMessage = await siwx.createMessage({ chainId: network.caipNetworkId, accountAddress: address @@ -47,7 +67,7 @@ export const SIWXUtil = { const message = siwxMessage.toString() - const signature = await client?.signMessage(message) + const signature = await client.signMessage(message) await siwx.addSession({ data: siwxMessage, @@ -60,22 +80,39 @@ export const SIWXUtil = { EventsController.sendEvent({ type: 'track', event: 'SIWX_AUTH_SUCCESS', - properties: SIWXUtil.getSIWXEventProperties() + properties: this.getSIWXEventProperties() }) - } catch (error: unknown) { - // eslint-disable-next-line no-console - console.error('Failed to initialize SIWX', error) + } catch (error) { + const properties = this.getSIWXEventProperties() + + if (properties.isSmartAccount) { + SnackController.showError('This application might not support Smart Accounts') + } else { + SnackController.showError('Signature declined') + } EventsController.sendEvent({ type: 'track', event: 'SIWX_AUTH_ERROR', - properties: SIWXUtil.getSIWXEventProperties() + properties }) // eslint-disable-next-line no-console - await client?.disconnect().catch(console.error) - await ModalController.open({ view: 'Connect' }) - SnackController.showError('It was not possible to verify the message signature') + console.error('SWIXUtil:requestSignMessage', error) + } + }, + async cancelSignMessage() { + try { + await ConnectionController.disconnect() + RouterController.reset('Connect') + EventsController.sendEvent({ + event: 'CLICK_CANCEL_SIWX', + type: 'track', + properties: this.getSIWXEventProperties() + }) + } catch (error) { + // eslint-disable-next-line no-console + console.error('SIWXUtil:cancelSignMessage', error) } }, async getSessions() { @@ -97,7 +134,7 @@ export const SIWXUtil = { const isSiwxSignMessage = RouterController.state.view === 'SIWXSignMessage' if (isApproveSignScreen || isSiwxSignMessage) { - return (await this.getSessions()).length > 1 + return (await this.getSessions()).length === 0 } } diff --git a/packages/scaffold-ui/src/views/w3m-siwx-sign-message-view/index.ts b/packages/scaffold-ui/src/views/w3m-siwx-sign-message-view/index.ts index 1652f45eac..b83a2b4151 100644 --- a/packages/scaffold-ui/src/views/w3m-siwx-sign-message-view/index.ts +++ b/packages/scaffold-ui/src/views/w3m-siwx-sign-message-view/index.ts @@ -1,12 +1,4 @@ -import { - ChainController, - ConnectionController, - EventsController, - ModalController, - OptionsController, - RouterController, - SIWXUtil -} from '@reown/appkit-core' +import { OptionsController, SIWXUtil } from '@reown/appkit-core' import { customElement } from '@reown/appkit-ui' import { LitElement, html } from 'lit' import { state } from 'lit/decorators.js' @@ -18,6 +10,8 @@ export class W3mSIWXSignMessageView extends LitElement { @state() private isCancelling = false + @state() private isSigning = false + // -- Render -------------------------------------------- // public override render() { return html` @@ -53,28 +47,32 @@ export class W3mSIWXSignMessageView extends LitElement { @click=${this.onCancel.bind(this)} data-testid="w3m-connecting-siwe-cancel" > - Cancel + ${this.isCancelling ? 'Cancelling...' : 'Cancel'} + + + ${this.isSigning ? 'Signing...' : 'Sign'} ` } // -- Private ------------------------------------------- // + private async onSign() { + this.isSigning = true + await SIWXUtil.requestSignMessage().finally(() => (this.isSigning = false)) + } + private async onCancel() { this.isCancelling = true - const caipAddress = ChainController.state.activeCaipAddress - if (caipAddress) { - await ConnectionController.disconnect() - ModalController.close() - } else { - RouterController.push('Connect') - } - this.isCancelling = false - EventsController.sendEvent({ - event: 'CLICK_CANCEL_SIWX', - type: 'track', - properties: SIWXUtil.getSIWXEventProperties() - }) + await SIWXUtil.cancelSignMessage().finally(() => (this.isCancelling = false)) } } From b1d59a1734baa68a6f51c4595c2dd24f164dafba Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 14 Nov 2024 19:40:45 -0300 Subject: [PATCH 26/34] fix: missing siwe configuration flags on mapToSIWX --- packages/core/src/utils/SIWXUtil.ts | 6 ++-- packages/siwe/src/mapToSIWX.ts | 51 ++++++++++++++++++++++++----- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/packages/core/src/utils/SIWXUtil.ts b/packages/core/src/utils/SIWXUtil.ts index 492304006d..ed82c15aaa 100644 --- a/packages/core/src/utils/SIWXUtil.ts +++ b/packages/core/src/utils/SIWXUtil.ts @@ -159,7 +159,7 @@ export const SIWXUtil = { // Ignores chainId and account address to get other message data const siwxMessage = await siwx.createMessage({ - chainId: '', + chainId: '' as CaipNetworkId, accountAddress: '' }) @@ -189,7 +189,7 @@ export const SIWXUtil = { return { data: { accountAddress: cacao.p.iss.split(':').slice(-1).join(''), - chainId: cacao.p.iss.split(':').slice(2, 4).join(':'), + chainId: cacao.p.iss.split(':').slice(2, 4).join(':') as CaipNetworkId, uri: cacao.p.aud, domain: cacao.p.domain, nonce: cacao.p.nonce, @@ -280,7 +280,7 @@ export namespace SIWXMessage { */ export interface Input { accountAddress: string - chainId: string + chainId: CaipNetworkId notBefore?: Timestamp } diff --git a/packages/siwe/src/mapToSIWX.ts b/packages/siwe/src/mapToSIWX.ts index 1b528b3025..69f59611cd 100644 --- a/packages/siwe/src/mapToSIWX.ts +++ b/packages/siwe/src/mapToSIWX.ts @@ -1,11 +1,38 @@ -import type { SIWXConfig, SIWXMessage, SIWXSession } from '@reown/appkit-core' -import type { SIWEConfig } from '../exports/index.js' +import { + ChainController, + CoreHelperUtil, + type SIWXConfig, + type SIWXMessage, + type SIWXSession +} from '@reown/appkit-core' +import type { AppKitSIWEClient } from '../exports/index.js' import { NetworkUtil, type CaipNetworkId } from '@reown/appkit-common' -export function mapToSIWX(siwe: SIWEConfig): SIWXConfig { +export function mapToSIWX(siwe: AppKitSIWEClient): SIWXConfig { + ChainController.subscribeKey('activeCaipNetwork', async activeCaipNetwork => { + const session = await siwe.methods.getSession().catch(() => undefined) + const isDiffernetNetwork = + session && + session.chainId !== NetworkUtil.caipNetworkIdToNumber(activeCaipNetwork?.caipNetworkId) + + if (isDiffernetNetwork) { + await siwe.methods.signOut() + } + }) + + ChainController.subscribeKey('activeCaipAddress', async activeCaipAddress => { + const session = await siwe.methods.getSession().catch(() => undefined) + const isDifferentAddress = + session && session.address !== CoreHelperUtil.getPlainAddress(activeCaipAddress) + + if (isDifferentAddress) { + await siwe.methods.signOut() + } + }) + return { async createMessage(input) { - const params = await siwe.getMessageParams?.() + const params = await siwe.methods.getMessageParams?.() if (!params) { throw new Error('Failed to get message params!') @@ -44,11 +71,11 @@ export function mapToSIWX(siwe: SIWEConfig): SIWXConfig { const chainId = NetworkUtil.parseEvmChainId(session.data.chainId) if (!chainId) { - throw new Error('Invalid chain ID!') + throw new Error('Invalid chain ID') } if (await siwe.verifyMessage?.(session)) { - siwe.onSignIn?.({ + siwe.methods.onSignIn?.({ address: session.data.accountAddress, chainId }) @@ -61,6 +88,8 @@ export function mapToSIWX(siwe: SIWEConfig): SIWXConfig { async revokeSession(_chainId, _address) { if (await siwe.signOut()) { + siwe.methods.onSignOut?.() + return Promise.resolve() } @@ -68,13 +97,17 @@ export function mapToSIWX(siwe: SIWEConfig): SIWXConfig { }, async setSessions(sessions) { - const addingSessions = sessions.map(session => this.addSession(session)) - await Promise.all(addingSessions) + if (sessions.length === 0) { + await siwe.methods.signOut() + } else { + const addingSessions = sessions.map(session => this.addSession(session)) + await Promise.all(addingSessions) + } }, async getSessions(chainId, address) { try { - const siweSession = await siwe.getSession() + const siweSession = await siwe.methods.getSession() const siweCaipNetworkId = `eip155:${siweSession?.chainId}` if (!siweSession || siweSession.address !== address || siweCaipNetworkId !== chainId) { From bcab8ea75297781711276f2b8217a619376c7d48 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Thu, 14 Nov 2024 20:29:33 -0300 Subject: [PATCH 27/34] fix: missing auth sign message opening --- packages/core/src/utils/SIWXUtil.ts | 9 +++++++++ packages/siwe/src/mapToSIWX.ts | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/core/src/utils/SIWXUtil.ts b/packages/core/src/utils/SIWXUtil.ts index ed82c15aaa..552534ac97 100644 --- a/packages/core/src/utils/SIWXUtil.ts +++ b/packages/core/src/utils/SIWXUtil.ts @@ -10,6 +10,7 @@ import UniversalProvider from '@walletconnect/universal-provider' import { EventsController } from '../controllers/EventsController.js' import { AccountController } from '../controllers/AccountController.js' import { W3mFrameRpcConstants } from '@reown/appkit-wallet' +import { StorageUtil } from './StorageUtil.js' export const SIWXUtil = { getSIWX() { @@ -67,6 +68,14 @@ export const SIWXUtil = { const message = siwxMessage.toString() + if (StorageUtil.getConnectedConnector() === 'ID_AUTH') { + RouterController.pushTransactionStack({ + view: null, + goBack: false, + replace: true + }) + } + const signature = await client.signMessage(message) await siwx.addSession({ diff --git a/packages/siwe/src/mapToSIWX.ts b/packages/siwe/src/mapToSIWX.ts index 69f59611cd..626ad22729 100644 --- a/packages/siwe/src/mapToSIWX.ts +++ b/packages/siwe/src/mapToSIWX.ts @@ -6,7 +6,7 @@ import { type SIWXSession } from '@reown/appkit-core' import type { AppKitSIWEClient } from '../exports/index.js' -import { NetworkUtil, type CaipNetworkId } from '@reown/appkit-common' +import { NetworkUtil } from '@reown/appkit-common' export function mapToSIWX(siwe: AppKitSIWEClient): SIWXConfig { ChainController.subscribeKey('activeCaipNetwork', async activeCaipNetwork => { @@ -58,7 +58,7 @@ export function mapToSIWX(siwe: AppKitSIWEClient): SIWXConfig { toString: () => siwe.createMessage({ ...params, - chainId: NetworkUtil.caipNetworkIdToNumber(input.chainId as CaipNetworkId) || 1, + chainId: NetworkUtil.caipNetworkIdToNumber(input.chainId) || 1, address: `did:pkh:${input.chainId}:${input.accountAddress}`, nonce, version, From 7677a164c41c47934b87164be46092ee8a863952 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Fri, 15 Nov 2024 11:08:05 -0300 Subject: [PATCH 28/34] refactor: remove file with functions not in use --- packages/scaffold-ui/src/utils/NetworkUtil.ts | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 packages/scaffold-ui/src/utils/NetworkUtil.ts diff --git a/packages/scaffold-ui/src/utils/NetworkUtil.ts b/packages/scaffold-ui/src/utils/NetworkUtil.ts deleted file mode 100644 index d0286fe91a..0000000000 --- a/packages/scaffold-ui/src/utils/NetworkUtil.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { RouterUtil } from '@reown/appkit-core' - -export const NetworkUtil = { - onNetworkChange: async () => { - RouterUtil.navigateAfterNetworkSwitch() - - return Promise.resolve() - } -} From b6c3ad5eff64d40e8e34bfe2fdd86d24d2ed43a5 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Fri, 15 Nov 2024 11:10:41 -0300 Subject: [PATCH 29/34] fix: spread cacao instead of include line by line --- packages/core/src/utils/SIWXUtil.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/core/src/utils/SIWXUtil.ts b/packages/core/src/utils/SIWXUtil.ts index 552534ac97..9ee290ee32 100644 --- a/packages/core/src/utils/SIWXUtil.ts +++ b/packages/core/src/utils/SIWXUtil.ts @@ -197,18 +197,14 @@ export const SIWXUtil = { return { data: { + ...cacao.p, accountAddress: cacao.p.iss.split(':').slice(-1).join(''), chainId: cacao.p.iss.split(':').slice(2, 4).join(':') as CaipNetworkId, uri: cacao.p.aud, - domain: cacao.p.domain, - nonce: cacao.p.nonce, version: cacao.p.version || siwxMessage.version, expirationTime: cacao.p.exp, - statement: cacao.p.statement, issuedAt: cacao.p.iat, - notBefore: cacao.p.nbf, - requestId: cacao.p.requestId, - resources: cacao.p.resources + notBefore: cacao.p.nbf }, message, signature: cacao.s.s, From 03139c76bb37a95c150643b7609e09ae248546a1 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Fri, 15 Nov 2024 11:18:11 -0300 Subject: [PATCH 30/34] fix: remove inline experssion --- packages/appkit/src/client.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index ba5577df79..8c72f33cbd 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -712,13 +712,17 @@ export class AppKit { (await this.universalProvider?.client?.core?.crypto?.getClientId()) || null ) - const isAuthenticated = - this.universalProvider && - (await SIWXUtil.universalProviderAuthenticate({ + let isAuthenticated = false + + if (this.universalProvider) { + const chains = this.caipNetworks?.map(network => network.caipNetworkId) || [] + + isAuthenticated = await SIWXUtil.universalProviderAuthenticate({ universalProvider: this.universalProvider, - chains: this.caipNetworks?.map(network => network.caipNetworkId) || [], + chains, methods: OPTIONAL_METHODS - })) + }) + } if (isAuthenticated) { this.close() From 30e28f9c2705e318f436a85e2a1eeeaaf75a1eb1 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Fri, 15 Nov 2024 17:20:10 -0300 Subject: [PATCH 31/34] fix: siwe mapping for non evm chains --- packages/core/src/utils/SIWXUtil.ts | 14 +++++++++---- .../scaffold-ui/src/modal/w3m-modal/index.ts | 2 +- packages/siwe/src/mapToSIWX.ts | 21 ++++++++++++++++--- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/packages/core/src/utils/SIWXUtil.ts b/packages/core/src/utils/SIWXUtil.ts index 9ee290ee32..f1f0179cda 100644 --- a/packages/core/src/utils/SIWXUtil.ts +++ b/packages/core/src/utils/SIWXUtil.ts @@ -18,15 +18,15 @@ export const SIWXUtil = { }, async initializeIfEnabled() { const siwx = OptionsController.state.siwx - const address = CoreHelperUtil.getPlainAddress(ChainController.getActiveCaipAddress()) - const network = ChainController.getActiveCaipNetwork() + const caipAddress = ChainController.getActiveCaipAddress() - if (!(siwx && address && network)) { + if (!(siwx && caipAddress)) { return } + const [network, chainId, address] = caipAddress.split(':') as [string, string, string] try { - const sessions = await siwx.getSessions(network.caipNetworkId, address) + const sessions = await siwx.getSessions(`${network}:${chainId}` as CaipNetworkId, address) if (sessions.length) { return } @@ -94,6 +94,12 @@ export const SIWXUtil = { } catch (error) { const properties = this.getSIWXEventProperties() + if (!ModalController.state.open || RouterController.state.view === 'ApproveTransaction') { + await ModalController.open({ + view: 'SIWXSignMessage' + }) + } + if (properties.isSmartAccount) { SnackController.showError('This application might not support Smart Accounts') } else { diff --git a/packages/scaffold-ui/src/modal/w3m-modal/index.ts b/packages/scaffold-ui/src/modal/w3m-modal/index.ts index 9f701854a0..60a3091a1f 100644 --- a/packages/scaffold-ui/src/modal/w3m-modal/index.ts +++ b/packages/scaffold-ui/src/modal/w3m-modal/index.ts @@ -165,7 +165,7 @@ export class W3mModal extends LitElement { } private async onNewAddress(caipAddress?: CaipAddress) { - const nextConnected = caipAddress ? CoreHelperUtil.getPlainAddress(caipAddress) : undefined + const nextConnected = CoreHelperUtil.getPlainAddress(caipAddress) this.caipAddress = caipAddress diff --git a/packages/siwe/src/mapToSIWX.ts b/packages/siwe/src/mapToSIWX.ts index 626ad22729..6100b94e28 100644 --- a/packages/siwe/src/mapToSIWX.ts +++ b/packages/siwe/src/mapToSIWX.ts @@ -71,13 +71,14 @@ export function mapToSIWX(siwe: AppKitSIWEClient): SIWXConfig { const chainId = NetworkUtil.parseEvmChainId(session.data.chainId) if (!chainId) { - throw new Error('Invalid chain ID') + // Workaround to ignore non-EVM chains to keep the same behavior of SIWE + return Promise.resolve() } - if (await siwe.verifyMessage?.(session)) { + if (await siwe.methods.verifyMessage(session)) { siwe.methods.onSignIn?.({ address: session.data.accountAddress, - chainId + chainId: NetworkUtil.parseEvmChainId(session.data.chainId) as number }) return Promise.resolve() @@ -107,6 +108,20 @@ export function mapToSIWX(siwe: AppKitSIWEClient): SIWXConfig { async getSessions(chainId, address) { try { + if (!chainId.startsWith('eip155:')) { + // Workaround to ignore non-EVM chains to keep the same behavior of SIWE + return [ + { + data: { + accountAddress: address, + chainId + }, + message: '', + signature: '' + } as SIWXSession + ] + } + const siweSession = await siwe.methods.getSession() const siweCaipNetworkId = `eip155:${siweSession?.chainId}` From 54c5552c222d978cc73f61dd3f66f3e52c916ba4 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Fri, 15 Nov 2024 18:08:51 -0300 Subject: [PATCH 32/34] test: fix tests --- .../multichain/multichain-ethers-solana-email-siwe.spec.ts | 2 +- .../tests/multichain/multichain-ethers-solana-siwe.spec.ts | 5 ++++- .../multichain/multichain-ethers5-solana-email-siwe.spec.ts | 2 +- .../tests/multichain/multichain-ethers5-solana-siwe.spec.ts | 5 ++++- .../multichain/multichain-wagmi-solana-email-siwe.spec.ts | 3 --- .../tests/multichain/multichain-wagmi-solana-siwe.spec.ts | 5 ++++- 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/laboratory/tests/multichain/multichain-ethers-solana-email-siwe.spec.ts b/apps/laboratory/tests/multichain/multichain-ethers-solana-email-siwe.spec.ts index 52973d08dc..ac808fac55 100644 --- a/apps/laboratory/tests/multichain/multichain-ethers-solana-email-siwe.spec.ts +++ b/apps/laboratory/tests/multichain/multichain-ethers-solana-email-siwe.spec.ts @@ -59,7 +59,7 @@ test('it should switch to different namespace', async () => { const chainName = 'Solana' await page.switchNetwork(chainName) - await page.openNetworks() + await validator.expectUnauthenticated() await validator.expectSwitchedNetwork(chainName) await page.closeModal() diff --git a/apps/laboratory/tests/multichain/multichain-ethers-solana-siwe.spec.ts b/apps/laboratory/tests/multichain/multichain-ethers-solana-siwe.spec.ts index e2567c09a2..c67af9da88 100644 --- a/apps/laboratory/tests/multichain/multichain-ethers-solana-siwe.spec.ts +++ b/apps/laboratory/tests/multichain/multichain-ethers-solana-siwe.spec.ts @@ -28,6 +28,9 @@ test.beforeAll(async ({ browser }) => { await modalPage.load() await modalPage.qrCodeFlow(modalPage, walletPage) await modalValidator.expectConnected() + await modalPage.promptSiwe() + await walletPage.handleRequest({ accept: true }) + await modalValidator.expectAuthenticated() }) test.afterAll(async () => { @@ -53,5 +56,5 @@ test('it should switch networks and sign siwe', async () => { test('it should switch to Solana and validate chain title', async () => { const chainName = 'Solana' await modalPage.switchNetwork(chainName) - await modalValidator.expectSwitchChainView(chainName.toLocaleLowerCase()) + await modalValidator.expectSwitchedNetworkOnNetworksView(chainName) }) diff --git a/apps/laboratory/tests/multichain/multichain-ethers5-solana-email-siwe.spec.ts b/apps/laboratory/tests/multichain/multichain-ethers5-solana-email-siwe.spec.ts index ce4ef04909..2f65550bb8 100644 --- a/apps/laboratory/tests/multichain/multichain-ethers5-solana-email-siwe.spec.ts +++ b/apps/laboratory/tests/multichain/multichain-ethers5-solana-email-siwe.spec.ts @@ -59,7 +59,7 @@ test('it should switch to different namespace', async () => { const chainName = 'Solana' await page.switchNetwork(chainName) - await page.openNetworks() + await validator.expectUnauthenticated() await validator.expectSwitchedNetwork(chainName) await page.closeModal() diff --git a/apps/laboratory/tests/multichain/multichain-ethers5-solana-siwe.spec.ts b/apps/laboratory/tests/multichain/multichain-ethers5-solana-siwe.spec.ts index a161cfd674..f1a991292e 100644 --- a/apps/laboratory/tests/multichain/multichain-ethers5-solana-siwe.spec.ts +++ b/apps/laboratory/tests/multichain/multichain-ethers5-solana-siwe.spec.ts @@ -28,6 +28,9 @@ test.beforeAll(async ({ browser }) => { await modalPage.load() await modalPage.qrCodeFlow(modalPage, walletPage) await modalValidator.expectConnected() + await modalPage.promptSiwe() + await walletPage.handleRequest({ accept: true }) + await modalValidator.expectAuthenticated() }) test.afterAll(async () => { @@ -52,5 +55,5 @@ test('it should switch networks and sign siwe', async () => { test('it should switch to Solana and validate chain title', async () => { const chainName = 'Solana' await modalPage.switchNetwork(chainName) - await modalValidator.expectSwitchChainView(chainName.toLocaleLowerCase()) + await modalValidator.expectSwitchedNetworkOnNetworksView(chainName) }) diff --git a/apps/laboratory/tests/multichain/multichain-wagmi-solana-email-siwe.spec.ts b/apps/laboratory/tests/multichain/multichain-wagmi-solana-email-siwe.spec.ts index 38b19f4c21..0fa15ade42 100644 --- a/apps/laboratory/tests/multichain/multichain-wagmi-solana-email-siwe.spec.ts +++ b/apps/laboratory/tests/multichain/multichain-wagmi-solana-email-siwe.spec.ts @@ -60,9 +60,6 @@ test('it should switch to different namespace', async () => { await page.switchNetwork(chainName) await validator.expectUnauthenticated() - await page.closeModal() - await page.openAccount() - await page.openNetworks() await validator.expectSwitchedNetwork(chainName) await page.closeModal() diff --git a/apps/laboratory/tests/multichain/multichain-wagmi-solana-siwe.spec.ts b/apps/laboratory/tests/multichain/multichain-wagmi-solana-siwe.spec.ts index f1dcf45040..ff41fd5e6b 100644 --- a/apps/laboratory/tests/multichain/multichain-wagmi-solana-siwe.spec.ts +++ b/apps/laboratory/tests/multichain/multichain-wagmi-solana-siwe.spec.ts @@ -28,6 +28,9 @@ test.beforeAll(async ({ browser }) => { await modalPage.load() await modalPage.qrCodeFlow(modalPage, walletPage) await modalValidator.expectConnected() + await modalPage.promptSiwe() + await walletPage.handleRequest({ accept: true }) + await modalValidator.expectAuthenticated() }) test.afterAll(async () => { @@ -53,5 +56,5 @@ test('it should switch networks and sign siwe', async () => { test('it should switch to Solana and validate chain title', async () => { const chainName = 'Solana' await modalPage.switchNetwork(chainName) - await modalValidator.expectSwitchChainView(chainName.toLocaleLowerCase()) + await modalValidator.expectSwitchedNetworkOnNetworksView(chainName) }) From d1b5dde2bb6961728b7119ed80559640aef0f5a6 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Mon, 18 Nov 2024 10:32:49 -0300 Subject: [PATCH 33/34] chore: add changeset --- .changeset/sour-timers-crash.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .changeset/sour-timers-crash.md diff --git a/.changeset/sour-timers-crash.md b/.changeset/sour-timers-crash.md new file mode 100644 index 0000000000..05624c5ab1 --- /dev/null +++ b/.changeset/sour-timers-crash.md @@ -0,0 +1,24 @@ +--- +'@reown/appkit-adapter-solana': minor +'@reown/appkit-scaffold-ui': minor +'@apps/laboratory': minor +'@reown/appkit': minor +'@reown/appkit-core': minor +'@reown/appkit-siwe': minor +'@reown/appkit-siwx': minor +'@apps/demo': minor +'@apps/gallery': minor +'@reown/appkit-adapter-ethers': minor +'@reown/appkit-adapter-ethers5': minor +'@reown/appkit-adapter-polkadot': minor +'@reown/appkit-adapter-wagmi': minor +'@reown/appkit-utils': minor +'@reown/appkit-cdn': minor +'@reown/appkit-common': minor +'@reown/appkit-experimental': minor +'@reown/appkit-polyfills': minor +'@reown/appkit-ui': minor +'@reown/appkit-wallet': minor +--- + +Replace SIWE with new SIWX From 7ed50aae0e53c5c653429b0bd3241a85e5166eb5 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Mon, 18 Nov 2024 13:08:40 -0300 Subject: [PATCH 34/34] fix: missing to check option in map to siwx --- packages/siwe/src/mapToSIWX.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/siwe/src/mapToSIWX.ts b/packages/siwe/src/mapToSIWX.ts index 6100b94e28..d413c92eda 100644 --- a/packages/siwe/src/mapToSIWX.ts +++ b/packages/siwe/src/mapToSIWX.ts @@ -10,6 +10,10 @@ import { NetworkUtil } from '@reown/appkit-common' export function mapToSIWX(siwe: AppKitSIWEClient): SIWXConfig { ChainController.subscribeKey('activeCaipNetwork', async activeCaipNetwork => { + if (!siwe.options.signOutOnNetworkChange) { + return + } + const session = await siwe.methods.getSession().catch(() => undefined) const isDiffernetNetwork = session && @@ -21,6 +25,10 @@ export function mapToSIWX(siwe: AppKitSIWEClient): SIWXConfig { }) ChainController.subscribeKey('activeCaipAddress', async activeCaipAddress => { + if (!siwe.options.signOutOnAccountChange) { + return + } + const session = await siwe.methods.getSession().catch(() => undefined) const isDifferentAddress = session && session.address !== CoreHelperUtil.getPlainAddress(activeCaipAddress)