diff --git a/configs/envs/.env.facet b/configs/envs/.env.facet new file mode 100644 index 0000000000..94a7374fcb --- /dev/null +++ b/configs/envs/.env.facet @@ -0,0 +1,48 @@ +# Local ENVs +NEXT_PUBLIC_APP_PROTOCOL=http +NEXT_PUBLIC_APP_HOST=localhost +NEXT_PUBLIC_APP_PORT=3000 +NEXT_PUBLIC_APP_ENV=development +NEXT_PUBLIC_API_WEBSOCKET_PROTOCOL=ws +NEXT_PUBLIC_IS_TESTNET=false + +# Instance ENVs +NEXT_PUBLIC_ADMIN_SERVICE_API_HOST=https://admin-rs.services.blockscout.com +NEXT_PUBLIC_API_BASE_PATH=/ +NEXT_PUBLIC_API_HOST=explorer.facet.org +NEXT_PUBLIC_API_SPEC_URL=https://raw.githubusercontent.com/blockscout/blockscout-api-v2-swagger/main/swagger.yaml +NEXT_PUBLIC_CONTRACT_CODE_IDES=[{'title':'Remix IDE','url':'https://remix.ethereum.org/?address={hash}&blockscout={domain}','icon_url':'https://raw.githubusercontent.com/blockscout/frontend-configs/main/configs/ide-icons/remix.png'}] +NEXT_PUBLIC_CONTRACT_INFO_API_HOST=https://contracts-info.services.blockscout.com +NEXT_PUBLIC_HAS_CONTRACT_AUDIT_REPORTS=true +NEXT_PUBLIC_HAS_USER_OPS=true +NEXT_PUBLIC_HIDE_INDEXING_ALERT_INT_TXS=true +NEXT_PUBLIC_HOMEPAGE_CHARTS=['daily_txs'] +NEXT_PUBLIC_HOMEPAGE_HERO_BANNER_CONFIG={'background':['url(https://facetswap.com/halftone_1.svg) center center / cover no-repeat, rgba(121,94,228,1)'],'text_color':['white'],'button':{'_default':{'background':['rgba(195,255,0,1)'],'text_color':['black']},'_hover':{'background':['rgba(219,255,102,1)'],'text_color':['black']}}} +NEXT_PUBLIC_METADATA_SERVICE_API_HOST=https://metadata.services.blockscout.com +NEXT_PUBLIC_METASUITES_ENABLED=true +NEXT_PUBLIC_NAME_SERVICE_API_HOST=https://bens.services.blockscout.com +NEXT_PUBLIC_NETWORK_CURRENCY_DECIMALS=18 +NEXT_PUBLIC_NETWORK_CURRENCY_NAME=Facet Compute Token +NEXT_PUBLIC_NETWORK_CURRENCY_SYMBOL=FCT +NEXT_PUBLIC_NETWORK_ICON=https://facet.org/facet-logo-black.svg +NEXT_PUBLIC_NETWORK_ID=1027303 +NEXT_PUBLIC_NETWORK_LOGO=https://facet.org/facet-logo-and-name-black.svg +NEXT_PUBLIC_NETWORK_NAME=Facet Mainnet +NEXT_PUBLIC_NETWORK_RPC_URL=https://mainnet.facet.org/ +NEXT_PUBLIC_NETWORK_SHORT_NAME=Mainnet +NEXT_PUBLIC_NETWORK_VERIFICATION_TYPE=validation +NEXT_PUBLIC_OG_ENHANCED_DATA_ENABLED=true +NEXT_PUBLIC_OG_IMAGE_URL=https://facet.org/facet-social.png +NEXT_PUBLIC_ROLLUP_PARENT_CHAIN={'baseUrl':'https://eth.blockscout.com','currency':{'name':'Ether','symbol':'ETH','decimals':18},'isTestnet':false,'id':1,'name':'Ethereum Mainnet','rpcUrls':['https://ethereum-rpc.publicnode.com']} +NEXT_PUBLIC_ROLLUP_L1_BASE_URL=https://eth.blockscout.com +NEXT_PUBLIC_ROLLUP_PARENT_CHAIN_NAME=Ethereum +NEXT_PUBLIC_ROLLUP_TYPE=optimistic +NEXT_PUBLIC_ROLLUP_STAGE_INDEX=2 +NEXT_PUBLIC_STATS_API_BASE_PATH=/stats-service +NEXT_PUBLIC_STATS_API_HOST=https://explorer.facet.org +NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=blockscout +NEXT_PUBLIC_VIEWS_ADDRESS_IDENTICON_TYPE=gradient_avatar +NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true +NEXT_PUBLIC_VIEWS_NFT_MARKETPLACES=[{'name':'Facet NFT','collection_url':'https://facetnft.com/collection/{hash}','instance_url':'https://facetnft.com/asset/{hash}/{id}','logo_url':'https://facet.org/facet-social.png'}] +NEXT_PUBLIC_VIEWS_TOKEN_SCAM_TOGGLE_ENABLED=true +NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com \ No newline at end of file diff --git a/next.config.js b/next.config.js index 8f60e3b2b4..21973d913f 100644 --- a/next.config.js +++ b/next.config.js @@ -13,6 +13,7 @@ const rewrites = require('./nextjs/rewrites'); /** @type {import('next').NextConfig} */ const moduleExports = { transpilePackages: [ + '@0xfacet/sdk', 'react-syntax-highlighter', ], reactStrictMode: true, diff --git a/package.json b/package.json index 1621a5e521..7460259466 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "postinstall": "chakra typegen ./toolkit/theme/theme.ts" }, "dependencies": { + "@0xfacet/sdk": "^0.4.12", "@bigmi/react": "0.5.2", "@blockscout/bens-types": "1.4.1", "@blockscout/multichain-aggregator-types": "1.6.3-alpha.3", @@ -130,6 +131,7 @@ "react-number-format": "^5.3.1", "react-scroll": "^1.8.7", "rollbar": "2.26.5", + "solady": "^0.1.26", "swagger-ui-react": "5.28.0", "use-font-face-observer": "^1.3.0", "valibot": "0.38.0", diff --git a/ui/address/contract/methods/useCallMethodWalletClient.ts b/ui/address/contract/methods/useCallMethodWalletClient.ts index a7c50a0c49..bef253ca8c 100644 --- a/ui/address/contract/methods/useCallMethodWalletClient.ts +++ b/ui/address/contract/methods/useCallMethodWalletClient.ts @@ -1,3 +1,4 @@ +import { facetMainnet, facetSepolia, sendFacetTransaction, writeFacetContract } from '@0xfacet/sdk'; import React from 'react'; import { getAddress, type Abi } from 'viem'; import { useAccount, useWalletClient, useSwitchChain } from 'wagmi'; @@ -18,9 +19,13 @@ interface Params { export default function useCallMethodWalletClient(): (params: Params) => Promise { const multichainContext = useMultichainContext(); - const chainConfig = (multichainContext?.chain.app_config ?? config).chain; + const chainConfig = multichainContext?.chain.app_config ?? config; + const isFacetChain = chainConfig.chain.id === String(facetMainnet.id) || chainConfig.chain.id === String(facetSepolia.id); + const rollupFeature = chainConfig.features.rollup; + const parentChain = rollupFeature.isEnabled ? rollupFeature.parentChain : undefined; + const targetChainId = isFacetChain && parentChain ? Number(parentChain.id) : Number(chainConfig.chain.id); - const { data: walletClient } = useWalletClient({ chainId: Number(chainConfig?.id) }); + const { data: walletClient } = useWalletClient({ chainId: targetChainId }); const { isConnected, chainId, address: account } = useAccount(); const { switchChainAsync } = useSwitchChain(); const { trackTransaction, trackTransactionConfirm } = useRewardsActivity(); @@ -34,8 +39,12 @@ export default function useCallMethodWalletClient(): (params: Params) => Promise throw new Error('Wallet Client is not defined'); } - if (chainId && String(chainId) !== chainConfig?.id) { - await switchChainAsync({ chainId: Number(chainConfig?.id) }); + if (chainId && chainId !== targetChainId) { + await switchChainAsync({ chainId: targetChainId }); + } + + if (walletClient.chain?.id !== targetChainId) { + await walletClient.switchChain({ id: targetChainId }); } const address = getAddress(addressHash); @@ -50,11 +59,16 @@ export default function useCallMethodWalletClient(): (params: Params) => Promise // if the fallback method acts as a read method, it can only have one input of type bytes // so we pass the input value as data without encoding it const data = typeof _args[0] === 'string' && _args[0].startsWith('0x') ? _args[0] as `0x${ string }` : undefined; - const hash = await walletClient.sendTransaction({ + + const txRequest = { to: address, value, ...(data ? { data } : {}), - }); + } as const; + + const hash = isFacetChain ? + await sendFacetTransaction(walletClient, txRequest) : + await walletClient.sendTransaction(txRequest); if (activityResponse?.token) { await trackTransactionConfirm(hash, activityResponse.token); @@ -69,7 +83,7 @@ export default function useCallMethodWalletClient(): (params: Params) => Promise throw new Error('Method name is not defined'); } - const hash = await walletClient.writeContract({ + const writeRequest = { args: _args, // Here we provide the ABI as an array containing only one item from the submitted form. // This is a workaround for the issue with the "viem" library. @@ -83,12 +97,16 @@ export default function useCallMethodWalletClient(): (params: Params) => Promise address, value, account, - }); + } as const; + + const hash = isFacetChain ? + await writeFacetContract(walletClient, writeRequest) : + await walletClient.writeContract(writeRequest); if (activityResponse?.token) { await trackTransactionConfirm(hash, activityResponse.token); } return { source: 'wallet_client', data: { hash } }; - }, [ chainId, chainConfig, isConnected, switchChainAsync, walletClient, account, trackTransaction, trackTransactionConfirm ]); + }, [ isConnected, walletClient, chainId, targetChainId, trackTransaction, account, isFacetChain, switchChainAsync, trackTransactionConfirm ]); } diff --git a/yarn.lock b/yarn.lock index c670cbcde8..a97d4418d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,6 +15,11 @@ "@gql.tada/internal" "^1.0.0" graphql "^15.5.0 || ^16.0.0 || ^17.0.0" +"@0xfacet/sdk@^0.4.12": + version "0.4.12" + resolved "https://registry.yarnpkg.com/@0xfacet/sdk/-/sdk-0.4.12.tgz#b588430291f596926e25f801266c890e41deb36b" + integrity sha512-FQIOnlukTeOI25XfwLhOVu8/Kh4eLsJOmb8RnY+oA3QRwhLXPR7l9IYgO0NCtvkwyZYOcIItscYIirCw7QZ0fQ== + "@achingbrain/http-parser-js@^0.5.8": version "0.5.9" resolved "https://registry.yarnpkg.com/@achingbrain/http-parser-js/-/http-parser-js-0.5.9.tgz#708aab4a46f7369f9f33d2a836fb37f5027f0038" @@ -20119,6 +20124,11 @@ socket.io-parser@~4.2.4: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" +solady@^0.1.26: + version "0.1.26" + resolved "https://registry.yarnpkg.com/solady/-/solady-0.1.26.tgz#80b4d621cfdbd82b772c5c701877d2f0ca12736f" + integrity sha512-dhGr/ptJFdea/1KE6xgqgwEdbMhUiSfRc6A+jLeltPe16zyt9qtED3PElIBVRnzEmUO5aZTjKVAr6SlqXBBcIw== + sonic-boom@^2.2.1: version "2.8.0" resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-2.8.0.tgz#c1def62a77425090e6ad7516aad8eb402e047611" @@ -20270,16 +20280,7 @@ string-template@~0.2.1: resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" integrity sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -20424,14 +20425,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -21933,7 +21927,7 @@ word-wrap@^1.2.5, word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -21951,15 +21945,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"