diff --git a/.github/workflows/generate-zip.yml b/.github/workflows/generate-zip.yml index e480aec..a68a596 100644 --- a/.github/workflows/generate-zip.yml +++ b/.github/workflows/generate-zip.yml @@ -18,7 +18,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v2 with: - node-version: '16' + node-version: '18' cache: 'yarn' - name: Install packages w/ Yarn diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 8507dd1..2b4a6bf 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,7 +13,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v2 with: - node-version: '16' + node-version: '18' cache: 'yarn' - name: Install packages w/ Yarn diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..25bf17f --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +18 \ No newline at end of file diff --git a/blocks/login-block/frontend.jsx b/blocks/login-block/frontend.jsx index d327b84..ebb8480 100644 --- a/blocks/login-block/frontend.jsx +++ b/blocks/login-block/frontend.jsx @@ -28,9 +28,15 @@ if ( loginBlocks ) { } onLogout={ () => { const logoutURL = new URL( LOGOUT_URL ); + const currentURL = new URL( window.location.href ); + // Add a 'wp-rainbow-logout' query parameter to the current URL. + currentURL.searchParams.append( + 'wp-rainbow-logout', + 'true' + ); logoutURL.searchParams.append( 'redirect_to', - encodeURI( window.location.href ) + encodeURI( currentURL ) ); window.location = logoutURL.toString(); } } diff --git a/inc/class-wp-rainbow-login-functionality.php b/inc/class-wp-rainbow-login-functionality.php index ca34363..508e1d3 100644 --- a/inc/class-wp-rainbow-login-functionality.php +++ b/inc/class-wp-rainbow-login-functionality.php @@ -128,10 +128,11 @@ public function get_should_disable_user_role_updates_on_login(): string { * @param string $filtered_infura_id Filtered Infura ID. * @param string $filtered_infura_network Filtered Infura network. * @param WP_User|false $user User object, if available. + * @param string $filtered_rpc_url Filtered RPC URL. * * @return string Filtered role for a given address. */ - public function get_role_for_address_filtered( string $address, string $filtered_infura_id, string $filtered_infura_network, $user ): string { + public function get_role_for_address_filtered( string $address, string $filtered_infura_id, string $filtered_infura_network, $user, string $filtered_rpc_url ): string { $default_role = get_option( 'default_role' ); $options = get_option( 'wp_rainbow_options', [ 'wp_rainbow_field_default_user_role' => '' ] ); @@ -140,7 +141,7 @@ public function get_role_for_address_filtered( string $address, string $filtered } /** - * Filter the default role for WP Rainbow users. + * Legacy filter for the default role for WP Rainbow users. * * @param string $default Default role for new users. * @param string $address Address of user being added. @@ -148,7 +149,17 @@ public function get_role_for_address_filtered( string $address, string $filtered * @param string $filtered_infura_network Filtered Infura network. * @param WP_User|false $user User object, if available. */ - return apply_filters( 'wp_rainbow_role_for_address', $default_role, $address, $filtered_infura_id, $filtered_infura_network, $user ); + $legacy_filtered_role = apply_filters( 'wp_rainbow_role_for_address', $default_role, $address, $filtered_infura_id, $filtered_infura_network, $user ); + + /** + * Filter the default role for WP Rainbow users. + * + * @param string $default Default role for new users. + * @param string $address Address of user being added. + * @param string $filtered_rpc_url Filtered RPC URL. + * @param WP_User|false $user User object, if available. + */ + return apply_filters( 'wp_rainbow_role', $legacy_filtered_role, $address, $filtered_rpc_url, $user ); } // API ROUTES. @@ -291,12 +302,13 @@ public function login_callback( WP_REST_Request $request ): WP_REST_Response { $wp_rainbow = WP_Rainbow::instance(); $filtered_infura_id = $wp_rainbow->get_infura_id_filtered(); $filtered_infura_network = $wp_rainbow->get_infura_network_filtered(); + $filtered_rpc_url = $wp_rainbow->get_rpc_url(); if ( ! empty( $wp_rainbow_options['wp_rainbow_field_required_token'] ) && ! empty( $filtered_infura_id ) && ! empty( $filtered_infura_network ) ) { // @TODO Figure out if ABI should be an option (or formatted differently). $example_abi = '[{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]'; - $contract = new Contract( 'https://' . map_filtered_network_to_infura_endpoint( $filtered_infura_network ) . '.infura.io/v3/' . $filtered_infura_id, $example_abi ); + $contract = new Contract( 'https://' . wp_rainbow_map_filtered_network_to_infura_endpoint( $filtered_infura_network ) . '.infura.io/v3/' . $filtered_infura_id, $example_abi ); $contract->at( $wp_rainbow_options['wp_rainbow_field_required_token'] )->call( 'balanceOf', $address, @@ -311,7 +323,7 @@ function ( $err, $balance ) use ( $wp_rainbow_options ) { // Lookup or generate user and then sign them in. $user = get_user_by( 'login', $address ); $sanitized_display_name = sanitize_text_field( $display_name ); - $role = $this->get_role_for_address_filtered( $address, $filtered_infura_id, $filtered_infura_network, $user ); + $role = $this->get_role_for_address_filtered( $address, $filtered_infura_id, $filtered_infura_network, $user, $filtered_rpc_url ); $should_set_role = $this->get_should_set_role_filtered(); if ( ! $user ) { diff --git a/inc/class-wp-rainbow-login-styling.php b/inc/class-wp-rainbow-login-styling.php index b734b82..de99cb6 100644 --- a/inc/class-wp-rainbow-login-styling.php +++ b/inc/class-wp-rainbow-login-styling.php @@ -92,6 +92,7 @@ public function action_login_head() { } #wp-rainbow-button div[role="button"] { + padding: 0 18px; text-align: center; width: 100%; } diff --git a/inc/class-wp-rainbow-settings.php b/inc/class-wp-rainbow-settings.php index d98bd87..54da552 100644 --- a/inc/class-wp-rainbow-settings.php +++ b/inc/class-wp-rainbow-settings.php @@ -150,13 +150,22 @@ public function action_rest_api_init() { 'description' => 'Default RainbowKit Login user role', ], 'wp_rainbow_field_infura_id' => [ - 'required' => true, + 'required' => false, 'type' => 'string', 'description' => 'Infura ID field', ], - 'wp_rainbow_field_infura_network' => [ + 'wp_rainbow_field_provider' => [ 'required' => true, 'type' => 'string', + 'description' => 'RPC provider to use for RainbowKit login', + 'enum' => [ + 'infura', + 'other', + ], + ], + 'wp_rainbow_field_infura_network' => [ + 'required' => false, + 'type' => 'string', 'description' => 'Infura network', 'enum' => [ 'mainnet', @@ -170,8 +179,22 @@ public function action_rest_api_init() { 'arbitrum', 'arbitrumGoerli', 'arbitrumSepolia', + 'base', + 'baseSepolia', + 'zora', + 'zoraSepolia', ], ], + 'wp_rainbow_field_rpc_url' => [ + 'required' => false, + 'type' => 'string', + 'description' => 'RPC URL', + ], + 'wp_rainbow_field_rpc_url_mainnet' => [ + 'required' => false, + 'type' => 'string', + 'description' => 'RPC URL', + ], 'wp_rainbow_field_walletconnect_project_id' => [ 'required' => true, 'type' => 'string', diff --git a/inc/class-wp-rainbow.php b/inc/class-wp-rainbow.php index 48a50cb..b44a3d5 100644 --- a/inc/class-wp-rainbow.php +++ b/inc/class-wp-rainbow.php @@ -76,20 +76,93 @@ public function get_redirect_url_filtered() { return apply_filters( 'wp_rainbow_redirect_url', $options['wp_rainbow_field_redirect_url'] ); } + /** + * Provide filter for RPC URL. Defaults to settings page value. + * + * @return mixed|void Filtered RPC URL. + */ + public function get_rpc_url() { + $options = get_option( + 'wp_rainbow_options', + [ + 'wp_rainbow_field_provider' => '', + 'wp_rainbow_field_rpc_url' => '', + ] + ); + $rpc_url = ''; + if ( + ! empty( $options['wp_rainbow_field_provider'] ) && + 'other' === $options['wp_rainbow_field_provider'] && + ! empty( $options['wp_rainbow_field_rpc_url'] ) + ) { + $rpc_url = $options['wp_rainbow_field_rpc_url']; + } elseif ( + empty( $options['wp_rainbow_field_provider'] ) || + 'infura' === $options['wp_rainbow_field_provider'] + ) { + $infura_network = $this->get_infura_network_filtered(); + $infura_id = $this->get_infura_id_filtered(); + $rpc_url = 'https://' . wp_rainbow_map_filtered_network_to_infura_endpoint( $infura_network ) . '.infura.io/v3/' . $infura_id; + } + + /** + * Filter the RPC URL used for WP Rainbow integration. + * + * @param string $default RPC URL as set in WP Rainbow options or derived from Infura ID. + */ + return apply_filters( 'wp_rainbow_rpc_url', $rpc_url ); + } + + /** + * Provide filter for mainnet RPC URL. Defaults to settings page value. + * + * @return mixed|void Filtered RPC URL for mainnet. + */ + public function get_rpc_url_mainnet() { + $options = get_option( + 'wp_rainbow_options', + [ + 'wp_rainbow_field_provider' => '', + 'wp_rainbow_field_rpc_url_mainnet' => '', + ] + ); + $rpc_url_mainnet = ''; + if ( + ! empty( $options['wp_rainbow_field_provider'] ) && + 'other' === $options['wp_rainbow_field_provider'] && + ! empty( $options['wp_rainbow_field_rpc_url_mainnet'] ) + ) { + $rpc_url_mainnet = $options['wp_rainbow_field_rpc_url_mainnet']; + } elseif ( + empty( $options['wp_rainbow_field_provider'] ) || + 'infura' === $options['wp_rainbow_field_provider'] + ) { + $infura_id = $this->get_infura_id_filtered(); + $rpc_url_mainnet = 'https://mainnet.infura.io/v3/' . $infura_id; + } + + /** + * Filter the mainnet RPC URL used for WP Rainbow integration. + * + * @param string $default Mainnet RPC URL as set in WP Rainbow options or derived from Infura ID. + */ + return apply_filters( 'wp_rainbow_rpc_url_mainnet', $rpc_url_mainnet ); + } + /** * Provide filter for Infura ID. Defaults to settings page value. * * @return mixed|void Filtered Infura ID. */ public function get_infura_id_filtered() { - $options = get_option( 'wp_rainbow_options', [ 'wp_rainbow_field_infura_id' => '' ] ); - + $options = get_option( 'wp_rainbow_options', [ 'wp_rainbow_field_infura_id' => '' ] ); + $infura_id = $options['wp_rainbow_field_infura_id'] ?? ''; /** * Filter the Infura ID used for WP Rainbow integration. * * @param string $default Infura ID as set in WP Rainbow options. */ - return apply_filters( 'wp_rainbow_infura_id', $options['wp_rainbow_field_infura_id'] ); + return apply_filters( 'wp_rainbow_infura_id', $infura_id ); } /** @@ -235,7 +308,8 @@ public function action_init() { 'wpRainbowData', [ 'ADMIN_URL' => get_admin_url(), - 'INFURA_ID' => esc_textarea( $this->get_infura_id_filtered() ), + 'RPC_URL' => esc_textarea( $this->get_rpc_url() ), + 'RPC_URL_MAINNET' => esc_textarea( $this->get_rpc_url_mainnet() ), 'LOGIN_API' => get_rest_url( null, 'wp-rainbow/v1/login' ), 'NONCE_API' => get_rest_url( null, 'wp-rainbow/v1/nonce' ), 'REDIRECT_URL' => esc_url( $this->get_redirect_url_filtered() ), @@ -253,7 +327,8 @@ public function action_init() { 'wpRainbowData', [ 'ADMIN_URL' => get_admin_url(), - 'INFURA_ID' => esc_textarea( $this->get_infura_id_filtered() ), + 'RPC_URL' => esc_textarea( $this->get_rpc_url() ), + 'RPC_URL_MAINNET' => esc_textarea( $this->get_rpc_url_mainnet() ), 'LOGIN_API' => get_rest_url( null, 'wp-rainbow/v1/login' ), 'LOGGED_IN' => is_user_logged_in(), 'NONCE_API' => get_rest_url( null, 'wp-rainbow/v1/nonce' ), @@ -353,7 +428,8 @@ public function action_login_enqueue_scripts() { 'wpRainbowData', [ 'ADMIN_URL' => get_admin_url(), - 'INFURA_ID' => esc_textarea( $this->get_infura_id_filtered() ), + 'RPC_URL' => esc_textarea( $this->get_rpc_url() ), + 'RPC_URL_MAINNET' => esc_textarea( $this->get_rpc_url_mainnet() ), 'LOGIN_API' => get_rest_url( null, 'wp-rainbow/v1/login' ), 'NONCE_API' => get_rest_url( null, 'wp-rainbow/v1/nonce' ), 'REDIRECT_URL' => esc_url( $this->get_redirect_url_filtered() ), diff --git a/inc/functions.php b/inc/functions.php index f35b2c6..87faeae 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1,4 +1,10 @@ 'arbitrum-mainnet', - 'arbitrumGoerli' => 'arbitrum-goerli', - 'arbitrumSepolia' => 'arbitrum-sepolia', - 'optimism' => 'optimism-mainnet', - 'optimismGoerli' => 'optimism-goerli', - 'optimismSepolia' => 'optimism-sepolia', - 'polygon' => 'polygon-mainnet', - 'polygonMumbai' => 'polygon-mumbai', - ]; - if ( ! empty( $overrides[ $filtered_network ] ) ) { - return $overrides[ $filtered_network ]; - } +function wp_rainbow_map_filtered_network_to_infura_endpoint( string $filtered_network ): string { + $overrides = [ + 'arbitrum' => 'arbitrum-mainnet', + 'arbitrumGoerli' => 'arbitrum-goerli', + 'arbitrumSepolia' => 'arbitrum-sepolia', + 'optimism' => 'optimism-mainnet', + 'optimismGoerli' => 'optimism-goerli', + 'optimismSepolia' => 'optimism-sepolia', + 'polygon' => 'polygon-mainnet', + 'polygonMumbai' => 'polygon-mumbai', + ]; + if ( ! empty( $overrides[ $filtered_network ] ) ) { + return $overrides[ $filtered_network ]; + } - return $filtered_network; + return $filtered_network; } diff --git a/package.json b/package.json index d758d3f..b8d1eba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wp-rainbow", - "version": "0.4.6", + "version": "0.5.0", "description": "RainbowKit Login (Web3 Integration for Sign-In With Ethereum)", "author": "Davis Shaver", "license": "GPL-2.0-or-later", @@ -21,31 +21,31 @@ "url": "https://github.com/davisshaver/wp-rainbow/issues" }, "dependencies": { - "@rainbow-me/rainbowkit": "^1.3.0", - "@wordpress/block-editor": "^12.14.0", - "@wordpress/blocks": "^12.23.0", - "@wordpress/components": "^25.12.0", - "@wordpress/i18n": "^4.46.0", - "classnames": "^2.3.2", - "ethers": "^6.8.1", + "@rainbow-me/rainbowkit": "^2.0.6", + "@tanstack/react-query": "^5.34.2", + "@wordpress/block-editor": "^12.25.0", + "@wordpress/blocks": "^12.34.0", + "@wordpress/components": "^27.4.0", + "@wordpress/i18n": "^4.57.0", + "classnames": "^2.5.1", "process": "^0.11.10", "prop-types": "^15.8.1", - "react-hook-form": "^7.48.2", + "react-hook-form": "^7.51.4", "react-style-proptype": "^3.2.2", - "siwe": "^2.1.4", + "simple-siwe": "^0.1.4", "util": "^0.12.5", - "viem": "^1.19.9", - "wagmi": "^1.4.7" + "viem": "^2.9.31", + "wagmi": "^2.8.1" }, "devDependencies": { - "@babel/preset-react": "^7.23.3", - "@wordpress/eslint-plugin": "^17.3.0", - "@wordpress/scripts": "^26.17.0", - "css-loader": "^6.8.1", + "@babel/preset-react": "^7.24.1", + "@wordpress/eslint-plugin": "^17.13.0", + "@wordpress/scripts": "^27.8.0", + "css-loader": "^7.1.1", "eslint-config-airbnb": "^19.0.4", - "style-loader": "^3.3.3", - "webpack": "^5.89.0", - "webpack-bundle-analyzer": "^4.10.1", + "style-loader": "^3.3.4", + "webpack": "^5.91.0", + "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4" }, "scripts": { diff --git a/plugins/class-wp-rainbow-plugins-erc-1155-roles.php b/plugins/class-wp-rainbow-plugins-erc-1155-roles.php index b9953b8..caf7fa9 100644 --- a/plugins/class-wp-rainbow-plugins-erc-1155-roles.php +++ b/plugins/class-wp-rainbow-plugins-erc-1155-roles.php @@ -41,7 +41,7 @@ public static function instance(): WP_Rainbow_Plugins_ERC_1155_Roles { * Setup instance. */ protected function setup() { - add_filter( 'wp_rainbow_role_for_address', [ self::$instance, 'filter_wp_rainbow_role_for_address' ], 10, 5 ); + add_filter( 'wp_rainbow_role', [ self::$instance, 'filter_wp_rainbow_role' ], 10, 5 ); } /** @@ -49,20 +49,19 @@ protected function setup() { * * @param string $default_role Role used as fallback. * @param string $address Address for determining role. - * @param string $filtered_infura_id Infura ID to use for contract calls. - * @param string $filtered_infura_network Infura network to use for contract calls. + * @param string $filtered_rpc_url Filtered RPC URL to use. * @param WP_User|false $user WordPress user if available. * * @return string Filtered WP Rainbow role. * @throws Exception Throws if user does not hold valid tokens. */ - public function filter_wp_rainbow_role_for_address( string $default_role, string $address, string $filtered_infura_id, string $filtered_infura_network, $user ): string { - if ( empty( $filtered_infura_id ) || empty( $filtered_infura_network ) ) { + public function filter_wp_rainbow_role( string $default_role, string $address, string $filtered_rpc_url, $user ): string { + if ( empty( $filtered_rpc_url ) ) { return $default_role; } $erc1155_abi = '[{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]'; $erc1155_role = ''; - $contract = new Contract( 'https://' . map_filtered_network_to_infura_endpoint( $filtered_infura_network ) . '.infura.io/v3/' . $filtered_infura_id, $erc1155_abi ); + $contract = new Contract( $filtered_rpc_url, $erc1155_abi ); $wp_rainbow_options = get_option( 'wp_rainbow_options', [ diff --git a/readme.md b/readme.md index 4b9eef9..82f5bf6 100644 --- a/readme.md +++ b/readme.md @@ -56,6 +56,10 @@ Find reference implementations of all filters in [example plugin here](https://g **`wp_rainbow_should_update_roles`** - Filter whether roles should be set. +**`wp_rainbow_rpc_url`** - Filter RPC URL to override settings value. + +**`wp_rainbow_rpc_url_mainnet`** - Filter mainnet RPC URL to override settings value. + **`wp_rainbow_infura_id`** - Filter Infura ID to override settings value. **`wp_rainbow_infura_network`** - Filter Infura network to override settings value. diff --git a/readme.txt b/readme.txt index 20c7297..1638ee9 100644 --- a/readme.txt +++ b/readme.txt @@ -1,7 +1,7 @@ === RainbowKit Login (Web3 Integration for Sign-In With Ethereum) === Contributors: davisshaver Tags: WordPress, web3, SIWE, Ethereum, RainbowKit, Sign-In With Ethereum -Tested up to: 6.4.3 +Tested up to: 6.5.2 Requires at least: 5.9 Requires PHP: 7.0 Stable tag: 0.4.6 @@ -70,6 +70,12 @@ Find reference implementations of all filters in [example plugin here](https://g == Changelog == += 0.5.0 = +* Add support for custom RPC URLs and Base/Zora networks +* Add helper classnames to buttons for additional style customization +* Switch from SIWE to simple-siwe for smaller bundle size +* Add basic validations of settings before save + = 0.4.6 = * Fix bug with Infura endpoint mapping diff --git a/src/connect.jsx b/src/connect.jsx index d94eb82..dd012fc 100644 --- a/src/connect.jsx +++ b/src/connect.jsx @@ -5,11 +5,11 @@ import { useDisconnect, useEnsName, usePublicClient, - useNetwork, useSignMessage, + useConnections, } from 'wagmi'; import stylePropType from 'react-style-proptype'; -import { SiweMessage } from 'siwe'; +import { prepareMessage } from 'simple-siwe'; import PropTypes from 'prop-types'; const { @@ -58,19 +58,19 @@ export function WPRainbowConnect( { style, } ) { const [ state, setState ] = React.useState( {} ); - const { address, connector: activeConnector } = useAccount(); - const { chain } = useNetwork(); + const { address, chain, connector: activeConnector } = useAccount(); const { signMessageAsync } = useSignMessage(); const { data: ensName, isSuccess: isENSSuccess } = useEnsName( { address, chainId: 1, } ); + const connections = useConnections(); const provider = usePublicClient( { chainId: 1, } ); - const { disconnectAsync } = useDisconnect(); + const { disconnect, disconnectAsync } = useDisconnect(); const signIn = React.useCallback( async () => { try { @@ -81,7 +81,7 @@ export function WPRainbowConnect( { setState( ( x ) => ( { ...x, address, loading: false } ) ); return; } - if ( window?.signingIn.length > 1 ) { + if ( window.signingIn && window.signingIn.length > 1 ) { return; } setState( ( x ) => ( { ...x, error: undefined, loading: true } ) ); @@ -97,7 +97,7 @@ export function WPRainbowConnect( { uri: window.location.origin, version: '1', }; - const message = new SiweMessage( siwePayload ); + const message = prepareMessage( siwePayload ); const attributes = {}; if ( ensName ) { try { @@ -114,7 +114,7 @@ export function WPRainbowConnect( { } } const signature = await signMessageAsync( { - message: message.prepareMessage(), + message, } ); if ( mockLogin ) { setState( ( x ) => ( { ...x, address, loading: false } ) ); @@ -149,12 +149,47 @@ export function WPRainbowConnect( { setState( ( x ) => ( { ...x, error, loading: false } ) ); } } catch ( error ) { + console.error( error ); setState( ( x ) => ( { ...x, error, loading: false } ) ); } }, [ address, chain, ensName ] ); const [ triggeredLogin, setTriggeredLogin ] = React.useState( false ); React.useEffect( () => { + const urlParams = new URLSearchParams( window.location.search ); + // This code is NUTS but Metamask doesn't support disconnecting apparently? + // Keep an eye on these issues: + // - https://github.com/wevm/wagmi/issues/684 + // - https://github.com/MetaMask/metamask-extension/issues/10353 + if ( + activeConnector && + activeConnector.id.includes( 'metamask' ) && + ! triggeredLogin && + ( urlParams.has( 'wp-rainbow-logout' ) || + ( urlParams.has( 'loggedout' ) && + ! urlParams.has( 'wp-rainbow-loggedout' ) ) ) + ) { + connections.forEach( ( { connector } ) => { + disconnect( { connector } ); + } ); + // Remove the query parameter from the URL. + if ( urlParams.has( 'wp-rainbow-logout' ) ) { + urlParams.delete( 'wp-rainbow-logout' ); + } + if ( urlParams.has( 'loggedout' ) ) { + urlParams.append( 'wp-rainbow-loggedout', 'true' ); + } + const paramsString = urlParams.toString(); + // Set the new URL without the query parameter. + window.history.replaceState( + {}, + document.title, + `${ window.location.pathname }${ + paramsString ? `?${ paramsString }` : '' + }` + ); + return; + } if ( activeConnector && address && isENSSuccess && ! triggeredLogin ) { window.signingIn = ! window.signingIn ? [ true ] @@ -162,6 +197,9 @@ export function WPRainbowConnect( { signIn(); setTriggeredLogin( true ); } else if ( ! address && state.address && ! window.signingOut ) { + connections.forEach( ( { connector } ) => { + disconnect( { connector } ); + } ); window.signingOut = true; setState( {} ); setTriggeredLogin( false ); @@ -176,6 +214,20 @@ export function WPRainbowConnect( { } }, [ address, isENSSuccess, state.address ] ); + const buttonClassNameWithState = React.useMemo( () => { + let buttonClassNameEnriched = buttonClassName; + if ( LOGGED_IN ) { + buttonClassNameEnriched += ' wpr-logged-in'; + } + if ( state.loading ) { + buttonClassNameEnriched += ' wpr-signing-in'; + } + if ( state.error ) { + buttonClassNameEnriched += ' wpr-error'; + } + return buttonClassNameEnriched; + }, [ buttonClassName, state.error, state.loading ] ); + return ( { ( { account, openAccountModal, openConnectModal } ) => { @@ -183,7 +235,7 @@ export function WPRainbowConnect( { if ( state.error ) { button = (
{ window.location = window.location.href; } } @@ -223,7 +275,7 @@ export function WPRainbowConnect( { }; button = (
{ if ( e.keyCode === 13 ) { @@ -248,7 +300,7 @@ export function WPRainbowConnect( { }; button = (
{ triggerLogin(); } } diff --git a/src/provider.jsx b/src/provider.jsx index 5b002e6..5db2d2b 100644 --- a/src/provider.jsx +++ b/src/provider.jsx @@ -3,16 +3,10 @@ import { lightTheme, darkTheme, midnightTheme, - connectorsForWallets, + getDefaultConfig, } from '@rainbow-me/rainbowkit'; -import { - metaMaskWallet, - rainbowWallet, - walletConnectWallet, - injectedWallet, - coinbaseWallet, -} from '@rainbow-me/rainbowkit/wallets'; -import { createConfig, configureChains, WagmiConfig } from 'wagmi'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { http, WagmiProvider } from 'wagmi'; import { arbitrum, arbitrumGoerli, @@ -25,10 +19,12 @@ import { polygon, polygonMumbai, sepolia, + base, + baseSepolia, + zora, + zoraSepolia, } from 'wagmi/chains'; -import { infuraProvider } from 'wagmi/providers/infura'; import stylePropType from 'react-style-proptype'; -import { publicProvider } from 'wagmi/providers/public'; import PropTypes from 'prop-types'; import { WPRainbowConnect } from './connect'; @@ -36,9 +32,10 @@ import { WPRainbowConnect } from './connect'; const { COMPACT_MODAL, COOL_MODE, - INFURA_ID, LOGGED_IN, NETWORK, + RPC_URL, + RPC_URL_MAINNET, SITE_TITLE, THEME, WALLETCONNECT_PROJECT_ID, @@ -62,40 +59,35 @@ const allChains = { polygon, polygonMumbai, sepolia, + base, + baseSepolia, + zora, + zoraSepolia, }; -const { chains, publicClient } = configureChains( - [ - ...( NETWORK && allChains[ NETWORK ] ? [ allChains[ NETWORK ] ] : [] ), - allChains.mainnet, - ], - [ infuraProvider( { apiKey: INFURA_ID } ), publicProvider() ] -); - -const wallets = [ - { - groupName: 'Popular', - wallets: [ - injectedWallet( { chains } ), - rainbowWallet( { chains, projectId: WALLETCONNECT_PROJECT_ID } ), - coinbaseWallet( { appName: SITE_TITLE, chains } ), - metaMaskWallet( { chains, projectId: WALLETCONNECT_PROJECT_ID } ), - walletConnectWallet( { - chains, - projectId: WALLETCONNECT_PROJECT_ID, - } ), - ], - }, -]; +const chains = + NETWORK && allChains[ NETWORK ] && NETWORK !== 'mainnet' + ? [ allChains[ NETWORK ], mainnet ] + : [ mainnet ]; -const connectors = connectorsForWallets( wallets ); - -const wagmiConfig = createConfig( { - autoConnect: LOGGED_IN === '1', - connectors, - publicClient, +const transports = + NETWORK && allChains[ NETWORK ] && NETWORK !== 'mainnet' + ? { + [ allChains[ NETWORK ] ]: http( RPC_URL ), + [ mainnet.id ]: http( RPC_URL_MAINNET ), + } + : { + [ mainnet.id ]: http( RPC_URL_MAINNET ), + }; +const wagmiConfig = getDefaultConfig( { + appName: SITE_TITLE, + chains, + projectId: WALLETCONNECT_PROJECT_ID, + transports, } ); +const queryClient = new QueryClient(); + /** * WP Rainbow Provider. * @@ -132,31 +124,35 @@ function WPRainbow( { style, } ) { return ( - - - - - + + + + + + + ); } diff --git a/src/settings.jsx b/src/settings.jsx index ae0d2a2..0397b1e 100644 --- a/src/settings.jsx +++ b/src/settings.jsx @@ -5,16 +5,20 @@ import { Spinner } from '@wordpress/components'; import { useForm, useFieldArray } from 'react-hook-form'; function WPRainbowSettings() { - const { control, register, handleSubmit, watch, setValue } = useForm(); + const { + control, + register, + handleSubmit, + watch, + setValue, + formState: { errors }, + } = useForm( { + criteriaMode: 'all', + } ); const { fields, append, remove } = useFieldArray( { control, name: 'userAttributesMapping', } ); - const setUserRoles = watch( 'wp_rainbow_field_set_user_roles' ); - const infuraId = watch( 'wp_rainbow_field_infura_id' ); - const walletConnectProjectID = watch( - 'wp_rainbow_field_walletconnect_project_id' - ); const { fields: erc1155Fields, append: erc1155FieldsAppend, @@ -166,12 +170,27 @@ function WPRainbowSettings() {
); } + + const setUserRoles = watch( + 'wp_rainbow_field_set_user_roles', + initialSettings?.wp_rainbow_field_set_user_roles + ); + const provider = watch( + 'wp_rainbow_field_provider', + initialSettings?.wp_rainbow_field_provider ?? 'infura' + ); + const network = watch( + 'wp_rainbow_field_infura_network', + initialSettings?.wp_rainbow_field_infura_network ?? 'mainnet' + ); + const walletConnectProjectID = watch( + 'wp_rainbow_field_walletconnect_project_id', + initialSettings?.wp_rainbow_field_walletconnect_project_id ?? '' + ); return (

{ __( 'RainbowKit Login Settings', 'wp-rainbow' ) }

- { ( infuraId === '' || - ( infuraId === undefined && - ! initialSettings?.wp_rainbow_field_infura_id ) ) && ( + { Object.keys( errors ).length > 0 && (
{ __( - 'Infura ID is not set. Token-gating and ENS integrations will not work. Users will be assigned the default role.', + 'There was an error validating your settings and they were not saved. Please review the form and try again.', 'wp-rainbow' ) } @@ -233,60 +252,58 @@ function WPRainbowSettings() { -