diff --git a/apps/playground-web/src/app/connect/in-app-wallet/page.tsx b/apps/playground-web/src/app/connect/in-app-wallet/page.tsx index 64c94b3064a..fa4b20c7039 100644 --- a/apps/playground-web/src/app/connect/in-app-wallet/page.tsx +++ b/apps/playground-web/src/app/connect/in-app-wallet/page.tsx @@ -74,7 +74,7 @@ function AnyAuth() { />
-

Custom Auth and UI

+

Custom UI

Customize the login UI and integrate with your existing user base. No limits on customizations and auth methods. @@ -85,63 +85,35 @@ function AnyAuth() {

} - code={`import { useMutation } from "@tanstack/react-query"; -import { useState } from "react"; + code={`import { useState } from "react"; import { useConnect } from "thirdweb/react"; -import { inAppWallet } from "thirdweb/wallets"; +import { inAppWallet, preAuthenticate } from "thirdweb/wallets/in-app"; -export function CustomLoginForm() { - const [email, setEmail] = useState(""); +export function CustomLoginUi() { const { connect, isConnecting, error } = useConnect(); - const { mutate: loginWithCustomAuth } = useMutation({ - mutationFn: async (email: string) => { - const wallet = await connect(async () => { - const wallet = inAppWallet(); - await wallet.connect({ - strategy: "auth_endpoint", - client, - // your own custom auth payload here - payload: JSON.stringify({ - userId: email, - email, - }), - }); - return wallet; + const preLogin = async (email: string) => { + // send email verification code + await preAuthenticate({ + client, + strategy: "email", + email, + }); + }; + + const handleLogin = async (email: string, verificationCode: string) => { + // verify email with verificationCode and connect + connect(async () => { + const wallet = inAppWallet(); + await wallet.connect({ + client, + strategy: "email", + email, + verificationCode, }); return wallet; - } - }); - - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - loginWithCustomAuth(email); + }); }; - - return ( -
-
- - setEmail(e.target.value)} - placeholder="Enter your email" - required - /> - - {error &&

{error.message}

} -
-
- ); } `} lang="tsx" diff --git a/apps/playground-web/src/components/in-app-wallet/custom-login-form.tsx b/apps/playground-web/src/components/in-app-wallet/custom-login-form.tsx index 636e16b012b..6fef2578f4f 100644 --- a/apps/playground-web/src/components/in-app-wallet/custom-login-form.tsx +++ b/apps/playground-web/src/components/in-app-wallet/custom-login-form.tsx @@ -1,45 +1,46 @@ "use client"; import { THIRDWEB_CLIENT } from "@/lib/client"; -import { useMutation } from "@tanstack/react-query"; import { useState } from "react"; import { useActiveAccount, useConnect } from "thirdweb/react"; -import { inAppWallet } from "thirdweb/wallets"; +import { inAppWallet, preAuthenticate } from "thirdweb/wallets"; import { InAppConnectEmbed } from "./connect-button"; export function CustomLoginForm() { const [email, setEmail] = useState(""); + const [verificationCode, setVerificationCode] = useState(""); + const [screen, setScreen] = useState<"login" | "verify">("login"); const { connect, isConnecting, error } = useConnect(); const account = useActiveAccount(); - const { mutate: loginWithCustomAuthEndpoint } = useMutation({ - mutationFn: async (email: string) => { - const wallet = await connect(async () => { - const wallet = inAppWallet(); - await wallet.connect({ - strategy: "auth_endpoint", - client: THIRDWEB_CLIENT, - payload: JSON.stringify({ - userId: email, - email, - }), - }); - return wallet; + const sendEmailVerificationCode = async (email: string) => { + setScreen("verify"); + await preAuthenticate({ + client: THIRDWEB_CLIENT, + strategy: "email", + email, + }); + }; + + const loginWithEmail = async (email: string, verificationCode: string) => { + connect(async () => { + const wallet = inAppWallet(); + await wallet.connect({ + strategy: "email", + client: THIRDWEB_CLIENT, + email, + verificationCode, }); return wallet; - }, - }); - - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - loginWithCustomAuthEndpoint(email); + }); }; + if (account) { return ; } - return ( -
+ if (screen === "login") { + return (
-
- ); + ); + } + + if (screen === "verify") { + return ( +
+ + setVerificationCode(e.target.value)} + className="rounded-lg border px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" + placeholder="Enter the code you received" + required + /> + + {error &&

{error.message}

} +
+ ); + } } diff --git a/apps/portal/src/app/connect/in-app-wallet/guides/build-your-own-ui/page.mdx b/apps/portal/src/app/connect/in-app-wallet/guides/build-your-own-ui/page.mdx index 636822a19a0..518afc8b401 100644 --- a/apps/portal/src/app/connect/in-app-wallet/guides/build-your-own-ui/page.mdx +++ b/apps/portal/src/app/connect/in-app-wallet/guides/build-your-own-ui/page.mdx @@ -135,9 +135,9 @@ const preLogin = async (email: string) => { }); }; -const handleLogin = async (email: string, verificationCode: string) => { +const handleLogin = (email: string, verificationCode: string) => { // verify email and connect - await connect(() => { + connect(async () => { const wallet = inAppWallet(); await wallet.connect({ client, diff --git a/apps/portal/src/app/connect/page.mdx b/apps/portal/src/app/connect/page.mdx index 5a1b1642153..fafdfaf0a9b 100644 --- a/apps/portal/src/app/connect/page.mdx +++ b/apps/portal/src/app/connect/page.mdx @@ -7,8 +7,10 @@ import { OpenSourceCard, Stack, ConnectCard, + SDKCard, Callout } from "@doc"; +import { TypeScriptIcon, ReactIcon, DotNetIcon, UnityIcon, UnrealEngineIcon } from "@/icons"; import { cn } from "@/lib/utils"; import Link from "next/link"; import { Button } from "@/components/ui/button"; @@ -36,24 +38,51 @@ Connect is the complete toolkit for connecting every user to your application. I title="Playground" href="https://playground.thirdweb.com" iconUrl="/icons/connect/intros/demo.svg" + isExternal={true} /> - {/* - */} -### With Connect, you can: + +### Quick starts + + + + + + + + + + +### With Connect, you can - **Connect to 350+ different wallet providers** with support for every EVM network - **Log in and authenticate your users** with customizable and secure [email, phone, passkeys and social login](https://portal.thirdweb.com/connect/in-app-wallet/overview) flows. @@ -82,59 +111,13 @@ Connect is the complete toolkit for connecting every user to your application. I Connect is supported on every EVM compatible chain. To view the full list, visit [thirdweb chainlist](https://thirdweb.com/chainlist). -### Templates +### Starter Kits & demos - +View all available starter kits, demos and templates on Github. - - - - - - - - - - - - - - diff --git a/apps/portal/src/app/connect/sidebar.tsx b/apps/portal/src/app/connect/sidebar.tsx index 4585f769b00..425b1d927d4 100644 --- a/apps/portal/src/app/connect/sidebar.tsx +++ b/apps/portal/src/app/connect/sidebar.tsx @@ -1,6 +1,6 @@ import type { SideBar } from "@/components/Layouts/DocLayout"; import { DotNetIcon, ReactIcon, TypeScriptIcon, UnityIcon } from "@/icons"; -import { ExternalLink, ZapIcon } from "lucide-react"; +import { ExternalLink } from "lucide-react"; import { UnrealEngineIcon } from "../../icons/sdks/UnrealEngineIcon"; // TODO: move the following two slugs to walletSlug with updated docs @@ -23,11 +23,6 @@ export const sidebar: SideBar = { name: "Why thirdweb?", href: "/connect/why-thirdweb", }, - { - name: "Quickstart", - href: "/connect/quickstart", - icon: , - }, { name: "Playground", href: "https://playground.thirdweb.com/", @@ -188,29 +183,6 @@ export const sidebar: SideBar = { name: "Sponsorship rules", href: `${aAslug}/sponsorship-rules`, }, - // { - // name: "References", - // isCollapsible: true, - // expanded: true, - // links: [ - // { - // name: "React", - // href: `/references/typescript/v5/smartWallet`, - // }, - // { - // name: "React Native", - // href: `/react-native/v0/wallets/smartwallet`, - // }, - // { - // name: "TypeScript", - // href: `/references/wallets/v2/SmartWallet`, - // }, - // { - // name: "Unity", - // href: `/unity/wallets/providers/smart-wallet`, - // }, - // ], - // }, { name: "FAQs", href: `${aAslug}/faq`, @@ -375,40 +347,42 @@ export const sidebar: SideBar = { }, ], }, + ], + }, + { separator: true }, + { + name: "API References", + isCollapsible: false, + links: [ { - name: "API References", - links: [ - { - name: "TypeScript", - href: "/typescript/v5", - icon: , - }, - { - name: "React", - href: "/react/v5", - icon: , - }, - { - name: "React Native", - href: "/react-native/v5", - icon: , - }, - { - name: "Dotnet", - href: "/dotnet", - icon: , - }, - { - name: "Unity", - href: "/unity", - icon: , - }, - { - name: "Unreal Engine", - href: "/unreal-engine", - icon: , - }, - ], + name: "TypeScript", + href: "/typescript/v5", + icon: , + }, + { + name: "React", + href: "/react/v5", + icon: , + }, + { + name: "React Native", + href: "/react-native/v5", + icon: , + }, + { + name: "Dotnet", + href: "/dotnet", + icon: , + }, + { + name: "Unity", + href: "/unity", + icon: , + }, + { + name: "Unreal Engine", + href: "/unreal-engine", + icon: , }, ], }, diff --git a/apps/portal/src/app/connect/wallet/sign-in-methods/configure/page.mdx b/apps/portal/src/app/connect/wallet/sign-in-methods/configure/page.mdx index 83c391fc50f..5277b345a98 100644 --- a/apps/portal/src/app/connect/wallet/sign-in-methods/configure/page.mdx +++ b/apps/portal/src/app/connect/wallet/sign-in-methods/configure/page.mdx @@ -113,19 +113,19 @@ Most authentication option are that straight forward. However, some options requ
- {/* */} - - - - - + + + + + ); } @@ -63,7 +37,6 @@ function Hero() { Frontend, backend, and onchain tools to build complete web3 apps — on every EVM chain.

- {/* */}
@@ -75,310 +48,61 @@ function Hero() { ); } -// function TutorialsSection() { -// return ( -//
-// - -// -// - -// - -// - -// - -// -// -//
-// ); -// } - -// function TutorialCard(props: { -// title: string; -// links: Array<{ name: string; href: string }>; -// viewAllHref: string; -// icon: LucideIcon; -// }) { -// return ( -//
-//
-// -// -// {props.title} -// -//
- -//
-// {props.links.map((link) => { -// return ( -// -// {link.name} -// -// ); -// })} -//
- -// -// View all -// -// -//
-// ); -// } - -function WalletsSection() { +function FrontendSection() { return ( -
- +
+
- - - - - - - - - - - - - - - - - - - - -
); } function ContractsSection() { return ( -
- -
- - - - - - -
- ); -} - -function EngineSection() { - return ( -
- +
+
- - - -
- ); -} - -function InsightSection() { - return ( -
- -
- - - +
); } -function NebulaSection() { +function BackendSection() { return ( -
- +
+
- - - + +
+ +
+
); } @@ -417,22 +141,3 @@ function ArticleCardIndex(props: { ); } - -/** - * This component is only for the index page - */ -function SDKCardIndex(props: { - title: string; - href: string; - icon?: React.FC<{ className?: string }>; -}) { - return ( - - {props.icon && } -

{props.title}

- - ); -} diff --git a/apps/portal/src/app/react/v5/connecting-wallets/hooks/page.mdx b/apps/portal/src/app/react/v5/connecting-wallets/hooks/page.mdx index c9beec1d651..1c643c9ac19 100644 --- a/apps/portal/src/app/react/v5/connecting-wallets/hooks/page.mdx +++ b/apps/portal/src/app/react/v5/connecting-wallets/hooks/page.mdx @@ -48,6 +48,7 @@ function Example() { You can create any wallet by id with auto completion using the [`createWallet`](/references/typescript/v5/createWallet) function. Or use one of the first party wallets like [`inAppWallet`](/references/typescript/v5/inAppWallet) or [`ecosystemWallet`](/references/typescript/v5/ecosystemWallet). + - + ## Pre Connection Hooks Use these hooks to trigger and manage wallet wallet connection within your own UI. Refer to [wallet connection hooks reference](/references/typescript/v5/useConnect) for more information. diff --git a/apps/portal/src/app/react/v5/in-app-wallet/get-started/page.mdx b/apps/portal/src/app/react/v5/in-app-wallet/get-started/page.mdx index 4d636b8966a..89db75ae7ee 100644 --- a/apps/portal/src/app/react/v5/in-app-wallet/get-started/page.mdx +++ b/apps/portal/src/app/react/v5/in-app-wallet/get-started/page.mdx @@ -13,7 +13,6 @@ import { Step } from "@doc"; import {ExternalLink} from "lucide-react"; -import ConnectWalletHero from "./connect-wallet-hero.webp"; export const metadata = createMetadata({ title: "Connect users with In-App Wallet", diff --git a/apps/portal/src/app/react/v5/sidebar.tsx b/apps/portal/src/app/react/v5/sidebar.tsx index 19a852e2f10..3b0fd08ab36 100644 --- a/apps/portal/src/app/react/v5/sidebar.tsx +++ b/apps/portal/src/app/react/v5/sidebar.tsx @@ -1,4 +1,4 @@ -import { Book, CodeIcon, ExternalLink, ZapIcon } from "lucide-react"; +import { CodeIcon, ExternalLink, ZapIcon } from "lucide-react"; import type { SideBar } from "../../../components/Layouts/DocLayout"; const slug = "/react/v5"; @@ -137,22 +137,15 @@ export const sidebar: SideBar = { isCollapsible: false, links: [ { - name: "Adapters", - links: [ - { - // TODO one guide per library - name: "Usage with other libraries", - icon: , - href: `${slug}/adapters`, - }, - ], + // TODO one guide per library + name: "Usage with other libraries", + href: `${slug}/adapters`, }, { name: "Shared Logins", links: ["SiteEmbed", "SiteLink"].map((name) => ({ name, href: `${slug}/${name}`, - icon: , })), }, ], diff --git a/apps/portal/src/app/typescript/v5/ecosystem-wallet/page.mdx b/apps/portal/src/app/typescript/v5/ecosystem-wallet/page.mdx new file mode 100644 index 00000000000..15e8d057859 --- /dev/null +++ b/apps/portal/src/app/typescript/v5/ecosystem-wallet/page.mdx @@ -0,0 +1,101 @@ +import { + Tabs, + TabsList, + TabsTrigger, + TabsContent, + Callout, + DocImage, + createMetadata, + ArticleIconCard, + Stack, + AuthList, +} from "@doc"; +import { ExternalLink} from "lucide-react"; +import EcosystemSocialConfig from './social-config.png' +import { TypeScriptIcon } from "@/icons"; + +export const metadata = createMetadata({ + title: "Connect users with Ecosystem Wallets", + description: + "Connect users with ecosystem wallets", + image: { + title: "Connect users with Ecosystem Wallets", + icon: "wallets", + }, +}); + +# Connect Users to your Ecosystem + +Ecosystem wallets inherit all the functionality of [in-app wallets](/references/typescript/v5/in-app-wallet), but instead of being scoped to a single app, they can be used across multiple applications. + +Head over to the [thirdweb dashboard](https://thirdweb.com/team) to create an ecosystem and obtain your ecosystem id. + +## Available auth methods + + + +## Live Playground + +Try out ecosystem wallets for yourself in the [in-app wallet live playground](https://playground.thirdweb.com/connect/in-app-wallet/ecosystem) + + + + + + + +## Configure ecosystem wallets + +The only difference with in-app wallets is how you create an ecosystem wallet using the `ecosystemWallet()` function and passing your ecosystem id. + +```tsx +import { ecosystemWallet } from "thirdweb/wallets"; + +const wallet = ecosystemWallet("ecosystem.your-ecosystem-id"); +``` + +## Configuring auth strategies + +You can configure the allowed auth strategies on [your dashboard](https://thirdweb.com/team/~/~/ecosystem). + + + +For prebuilt UIs, the enabled auth strategies are automatically read from your dashbaord configurations. + +For custom UIs, you can configure the auth options when connecting the wallet. See [using your own UI](#using-your-own-ui) for an example. + + + Note that while you're allowed to pass any auth strategy today, we recommend only passing the strategies that are enabled on your dashboard. We might enforce this in the future. + + +## Passing a partner ID + +For closed ecosystems, you can invite partners to your ecosystem. Partners will have to pass a valid `partnerId` to the `ecosystemWallet()` function in order to connect to your ecosystem. + +```tsx +const wallet = ecosystemWallet("ecosystem.your-ecosystem-id", { + partnerId: "your-partner-id", +}); +``` + +For more information, refer to the [ecosystemWallet API reference](/references/typescript/v5/ecosystemWallet). + + + + + + + +## Using ecosystem wallets + +Refer to the [in-app wallets](/references/typescript/v5/in-app-wallet) documentation to add your ecosystem wallet to your applications. diff --git a/apps/portal/src/app/typescript/v5/ecosystem-wallet/social-config.png b/apps/portal/src/app/typescript/v5/ecosystem-wallet/social-config.png new file mode 100644 index 00000000000..5a41a449a3b Binary files /dev/null and b/apps/portal/src/app/typescript/v5/ecosystem-wallet/social-config.png differ diff --git a/apps/portal/src/app/typescript/v5/in-app-wallet/page.mdx b/apps/portal/src/app/typescript/v5/in-app-wallet/page.mdx new file mode 100644 index 00000000000..d7d39e6e8ed --- /dev/null +++ b/apps/portal/src/app/typescript/v5/in-app-wallet/page.mdx @@ -0,0 +1,113 @@ +import { + Tabs, + TabsList, + TabsTrigger, + TabsContent, + Callout, + DocImage, + createMetadata, + AuthList, + ArticleIconCard, + Stack, + Steps, + Step +} from "@doc"; +import {ExternalLink} from "lucide-react"; +import { TypeScriptIcon } from "@/icons"; + +export const metadata = createMetadata({ + title: "Connect users with In-App Wallet", + description: + "use the prebuilt connect UI components to authenticate users and connect in-app wallets", + image: { + title: "Connect users with In-App Wallets", + icon: "wallets", + }, +}); + +# In-App Wallets + +Create in-app wallet for your users based on their email, phone, passkey, social auth or even their external wallets. These wallets are scoped by your clientId and do not require any confirmation to sign transactions. + +## Available auth methods + + + +## Live Playground + +Try out in-app wallets for yourself in the [in-app wallet live playground](https://playground.thirdweb.com/connect/in-app-wallet) + + + + + + + +## Configure in-app wallets + +The simplest way to create an in-app wallet is to use the `inAppWallet()` function. By default, this will create a wallet that supports email/password login, Google, Apple, Facebook login, and passkey. + +```tsx +import { inAppWallet } from "thirdweb/wallets"; + +const wallet = inAppWallet(); +``` + +You can also customize the wallet by passing in options. + +```tsx +import { inAppWallet } from "thirdweb/wallets"; + +const wallet = inAppWallet({ + auth: { + mode, // options are "popup" | "redirect" | "window"; + options, // ex: ["discord", "farcaster", "apple", "facebook", "google", "passkey"], + passkeyDomain, // for passkey, the domain that the passkey is created on + redirectUrl, // the URL to redirect to after authentication + }, + metadata, // metadata for the wallet (name, icon, etc.) + smartAccount, // smart account options for the wallet (for gasless tx) +}); +``` + +[View all in-app wallet options](/references/typescript/v5/InAppWalletCreationOptions). + +Once created, you can use it either with the prebuilt UI components, or with your own UI. + +## Usage + +```tsx +import { ThirdwebProvider, ConnectButton } from "thirdweb/react"; +import { inAppWallet } from "thirdweb/wallets"; + +const client = createThirdwebClient({ clientId }); +const wallet = inAppWallet(); + +const account = await wallet.connect({ + client, + strategy: "google", +}); + +console.log("connected as", account.address); + +``` + +## API Reference + +View all the auth and configuration options for in-app wallets in the [API Reference](/references/typescript/v5/inAppWallet). + + + + + + \ No newline at end of file diff --git a/apps/portal/src/app/typescript/v5/sidebar.tsx b/apps/portal/src/app/typescript/v5/sidebar.tsx index 12418f76cd2..5aef9d26ef9 100644 --- a/apps/portal/src/app/typescript/v5/sidebar.tsx +++ b/apps/portal/src/app/typescript/v5/sidebar.tsx @@ -1,5 +1,4 @@ -import { Book, CodeIcon, ZapIcon } from "lucide-react"; -import type { FunctionDoc } from "typedoc-better-json"; +import { CodeIcon, ExternalLink, ZapIcon } from "lucide-react"; import type { SideBar } from "../../../components/Layouts/DocLayout"; import { fetchTypeScriptDoc } from "../../references/components/TDoc/fetchDocs/fetchTypeScriptDoc"; import { getCustomTag } from "../../references/components/TDoc/utils/getSidebarLinkgroups"; @@ -22,102 +21,55 @@ export const sidebar: SideBar = { href: `${slug}/getting-started`, icon: , }, + { + name: "Live Playground", + href: "https://playground.thirdweb.com/", + icon: , + }, + { + name: "API Reference", + href: "/references/typescript/v5", + icon: , + }, { separator: true }, { - name: "Core", + name: "Core Concepts", isCollapsible: false, links: [ { name: "Client", - links: [ - { - name: "Introduction", - icon: , - href: `${slug}/client`, - }, - ...["createThirdwebClient"].map((name) => ({ - name, - href: `${slug}/${name}`, - icon: , - })), - ], + href: `${slug}/client`, }, { - name: "Adapters", - links: [ - { - name: "Introduction", - icon: , - href: `${slug}/adapters`, - }, - ...[ - "createWalletAdapter", - "viemAdapter", - "ethers6Adapter", - "ethers5Adapter", - ].map((name) => ({ - name, - href: `${slug}/${name}`, - icon: , - })), - ], + name: "Chains", + href: `${slug}/chain`, + }, + { + name: "Contracts", + href: `${slug}/contract`, }, ], }, { separator: true }, { - name: "Wallets", + name: "Onboarding Users", isCollapsible: false, links: [ { name: "Overview", href: `${slug}/wallets`, }, - { - name: "Supported Wallets", - href: `${slug}/supported-wallets`, - }, { name: "External Wallets", - links: [ - "createWallet", - "createWalletAdapter", - "privateKeyToAccount", - "generateAccount", - "injectedProvider", - ].map((name) => ({ - name, - href: `${slug}/${name}`, - icon: , - })), + href: `${slug}/supported-wallets`, }, { name: "In-App Wallets", - links: [ - "inAppWallet", - "preAuthenticate", - "linkProfile", - "getProfiles", - "hasStoredPasskey", - ].map((name) => ({ - name, - href: `${slug}/${name}`, - icon: , - })), + href: `${slug}/in-app-wallet`, }, { name: "Ecosystem Wallets", - links: [ - "ecosystemWallet", - "preAuthenticate", - "linkProfile", - "getProfiles", - "hasStoredPasskey", - ].map((name) => ({ - name, - href: `${slug}/${name}`, - icon: , - })), + href: `${slug}/ecosystem-wallet`, }, { name: "Account Abstraction", @@ -125,226 +77,91 @@ export const sidebar: SideBar = { { name: "Getting Started", href: `${slug}/account-abstraction/get-started`, - icon: , - }, - { - name: "Admins & Session Keys", - href: `${slug}/account-abstraction/permissions`, - icon: , }, { name: "Batching Transactions", href: `${slug}/account-abstraction/batching-transactions`, - icon: , }, - ...[ - "smartWallet", - "predictSmartAccountAddress", - "createAndSignUserOp", - "createUnsignedUserOp", - "signUserOp", - "bundleUserOp", - "getUserOpReceipt", - "waitForUserOpReceipt", - "getUserOpGasFees", - "estimateUserOpGas", - ].map((name) => ({ - name, - href: `${slug}/${name}`, - icon: , - })), - ...[ - "addAdmin", - "removeAdmin", - "addSessionKey", - "removeSessionKey", - "getAccountsOfSigner", - "getAllActiveSigners", - "getPermissionsForSigner", - ].map((name) => ({ - name, - href: `${slug}/erc4337/${name}`, - icon: , - })), - ], - }, - { - name: "Auth (SIWE)", - href: `${slug}/auth`, - links: [ - { - name: "Introduction", - icon: , - href: `${slug}/auth`, - }, - ...(docs.functions - ?.filter((f) => { - const [tag] = getCustomTag(f) || []; - return tag === "@auth"; - }) - ?.map((f) => ({ - name: f.name, - href: `${slug}/${f.name}`, - icon: , - })) || []), ], }, ], }, { separator: true }, { - name: "Pay", + name: "Identity Management", isCollapsible: false, links: [ { - name: "Buy with Fiat", - links: - docs.functions - ?.filter((f) => { - const [tag] = getCustomTag(f) || []; - return tag === "@buyCrypto" && f.name.includes("Fiat"); - }) - ?.map((f) => ({ - name: f.name, - href: `${slug}/${f.name}`, - icon: , - })) || [], + name: "Sign In With Ethereum", + href: `${slug}/auth`, }, { - name: "Buy with Crypto", - links: - docs.functions - ?.filter((f) => { - const [tag] = getCustomTag(f) || []; - return tag === "@buyCrypto" && f.name.includes("Crypto"); - }) - ?.map((f) => ({ - name: f.name, - href: `${slug}/${f.name}`, - icon: , - })) || [], + name: "Link Profiles", + href: `${slug}/linkProfile`, + }, + { + name: "Web3 Social Identities", + href: `${slug}/getSocialProfiles`, + }, + { + name: "Permissions", + href: `${slug}/account-abstraction/permissions`, }, ], }, { separator: true }, { - name: "Social API", - isCollapsible: false, - links: ["getSocialProfiles"].map((name) => ({ - name, - href: `${slug}/${name}`, - icon: , - })), - }, - { separator: true }, - { - name: "Blockchain API", + name: "Onchain Interactions", isCollapsible: false, links: [ { - name: "Chains", - links: [ - { - name: "Introduction", - icon: , - href: `${slug}/chain`, - }, - ...(docs.functions - ?.filter((f) => { - const [tag] = getCustomTag(f) || []; - return tag === "@chain"; - }) - ?.map((f) => ({ - name: f.name, - href: `${slug}/${f.name}`, - icon: , - })) || []), - ], + name: "Reading state", + href: `${slug}/transactions/read`, }, { - name: "Contracts", - links: [ - { - name: "Introduction", - icon: , - href: `${slug}/contract`, - }, - ...[ - "getContract", - "getBytecode", - "verifyContract", - "resolveContractAbi", - "fetchPublishedContract", - "resolveMethod", - "detectMethod", - ].map((name) => ({ - name, - href: `${slug}/${name}`, - icon: , - })), - ], + name: "Preparing transactions", + href: `${slug}/transactions/prepare`, }, { - name: "Reading state", - links: [ - { - name: "Introduction", - icon: , - href: `${slug}/transactions/read`, - }, - ...["readContract", "prepareEvent", "getContractEvents"].map( - (name) => ({ - name, - href: `${slug}/${name}`, - icon: , - }), - ), - ], + name: "Sending transactions", + href: `${slug}/transactions/send`, }, { - name: "Preparing transactions", + name: "Extensions", links: [ { - name: "Introduction", - icon: , - href: `${slug}/transactions/prepare`, + name: "Using Extensions", + href: `${slug}/extensions/use`, }, - ...[ - "prepareContractCall", - "prepareTransaction", - "encode", - "signTransaction", - "simulateTransaction", - "estimateGas", - "estimateGasCost", - "toSerializableTransaction", - "serializeTransaction", - ].map((name) => ({ - name, - href: `${slug}/${name}`, - icon: , - })), - ], - }, - { - name: "Sending transactions", - links: [ { - name: "Introduction", - icon: , - href: `${slug}/transactions/send`, + name: "Generating Extensions", + href: `${slug}/extensions/generate`, + }, + { + name: "Writing Extensions", + href: `${slug}/extensions/create`, + }, + { + name: "Available Extensions", + href: `${slug}/extensions/built-in`, + }, + { + name: "Examples", + links: [ + { + name: "Lens Protocol", + href: `${slug}/extensions/examples/lens-protocol`, + }, + { + name: "Transfering tokens", + href: `${slug}/extensions/examples/transfering-tokens`, + }, + { + name: "Ethereum Name Service", + href: `${slug}/extensions/examples/ethereum-name-service`, + }, + ], }, - ...[ - "sendTransaction", - "sendAndConfirmTransaction", - "sendBatchTransaction", - "waitForReceipt", - "getTransactionStore", - ].map((name) => ({ - name, - href: `${slug}/${name}`, - icon: , - })), ], }, { @@ -359,7 +176,6 @@ export const sidebar: SideBar = { .map((f) => ({ name: f.name, href: `${slug}/deploy/${f.name}`, - icon: , })) || [], }, { @@ -368,129 +184,27 @@ export const sidebar: SideBar = { { name: "Introduction", href: `${slug}/modular`, - icon: , }, { name: "Deploying", href: `${slug}/modular/deploy`, - icon: , }, { name: "Upgrading", href: `${slug}/modular/upgrade`, - icon: , }, { name: "Interacting", href: `${slug}/modular/interact`, - icon: , }, { name: "Available Modules", href: `${slug}/modular/built-in`, - isCollapsible: false, - links: Object.entries( - docs.functions - ?.filter((f) => { - const [tag] = getCustomTag(f) || []; - return tag === "@modules"; - }) - ?.reduce( - (acc, f) => { - const [, extensionName] = getCustomTag(f) || []; - if (extensionName) { - acc[extensionName] = acc[extensionName] || []; - acc[extensionName]?.push(f); - } - return acc; - }, - {} as Record, - ) || [], - ).map(([extensionName, extensionFunctions]) => ({ - name: extensionName, - links: extensionFunctions - .sort((a, b) => a.name.localeCompare(b.name)) - .map((f) => ({ - name: f.name, - href: `${slug}/${extensionName.toLowerCase()}/${f.name}`, - icon: , - })), - })), - }, - ], - }, - { - name: "Extensions", - links: [ - { - name: "Using Extensions", - href: `${slug}/extensions/use`, - icon: , - }, - { - name: "Generating Extensions", - href: `${slug}/extensions/generate`, - icon: , - }, - { - name: "Writing Extensions", - href: `${slug}/extensions/create`, - icon: , - }, - { - name: "Examples", - icon: , - links: [ - { - name: "Lens Protocol", - href: `${slug}/extensions/examples/lens-protocol`, - }, - { - name: "Transfering tokens", - href: `${slug}/extensions/examples/transfering-tokens`, - }, - { - name: "Ethereum Name Service", - href: `${slug}/extensions/examples/ethereum-name-service`, - }, - ], - }, - { - name: "Available Extensions", - href: `${slug}/extensions/built-in`, - isCollapsible: false, - links: Object.entries( - docs.functions - ?.filter((f) => { - const [tag, extensionName] = getCustomTag(f) || []; - return tag === "@extension" && extensionName !== "DEPLOY"; - }) - ?.reduce( - (acc, f) => { - const [, extensionName] = getCustomTag(f) || []; - if (extensionName) { - acc[extensionName] = acc[extensionName] || []; - acc[extensionName]?.push(f); - } - return acc; - }, - {} as Record, - ) || [], - ).map(([extensionName, extensionFunctions]) => ({ - name: extensionName, - links: extensionFunctions - .sort((a, b) => a.name.localeCompare(b.name)) - .map((f) => ({ - name: f.name, - href: `${slug}/${extensionName.toLowerCase()}/${f.name}`, - icon: , - })), - })), }, ], }, { - name: "RPC", + name: "RPC Methods", links: docs.functions ?.filter((f) => { @@ -500,61 +214,48 @@ export const sidebar: SideBar = { ?.map((f) => ({ name: f.name, href: `${slug}/${f.name}`, - icon: , })) || [], }, { - name: "Storage", - links: [ - { - name: "Introduction", - icon: , - href: `${slug}/storage`, - }, - ...(docs.functions + name: "IPFS Storage", + href: `${slug}/storage`, + }, + { + name: "Pay with Fiat", + links: + docs.functions ?.filter((f) => { const [tag] = getCustomTag(f) || []; - return tag === "@storage"; + return tag === "@buyCrypto" && f.name.includes("Fiat"); }) ?.map((f) => ({ name: f.name, href: `${slug}/${f.name}`, - icon: , - })) || []), - ], + })) || [], }, { - name: "Utils", - links: [ - "toEther", - "toTokens", - "toWei", - "toUnits", - "shortenAddress", - "shortenHex", - "encodeAbiParameters", - "encodePacked", - "sha256", - "keccak256", - "keccakId", - ].map((name) => ({ - name, - href: `${slug}/${name}`, - icon: , - })), + name: "Bridge & Swap", + links: + docs.functions + ?.filter((f) => { + const [tag] = getCustomTag(f) || []; + return tag === "@buyCrypto" && f.name.includes("Crypto"); + }) + ?.map((f) => ({ + name: f.name, + href: `${slug}/${f.name}`, + })) || [], }, ], }, + { separator: true }, { - separator: true, + name: "Usage with other libraries", + href: `${slug}/adapters`, }, { name: "Migrate from v4", href: `${slug}/migrate`, }, - { - name: "Full Reference", - href: "/references/typescript/v5", - }, ], }; diff --git a/apps/portal/src/app/typescript/v5/storage/page.mdx b/apps/portal/src/app/typescript/v5/storage/page.mdx index 7fa7a34c31a..d09e7488bc6 100644 --- a/apps/portal/src/app/typescript/v5/storage/page.mdx +++ b/apps/portal/src/app/typescript/v5/storage/page.mdx @@ -47,3 +47,16 @@ const uris = await upload({ ``` You can view all of the configuration options in the [full reference](/references/typescript/v5/upload). + +### Resolve IPFS uris + +You can easily convert a `ipfs://` uri to a `https://` uri with your own IPFS gateway using the `resolveScheme` function. + +The resolved uri will be protected by your api key settings, and only accessible to your whitelisted domains. + +```ts +import { resolveScheme } from "thirdweb/storage"; + +const uri = await resolveScheme("ipfs://Qm..."); +// resolves to https://.ipfscdn.io/Qm... +``` \ No newline at end of file diff --git a/apps/portal/src/app/typescript/v5/transactions/read/page.mdx b/apps/portal/src/app/typescript/v5/transactions/read/page.mdx index a2f6855b883..6d5b93de6c7 100644 --- a/apps/portal/src/app/typescript/v5/transactions/read/page.mdx +++ b/apps/portal/src/app/typescript/v5/transactions/read/page.mdx @@ -14,7 +14,25 @@ const balance = await readContract({ This will execute the read immediately and return the result from the blockchain. -### Generating all read functions for a deployed contract +## Reading contract events + +The recommended way to read the contract events is to use the `getContractEvents` function and passing a prepared event with the Solidity event signature and the params. This is type-safe based on the Solidity event signature you define. You can get your desired contract event signature from the solidity code directly. + +```ts +import { getContractEvents, prepareEvent } from "thirdweb"; + +const myEvent = prepareEvent({ + signature: "event Transfer(address indexed from, address indexed to, uint256 value)", +}); + +const events = await getContractEvents({ + contract: myContract, + events: [myEvent], + blockRange: 1000, +}); +``` + +### Generating all read functions and events for a deployed contract Using the CLI, you can generate optimized functions for all the possible calls to a contract. This saves you time and precomputes all the necessary encoding. diff --git a/apps/portal/src/components/Document/Cards/ConnectCard.tsx b/apps/portal/src/components/Document/Cards/ConnectCard.tsx index 2f6ca4a94c5..967e782fd7f 100644 --- a/apps/portal/src/components/Document/Cards/ConnectCard.tsx +++ b/apps/portal/src/components/Document/Cards/ConnectCard.tsx @@ -5,9 +5,14 @@ export function ConnectCard(props: { title: string; href: string; iconUrl: string; + isExternal?: boolean; }) { return ( - +
diff --git a/apps/portal/src/components/Document/index.ts b/apps/portal/src/components/Document/index.ts index be36d17a854..efacfd832d0 100644 --- a/apps/portal/src/components/Document/index.ts +++ b/apps/portal/src/components/Document/index.ts @@ -24,6 +24,6 @@ export { ExpandableGrid } from "./ExpandableGrid"; export { Stack } from "./Stack"; export { createMetadata } from "./metadata"; export { ConnectCard } from "./Cards/ConnectCard"; -export { FeatureCard } from "./FeatureCard"; export { AAChainList } from "./AAChainList"; export { AuthList } from "./AuthList"; +export { FeatureCard } from "./FeatureCard"; diff --git a/packages/thirdweb/src/wallets/in-app/web/in-app.ts b/packages/thirdweb/src/wallets/in-app/web/in-app.ts index b2cd6632724..30246a7d66f 100644 --- a/packages/thirdweb/src/wallets/in-app/web/in-app.ts +++ b/packages/thirdweb/src/wallets/in-app/web/in-app.ts @@ -29,6 +29,26 @@ import { createInAppWallet } from "../core/wallet/in-app-core.js"; * * [View all available social auth methods](https://portal.thirdweb.com/connect/wallet/sign-in-methods/configure) * + * ### Enable smart accounts and sponsor gas for your users: + * + * ```ts + * import { inAppWallet } from "thirdweb/wallets"; + * import { sepolia } from "thirdweb/chains"; + * + * const wallet = inAppWallet({ + * smartAccount: { + * chain: sepolia, + * sponsorGas: true, + * }, + * }); + * + * // account will be a smart account with sponsored gas enabled + * const account = await wallet.connect({ + * client, + * strategy: "google", + * }); + * ``` + * * ### Login with email * * ```ts @@ -107,27 +127,38 @@ import { createInAppWallet } from "../core/wallet/in-app-core.js"; * }); * ``` * - * ### Enable smart accounts and sponsor gas for your users: - * + * ### Connect to a guest account * ```ts * import { inAppWallet } from "thirdweb/wallets"; - * import { sepolia } from "thirdweb/chains"; * - * const wallet = inAppWallet({ - * smartAccount: { - * chain: sepolia, - * sponsorGas: true, - * }, + * const wallet = inAppWallet(); + * + * const account = await wallet.connect({ + * client, + * strategy: "guest", * }); + * ``` + * + * ### Connect with custom JWT (any OIDC provider) + * + * You can use any OIDC provider to authenticate your users. Make sure to configure it in your dashboard under in-app wallet settings. + * + * ```ts + * import { inAppWallet } from "thirdweb/wallets"; + * + * const wallet = inAppWallet(); * - * // account will be a smart account with sponsored gas enabled * const account = await wallet.connect({ * client, - * strategy: "google", + * strategy: "jwt", + * jwt: "your_jwt_here", * }); * ``` * - * ### Connect to a guest account + * ### Connect with custom endpoint + * + * You can also use your own endpoint to authenticate your users. Make sure to configure it in your dashboard under in-app wallet settings. + * * ```ts * import { inAppWallet } from "thirdweb/wallets"; * @@ -135,7 +166,8 @@ import { createInAppWallet } from "../core/wallet/in-app-core.js"; * * const account = await wallet.connect({ * client, - * strategy: "guest", + * strategy: "auth_endpoint", + * payload: "your_auth_payload_here", * }); * ``` * diff --git a/packages/thirdweb/src/wallets/smart/smart-wallet-dev.test.ts b/packages/thirdweb/src/wallets/smart/smart-wallet-dev.test.ts index 8514febe29c..6b5e69a7fb2 100644 --- a/packages/thirdweb/src/wallets/smart/smart-wallet-dev.test.ts +++ b/packages/thirdweb/src/wallets/smart/smart-wallet-dev.test.ts @@ -1,6 +1,5 @@ import { beforeAll, describe, expect, it } from "vitest"; import { TEST_CLIENT } from "../../../test/src/test-clients.js"; -import { arbitrumSepolia } from "../../chains/chain-definitions/arbitrum.js"; import { type ThirdwebContract, getContract } from "../../contract/contract.js"; import { balanceOf } from "../../extensions/erc1155/__generated__/IERC1155/read/balanceOf.js"; import { claimTo } from "../../extensions/erc1155/drops/write/claimTo.js"; @@ -14,6 +13,8 @@ import type { Account, Wallet } from "../interfaces/wallet.js"; import { generateAccount } from "../utils/generateAccount.js"; import { smartWallet } from "./smart-wallet.js"; let wallet: Wallet; +import { arbitrumSepolia } from "../../chains/chain-definitions/arbitrum-sepolia.js"; + let smartAccount: Account; let smartWalletAddress: Address; let personalAccount: Account;