Compare commits

..
Author SHA1 Message Date
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
c710fc1c62 Version Packages (#1745)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-10-12 21:12:59 -07:00
iketwandGitHub f41ee6fb1c [RN] Correctly use custom themes (#1760) 2023-10-13 03:53:48 +00:00
iketwandGitHub 513c332ed0 [RN] Show selectUI component when passing one supportedWallet (#1759) 2023-10-13 03:02:47 +00:00
Kien NgoandGitHub 693f349db2 [SDK] Add pagination to getOwned for ERC721 & 1155 (#1695) 2023-10-12 23:34:39 +00:00
YashandGitHub 63ad0050f0 Update deployment setup (#1757) 2023-10-12 17:34:31 +00:00
iketwandGitHub dcdb0dcb83 [Wallets] Typo fixes for SW api (#1754) 2023-10-11 22:40:05 +00:00
iketwandGitHub b3b9edca29 [RN] Minor bug fix and UI improvements to connecting an app to a smar… (#1753) 2023-10-11 21:51:19 +00:00
Winston YeoandGitHub 1fbbc2d27d [SDK] update ApiKeyMetadata (#1752) 2023-10-11 20:38:44 +00:00
Joaquim VergesandGitHub 4b98e487d4 [Wallets] Add wallet analytics (#1730) 2023-10-11 20:19:22 +00:00
Phillip HoandGitHub 95380eaed4 chore: Add walletType to usage tracker payload (#1751) 2023-10-11 17:55:51 +00:00
Joaquim VergesandGitHub 1f3c64d361 [SDK] handle upgradeable proxies and optimize proxy resolution (#1747) 2023-10-11 16:39:06 +00:00
Manan TankandGitHub bb1666b92b [react] ConnectWallet UI fixes + improvements (#1750) 2023-10-11 13:20:40 +00:00
farhanW3andGitHub 0f12d1f903 RPC Override Fix (#1746) 2023-10-11 01:01:03 +00:00
Joaquim VergesandGitHub 74941603a9 [Wallets] Fix executeBatch type mismatch (#1744) 2023-10-10 21:24:08 +00:00
93 changed files with 5952 additions and 799 deletions
+7
View File
@@ -1,5 +1,12 @@
# @thirdweb-dev/auth
## 4.0.2
### Patch Changes
- Updated dependencies [[`74941603`](https://github.com/thirdweb-dev/js/commit/74941603a96456da46a47147f67c98235ac55022), [`4b98e487`](https://github.com/thirdweb-dev/js/commit/4b98e487d4b47225d7095e5444dc5e7608db48a3), [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9), [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e)]:
- @thirdweb-dev/wallets@2.0.2
## 4.0.1
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "4.0.1",
"version": "4.0.2",
"main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js",
"browser": {
+9
View File
@@ -1,5 +1,14 @@
# thirdweb
## 0.13.2
### Patch Changes
- Updated dependencies [[`1f3c64d3`](https://github.com/thirdweb-dev/js/commit/1f3c64d3618903b9008cc7b633ea890b508e7800), [`74941603`](https://github.com/thirdweb-dev/js/commit/74941603a96456da46a47147f67c98235ac55022), [`4b98e487`](https://github.com/thirdweb-dev/js/commit/4b98e487d4b47225d7095e5444dc5e7608db48a3), [`693f349d`](https://github.com/thirdweb-dev/js/commit/693f349db2478e1cd0fc82a9ef9882f46832b125), [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9), [`0f12d1f9`](https://github.com/thirdweb-dev/js/commit/0f12d1f90320923309f085c372d3a5ed01dd4606), [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e), [`63ad0050`](https://github.com/thirdweb-dev/js/commit/63ad0050f0a24ec15b90933b5664d697618cf2d0)]:
- @thirdweb-dev/sdk@4.0.1
- @thirdweb-dev/wallets@2.0.2
- @thirdweb-dev/auth@4.0.2
## 0.13.1
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "thirdweb",
"main": "dist/cli/index.js",
"version": "0.13.1",
"version": "0.13.2",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+6
View File
@@ -1,5 +1,11 @@
# @thirdweb-dev/contracts-js
## 1.3.14
### Patch Changes
- [#1757](https://github.com/thirdweb-dev/js/pull/1757) [`63ad0050`](https://github.com/thirdweb-dev/js/commit/63ad0050f0a24ec15b90933b5664d697618cf2d0) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Update deployment and tests for MarketplaceV3 latest
## 1.3.13
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/contracts-js",
"version": "1.3.13",
"version": "1.3.14",
"main": "dist/thirdweb-dev-contracts-js.cjs.js",
"module": "dist/thirdweb-dev-contracts-js.esm.js",
"browser": {
@@ -10,7 +10,7 @@
"license": "Apache-2.0",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/contracts-js",
"dependencies": {
"@thirdweb-dev/contracts": "3.10.1-0"
"@thirdweb-dev/contracts": "3.10.2-3"
},
"devDependencies": {
"@babel/preset-env": "^7.22.9",
+9
View File
@@ -1,5 +1,14 @@
# @thirdweb-dev/react-core
## 4.0.2
### Patch Changes
- Updated dependencies [[`1f3c64d3`](https://github.com/thirdweb-dev/js/commit/1f3c64d3618903b9008cc7b633ea890b508e7800), [`74941603`](https://github.com/thirdweb-dev/js/commit/74941603a96456da46a47147f67c98235ac55022), [`4b98e487`](https://github.com/thirdweb-dev/js/commit/4b98e487d4b47225d7095e5444dc5e7608db48a3), [`693f349d`](https://github.com/thirdweb-dev/js/commit/693f349db2478e1cd0fc82a9ef9882f46832b125), [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9), [`0f12d1f9`](https://github.com/thirdweb-dev/js/commit/0f12d1f90320923309f085c372d3a5ed01dd4606), [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e), [`63ad0050`](https://github.com/thirdweb-dev/js/commit/63ad0050f0a24ec15b90933b5664d697618cf2d0)]:
- @thirdweb-dev/sdk@4.0.1
- @thirdweb-dev/wallets@2.0.2
- @thirdweb-dev/auth@4.0.2
## 4.0.1
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-core",
"version": "4.0.1",
"version": "4.0.2",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -1,5 +1,7 @@
# @thirdweb-dev/react-native-compat
## 0.3.7
## 0.3.6
## 0.3.5
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@thirdweb-dev/react-native-compat",
"description": "Shims for Thirdweb in React Native Projects",
"version": "0.3.6",
"version": "0.3.7",
"author": "thirdweb eng <[email protected]>",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
"license": "Apache-2.0",
+17
View File
@@ -1,5 +1,22 @@
# @thirdweb-dev/react-native
## 0.3.7
### Patch Changes
- [#1754](https://github.com/thirdweb-dev/js/pull/1754) [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9) Thanks [@iketw](https://github.com/iketw)! - Fix typos in SmartWallet api
- [#1760](https://github.com/thirdweb-dev/js/pull/1760) [`f41ee6fb`](https://github.com/thirdweb-dev/js/commit/f41ee6fb1cc3b1e58cc273fa45087d4c92ff97d1) Thanks [@iketw](https://github.com/iketw)! - Correctly pass theme via ConnectWallet
- [#1753](https://github.com/thirdweb-dev/js/pull/1753) [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e) Thanks [@iketw](https://github.com/iketw)! - Minor bug and UI fix for connecting an external app to a smart wallet
- [#1759](https://github.com/thirdweb-dev/js/pull/1759) [`513c332e`](https://github.com/thirdweb-dev/js/commit/513c332ed02df4ac316076cc03178a4702b12110) Thanks [@iketw](https://github.com/iketw)! - Fixes bug when passing only one wallet as a supportedWallet. The selectUI component must be displayed.
- Updated dependencies [[`1f3c64d3`](https://github.com/thirdweb-dev/js/commit/1f3c64d3618903b9008cc7b633ea890b508e7800), [`74941603`](https://github.com/thirdweb-dev/js/commit/74941603a96456da46a47147f67c98235ac55022), [`4b98e487`](https://github.com/thirdweb-dev/js/commit/4b98e487d4b47225d7095e5444dc5e7608db48a3), [`693f349d`](https://github.com/thirdweb-dev/js/commit/693f349db2478e1cd0fc82a9ef9882f46832b125), [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9), [`0f12d1f9`](https://github.com/thirdweb-dev/js/commit/0f12d1f90320923309f085c372d3a5ed01dd4606), [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e), [`63ad0050`](https://github.com/thirdweb-dev/js/commit/63ad0050f0a24ec15b90933b5664d697618cf2d0)]:
- @thirdweb-dev/sdk@4.0.1
- @thirdweb-dev/wallets@2.0.2
- @thirdweb-dev/react-core@4.0.2
## 0.3.6
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-native",
"version": "0.3.6",
"version": "0.3.7",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -1,6 +1,6 @@
import { useWallet } from "@thirdweb-dev/react-core";
import { IWalletConnectReceiver } from "@thirdweb-dev/wallets";
import { useCallback, useEffect, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import Box from "../base/Box";
import BaseButton from "../base/BaseButton";
import DisconnectIcon from "../../assets/disconnect";
@@ -21,6 +21,7 @@ const ConnectAppField = () => {
const [appMeta, setAppMeta] = useState<{ name: string; iconUrl: string }>();
const wallet = useWallet();
const [showQRCodeScan, setShowQRCodeScan] = useState(false);
const wcUriRef = useRef<string | undefined>();
const getAppMeta = useCallback(() => {
if (wallet && "isWCReceiverEnabled" in wallet) {
@@ -80,9 +81,10 @@ const ConnectAppField = () => {
};
const onQRCodeScan = (data: string) => {
if (wcUri !== data && data.startsWith("wc:")) {
if (wcUriRef.current !== data && data.startsWith("wc:")) {
setWCUri(data);
setShowQRCodeScan(false);
wcUriRef.current = data;
onWCPress(data);
}
@@ -102,6 +104,9 @@ const ConnectAppField = () => {
if (uriToUse?.startsWith("wc:")) {
(wallet as unknown as IWalletConnectReceiver).connectApp(uriToUse);
}
setWCUri(undefined);
wcUriRef.current = undefined;
};
const onScanQRPress = () => {
@@ -124,9 +129,11 @@ const ConnectAppField = () => {
value: wcUri,
placeholder: "wc://...",
placeholderTextColor: theme.colors.textSecondary,
numberOfLines: 1,
}}
containerProps={{
flex: 1,
pl: "xxs",
}}
/>
<BaseButton
@@ -164,12 +171,12 @@ const ConnectAppField = () => {
>
<>
{appMeta?.iconUrl ? (
<WalletIcon size={32} iconUri={appMeta.iconUrl} />
<WalletIcon size={24} iconUri={appMeta.iconUrl} />
) : (
<WalletConnectIcon width={16} height={16} />
<WalletConnectIcon width={24} height={24} />
)}
<View style={styles.exportWalletInfo}>
<Text variant="bodySmall">
<Text variant="bodySmall" numberOfLines={1}>
{appMeta ? appMeta.name : "Connect app"}
</Text>
</View>
@@ -215,8 +222,9 @@ const styles = StyleSheet.create({
justifyContent: "flex-start",
alignItems: "flex-start",
alignContent: "center",
flexDirection: "column",
flexDirection: "row",
marginLeft: 8,
marginRight: 8,
},
exportWallet: {
display: "flex",
@@ -12,9 +12,9 @@ import { useEffect, useState } from "react";
import { useSmartWallet } from "../../providers/context-provider";
import RightArrowIcon from "../../assets/right-arrow";
import ConnectAppField from "./ConnectAppField";
import { useAppTheme } from "../../styles/hooks";
import DisconnectIcon from "../../assets/disconnect";
import { IconTextButton } from "../base/IconTextButton";
import { useGlobalTheme } from "../../providers/ui-context-provider";
export const SmartWalletAdditionalActions = ({
onExportPress,
@@ -26,7 +26,7 @@ export const SmartWalletAdditionalActions = ({
const [smartWalletAddress, setSmartWalletAddress] = useState<string>("");
const [showSmartWallet, setShowSmartWallet] = useState(false);
const activeWallet = useWallet();
const theme = useAppTheme();
const theme = useGlobalTheme();
const wallet = showSmartWallet
? smartWallet
@@ -1,5 +1,4 @@
import { Icon } from "../../assets/icon";
import { useAppTheme } from "../../styles/hooks";
import { AddressDisplay } from "../base/AddressDisplay";
import BaseButton from "../base/BaseButton";
import { WalletIcon } from "../base/WalletIcon";
@@ -13,6 +12,7 @@ import { TextBalance } from "../base/TextBalance";
import { walletIds } from "@thirdweb-dev/wallets";
import { SMART_WALLET_ICON } from "../../assets/svgs";
import Text from "../base/Text";
import { useGlobalTheme } from "../../providers/ui-context-provider";
interface WalletDetailsModalHeaderProps {
address?: string;
@@ -28,7 +28,7 @@ export const WalletDetailsModalHeader = ({
onAddressCopied,
tokenAddress,
}: WalletDetailsModalHeaderProps) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
const activeWallet = useWallet();
const [showLoading, setShowLoading] = useState(false);
const ensQuery = useENS();
@@ -5,11 +5,11 @@ import { ReactNode, useState } from "react";
import Box from "../../base/Box";
import Text from "../../base/Text";
import ThirdwebLogo from "../../../assets/thirdweb-logo";
import { useAppTheme } from "../../../styles/hooks";
import { ChooseWalletContent } from "./ChooseWalletContent";
import { BaseButton, ImageSvgUri, WalletButton } from "../../base";
import { ActivityIndicator, Linking } from "react-native";
import { useTheme } from "@shopify/restyle";
import { useGlobalTheme } from "../../../providers/ui-context-provider";
export type ChooseWalletProps = {
headerText?: ReactNode | string;
@@ -34,7 +34,7 @@ export function ChooseWallet({
termsOfServiceUrl,
privacyPolicyUrl,
}: ChooseWalletProps) {
const theme = useAppTheme();
const theme = useGlobalTheme();
const themeLightDark = useTheme();
const [isConnecting, setIsConnecting] = useState(false);
const [isConnectAWalletEnabled, setIsConnectAWalletEnabled] = useState(false);
@@ -2,9 +2,11 @@ import { ActivityIndicator, StyleSheet } from "react-native";
import { BaseButton, Text } from "../base";
import { useConnectionStatus, useWallets } from "@thirdweb-dev/react-core";
import { useState, useEffect } from "react";
import { useModalState } from "../../providers/ui-context-provider";
import {
useGlobalTheme,
useModalState,
} from "../../providers/ui-context-provider";
import { ThemeProvider, ThemeProviderProps } from "../../styles/ThemeProvider";
import { useAppTheme } from "../../styles/hooks";
export type ConnectWalletButtonProps = {
theme?: ThemeProviderProps["theme"];
@@ -43,7 +45,7 @@ export const ConnectWalletButton = ({
buttonTitle,
theme,
}: ConnectWalletButtonProps) => {
const appTheme = useAppTheme();
const appTheme = useGlobalTheme();
const connectionStatus = useConnectionStatus();
const isWalletConnecting = connectionStatus === "connecting";
@@ -5,14 +5,16 @@ import { WalletConfig, useConnect, useWallets } from "@thirdweb-dev/react-core";
import { useCallback, useEffect, useState } from "react";
import { walletIds } from "@thirdweb-dev/wallets";
import { useColorScheme } from "react-native";
import { useModalState } from "../../providers/ui-context-provider";
import {
useGlobalTheme,
useModalState,
} from "../../providers/ui-context-provider";
import {
CLOSE_MODAL_STATE,
ConnectWalletFlowModal,
} from "../../utils/modalTypes";
import Box from "../base/Box";
import { ThemeProvider } from "../../styles/ThemeProvider";
import { useAppTheme } from "../../styles/hooks";
export const ConnectWalletFlow = () => {
const { modalState, setModalState } = useModalState();
@@ -30,7 +32,7 @@ export const ConnectWalletFlow = () => {
const [selectionData, setSelectionData] = useState<any>();
const supportedWallets = useWallets();
const theme = useColorScheme();
const appTheme = useAppTheme();
const appTheme = useGlobalTheme();
const connect = useConnect();
const onClose = useCallback(
@@ -74,13 +76,19 @@ export const ConnectWalletFlow = () => {
useEffect(() => {
// case when only one wallet is passed in supportedWallets
if (walletConfig) {
if (walletConfig.connectUI) {
// if there's a connection UI, then show it
setActiveWallet(walletConfig);
} else {
// if there's no connection UI, then connect the wallet
onChooseWallet(walletConfig);
// if there's a selection UI, then continue with the flow
if (walletConfig.selectUI) {
return;
}
if (walletConfig.connectUI) {
// if there's a connection UI and no selection UI, then show it
setActiveWallet(walletConfig);
return;
}
// if there's no connection UI or selectionUI, then automatically select it
onChooseWallet(walletConfig);
}
}, [onChooseWallet, walletConfig]);
@@ -1,5 +1,5 @@
import { Icon } from "../../../assets/icon";
import { useAppTheme } from "../../../styles/hooks";
import { useGlobalTheme } from "../../../providers/ui-context-provider";
import Text from "../../base/Text";
import { FlexAlignType, StyleSheet, View } from "react-native";
@@ -20,7 +20,7 @@ export const ConnectWalletHeader = ({
onClose,
onBackPress,
}: ConnectWalletHeaderProps) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
return (
<>
<View style={styles.header}>
@@ -16,7 +16,7 @@ import * as FileSystem from "expo-file-system";
import { TWModal } from "../base/modal/TWModal";
import { localWallet } from "../../wallets/wallets/local-wallet";
import { TextInput } from "../base";
import { useAppTheme } from "../../styles/hooks";
import { useGlobalTheme } from "../../providers/ui-context-provider";
export type LocalWalletImportModalProps = {
isVisible: boolean;
@@ -37,7 +37,7 @@ export const LocalWalletImportModal = ({
const [error, setError] = useState<string | undefined>();
const [isImporting, setIsImporting] = useState<boolean>(false);
const createWalletInstance = useCreateWalletInstance();
const theme = useAppTheme();
const theme = useGlobalTheme();
const createLocalWalletFromJsonFile = async () => {
if (!jsonFile || !password) {
@@ -15,7 +15,7 @@ import WalletLoadingThumbnail from "../../../wallets/wallets/wallet-connect/Wall
import ImageSvgUri from "../../base/ImageSvgUri";
import Box from "../../base/Box";
import { ConnectWalletHeader } from "../ConnectingWallet/ConnectingWalletHeader";
import { useAppTheme } from "../../../styles/hooks";
import { useGlobalTheme } from "../../../providers/ui-context-provider";
export const SmartWalletFlow = ({
connected,
@@ -24,7 +24,7 @@ export const SmartWalletFlow = ({
personalWalletConfig,
...props
}: ConnectUIProps<SmartWallet> & { personalWalletConfig: WalletConfig }) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
const [connectedPersonalWallet, setConnectedPersonalWallet] =
useState<WalletInstance>();
const [personalWalletChainId, setPersonalWalletChaindId] = useState<
@@ -1,4 +1,7 @@
import { useModalState } from "../providers/ui-context-provider";
import {
useGlobalTheme,
useModalState,
} from "../providers/ui-context-provider";
import { ConnectWalletFlow } from "./ConnectWalletFlow/ConnectWalletFlow";
import { Dimensions, StyleSheet, View } from "react-native";
import { useMemo } from "react";
@@ -7,13 +10,13 @@ import { SessionRequestModal } from "./ConnectWalletDetails/SessionRequestModal"
import { SessionProposalModal } from "./ConnectWalletDetails/SessionProposalModal";
import { TWModal } from "./base/modal/TWModal";
import Box from "./base/Box";
import { useAppTheme } from "../styles/hooks";
// import { useAppTheme } from "../styles/hooks";
const MODAL_HEIGHT = Dimensions.get("window").height * 0.6;
const DEVICE_WIDTH = Dimensions.get("window").width;
export const MainModal = () => {
const theme = useAppTheme();
const theme = useGlobalTheme();
const { modalState } = useModalState();
const { isOpen, isSheet } = modalState;
@@ -3,14 +3,14 @@ import Box from "./base/Box";
import { useState } from "react";
import EyeClosed from "../assets/eye-closed";
import EyeOpened from "../assets/eye-opened";
import { useAppTheme } from "../styles/hooks";
import { useGlobalTheme } from "../providers/ui-context-provider";
export const PasswordInput = ({
onChangeText,
}: {
onChangeText: TextInput["props"]["onChangeText"];
}) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
const [showPassword, setShowPassword] = useState(false);
const onPressEyeIcon = () => {
@@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react";
import { IconTextButton } from "./base/IconTextButton";
import { useAddress } from "@thirdweb-dev/react-core";
import { Dimensions, KeyboardAvoidingView } from "react-native";
import { useAppTheme } from "../styles/hooks";
import {
TWModal,
Box,
@@ -15,9 +14,10 @@ import {
import DownloadIcon from "../assets/download";
import CopyIcon from "../assets/copy";
import QRCode from "react-native-qrcode-svg";
import { useGlobalTheme } from "../providers/ui-context-provider";
export const ReceiveButton = () => {
const theme = useAppTheme();
const theme = useGlobalTheme();
const [isModalVisible, setIsModalVisible] = useState(false);
const onClose = () => {
@@ -60,7 +60,7 @@ export const ReceiveFundsModal = ({
isVisible,
onClose,
}: ReceiveFundsModalProps) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
const address = useAddress();
const [addressCopied, setAddressCopied] = useState(false);
@@ -1,4 +1,3 @@
import { useAppTheme } from "../../styles/hooks";
import React, { useEffect, useMemo, useState } from "react";
import SendIcon from "../../assets/send";
import {
@@ -30,13 +29,14 @@ import { utils } from "ethers";
import LoadingTextAnimation from "../base/LoadingTextAnimation";
import CheckIcon from "../../assets/check";
import { TokenSelector } from "./TokenSelector";
import { useGlobalTheme } from "../../providers/ui-context-provider";
export const SendButton = ({
supportedTokens,
}: {
supportedTokens: SupportedTokens;
}) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
const [isModalVisible, setIsModalVisible] = useState(false);
const onClose = () => {
@@ -139,7 +139,7 @@ const SendFundsForm = ({
onTokenSelectorPress: () => void;
token?: TokenInfo;
}) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
const chain = useChain();
const wallet = useWallet();
const chainId = useChainId();
@@ -352,7 +352,7 @@ const SendFundsForm = ({
) : showIcon ? (
<CheckIcon width={20} height={13} color={theme.colors.textPrimary} />
) : (
<Text variant="bodySmall" mr="sm">
<Text variant="bodySmall" color="accentButtonTextColor" mr="sm">
Send
</Text>
)}
@@ -15,10 +15,10 @@ import {
ScrollView,
TextInput,
} from "react-native";
import { useAppTheme } from "../../styles/hooks";
import { SelectTokenButton } from "./SelectTokenButton";
import CloseIcon from "../../assets/close";
import Text from "../base/Text";
import { useGlobalTheme } from "../../providers/ui-context-provider";
export function useToken(tokenAddress: string): {
isLoading: boolean;
@@ -82,7 +82,7 @@ export function TokenSelector(props: {
onBack: () => void;
supportedTokens: SupportedTokens;
}) {
const theme = useAppTheme();
const theme = useGlobalTheme();
const [input, setInput] = useState("");
const chainId = useChainId();
const nativeTokenInfo = useNativeToken();
@@ -1,7 +1,7 @@
import React, { useCallback, useEffect, useRef } from "react";
import { View, Animated, Easing, StyleSheet } from "react-native";
import { baseTheme } from "../../styles/theme";
import { useAppTheme } from "../../styles/hooks";
import { useGlobalTheme } from "../../providers/ui-context-provider";
type LoadingTextAnimationProps = {
text: string;
@@ -13,7 +13,7 @@ const LoadingTextAnimation = ({
textVariant,
}: LoadingTextAnimationProps) => {
const fadeAnim = useRef(new Animated.Value(0)).current;
const theme = useAppTheme();
const theme = useGlobalTheme();
const fadeInOut = useCallback(() => {
Animated.loop(
@@ -14,8 +14,8 @@ import { useSwitchChain, useSupportedChains } from "@thirdweb-dev/react-core";
import Box from "./Box";
import { ModalHeaderTextClose } from "./modal/ModalHeaderTextClose";
import { TWModal } from "./modal/TWModal";
import { useAppTheme } from "../../styles/hooks";
import { Chain } from "@thirdweb-dev/chains";
import { useGlobalTheme } from "../../providers/ui-context-provider";
type NetworkButtonProps = {
chain?: Chain;
@@ -35,7 +35,7 @@ export const NetworkButton = ({
padding,
...props
}: NetworkButtonProps) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
const [isModalVisible, setIsModalVisible] = useState(false);
const [switchError, setSwitchError] = useState<string | undefined>();
const [isSwitching, setIsSwitching] = useState(false);
@@ -2,7 +2,7 @@ import { ReactElement, useEffect, useRef } from "react";
import { Theme } from "../../styles/theme";
import Text from "./Text";
import { Animated, StyleSheet } from "react-native";
import { useAppTheme } from "../../styles/hooks";
import { useGlobalTheme } from "../../providers/ui-context-provider";
export const TOAST_HEIGHT = 45;
@@ -19,7 +19,7 @@ export function Toast({
backgroundColor,
translateY = TOAST_HEIGHT,
}: ToastProps) {
const theme = useAppTheme();
const theme = useGlobalTheme();
const translateYRef = useRef(new Animated.Value(translateY)).current;
@@ -1,4 +1,4 @@
import { useAppTheme } from "../../styles/hooks";
import { useGlobalTheme } from "../../providers/ui-context-provider";
import BaseButton from "./BaseButton";
import Box from "./Box";
import ImageSvgUri from "./ImageSvgUri";
@@ -17,7 +17,7 @@ export const WalletButtonSquare = ({
name,
size,
}: WalletButtonSquareProps) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
const marginVertical = theme.spacing.xs;
return (
@@ -1,6 +1,6 @@
import { useGlobalTheme } from "../../../providers/ui-context-provider";
import Text from "../Text";
import { TouchableOpacity, StyleSheet, ActivityIndicator } from "react-native";
import { useAppTheme } from "../../../styles/hooks";
export const ModalFooter = ({
footer,
@@ -11,7 +11,7 @@ export const ModalFooter = ({
isLoading?: boolean;
onPress?: () => void;
}) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
return (
<TouchableOpacity style={styles.footer} onPress={onPress}>
@@ -1,9 +1,9 @@
import { View } from "react-native";
import { Icon } from "../../../assets/icon";
import { useAppTheme } from "../../../styles/hooks";
import Box from "../Box";
import Text from "../Text";
import { ReactNode } from "react";
import { useGlobalTheme } from "../../../providers/ui-context-provider";
interface ModalHeaderTextCloseProps {
onClose?: () => void;
@@ -19,7 +19,7 @@ export const ModalHeaderTextClose = ({
onBackPress,
...props
}: ModalHeaderTextCloseProps & React.ComponentProps<typeof Box>) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
return (
<>
@@ -78,7 +78,7 @@ export const useGlobalTheme = (theme?: ThemeProviderProps["theme"]): Theme => {
const appTheme = useTheme();
const resultTheme = useMemo(() => {
const resp = getThemeObj(theme) || getThemeObj(context.theme) || appTheme;
const resp = getThemeObj(context.theme) || getThemeObj(theme) || appTheme;
return resp;
}, [theme, context, appTheme]);
@@ -12,12 +12,12 @@ import {
TextInput,
TextInputKeyPressEventData,
} from "react-native";
import { useAppTheme } from "../../../styles/hooks";
import { ConnectWalletHeader } from "../../../components/ConnectWalletFlow/ConnectingWallet/ConnectingWalletHeader";
import Box from "../../../components/base/Box";
import Text from "../../../components/base/Text";
import BaseButton from "../../../components/base/BaseButton";
import * as Clipboard from "expo-clipboard";
import { useGlobalTheme } from "../../../providers/ui-context-provider";
const OTP_LENGTH = 6;
@@ -27,7 +27,7 @@ export const EmbeddedConnectionUI: React.FC<ConnectUIProps<EmbeddedWallet>> = ({
selectionData,
onLocallyConnected,
}) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
const inputRefs = useRef<(TextInput | null)[]>([]);
const [values, setValues] = useState<string[]>(
new Array(OTP_LENGTH).fill(""),
@@ -1,7 +1,6 @@
import React, { useEffect, useState } from "react";
import { EmbeddedWallet } from "./EmbeddedWallet";
import { ActivityIndicator } from "react-native";
import { useAppTheme } from "../../../styles/hooks";
import {
SelectUIProps,
useCreateWalletInstance,
@@ -10,6 +9,7 @@ import Box from "../../../components/base/Box";
import Text from "../../../components/base/Text";
import BaseButton from "../../../components/base/BaseButton";
import { TextInput } from "../../../components/base/TextInput";
import { useGlobalTheme } from "../../../providers/ui-context-provider";
/**
* UI for selecting wallet - this UI is rendered in the wallet selection screen
@@ -18,7 +18,7 @@ export const EmailSelectionUI: React.FC<SelectUIProps<EmbeddedWallet>> = ({
onSelect,
walletConfig,
}) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
const [email, setEmail] = useState<string>("");
const [errorMessage, setErrorMessage] = useState<string>("");
const [isFetching, setIsFetching] = useState<boolean>(false);
@@ -17,9 +17,9 @@ import { TextInput } from "../../components/base/TextInput";
import Text from "../../components/base/Text";
import { useMagicLink } from "../../providers/context-provider";
import BaseButton from "../../components/base/BaseButton";
import { useAppTheme } from "../../styles/hooks";
import React from "react";
import { ConnectingWallet } from "../../components/ConnectWalletFlow/ConnectingWallet/ConnectingWallet";
import { useGlobalTheme } from "../../providers/ui-context-provider";
export const magicLink = (
magicLinkOptions: MagicLinkOptions & { recommended?: boolean },
@@ -54,7 +54,7 @@ export const magicLink = (
};
const MagicSelectionUI: React.FC<SelectUIProps<MagicLink>> = (props) => {
const theme = useAppTheme();
const theme = useGlobalTheme();
const [email, setEmail] = React.useState("");
const onContinuePress = () => {
@@ -19,9 +19,9 @@ import {
useSetConnectionStatus,
} from "@thirdweb-dev/react-core";
import { WalletConnect } from "./WalletConnect";
import { useAppTheme } from "../../../styles/hooks";
import { WalletConnectButton } from "./WalletConnectButton";
import { ModalHeaderTextClose } from "../../../components/base";
import { useGlobalTheme } from "../../../providers/ui-context-provider";
type WCWallet = {
iconURL: string;
@@ -41,7 +41,7 @@ export function WalletConnectUI({
goBack,
projectId,
}: ConnectUIProps<WalletConnect> & { projectId: string }) {
const theme = useAppTheme();
const theme = useGlobalTheme();
const [wallets, setWallets] = useState<WCWallet[]>([]);
const [error, setError] = useState<string | undefined>();
const [loading, setLoading] = useState<boolean>(true);
@@ -1,7 +1,7 @@
import { useEffect, useRef } from "react";
import { Animated, Easing, StyleSheet, View } from "react-native";
import Svg, { Rect } from "react-native-svg";
import { useAppTheme } from "../../../styles/hooks";
import { useGlobalTheme } from "../../../providers/ui-context-provider";
const AnimatedRect = Animated.createAnimatedComponent(Rect);
@@ -19,7 +19,7 @@ function WalletLoadingThumbnail({
showError,
imageSize = 50,
}: Props) {
const Theme = useAppTheme();
const Theme = useGlobalTheme();
const spinValue = useRef(new Animated.Value(0));
useEffect(() => {
+11
View File
@@ -1,5 +1,16 @@
# @thirdweb-dev/react
## 4.0.2
### Patch Changes
- [#1750](https://github.com/thirdweb-dev/js/pull/1750) [`bb1666b9`](https://github.com/thirdweb-dev/js/commit/bb1666b92b5e151d78ea7dae6831297fb947d954) Thanks [@MananTank](https://github.com/MananTank)! - ConnectWallet UI tweaks/fixes
- Updated dependencies [[`1f3c64d3`](https://github.com/thirdweb-dev/js/commit/1f3c64d3618903b9008cc7b633ea890b508e7800), [`74941603`](https://github.com/thirdweb-dev/js/commit/74941603a96456da46a47147f67c98235ac55022), [`4b98e487`](https://github.com/thirdweb-dev/js/commit/4b98e487d4b47225d7095e5444dc5e7608db48a3), [`693f349d`](https://github.com/thirdweb-dev/js/commit/693f349db2478e1cd0fc82a9ef9882f46832b125), [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9), [`0f12d1f9`](https://github.com/thirdweb-dev/js/commit/0f12d1f90320923309f085c372d3a5ed01dd4606), [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e), [`63ad0050`](https://github.com/thirdweb-dev/js/commit/63ad0050f0a24ec15b90933b5664d697618cf2d0)]:
- @thirdweb-dev/sdk@4.0.1
- @thirdweb-dev/wallets@2.0.2
- @thirdweb-dev/react-core@4.0.2
## 4.0.1
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react",
"version": "4.0.1",
"version": "4.0.2",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+17 -2
View File
@@ -1,7 +1,22 @@
import styled from "@emotion/styled";
import { fontSize, Theme } from "../design-system";
import { fontSize, spacing, Theme } from "../design-system";
export const TextDivider = styled.div<{ theme?: Theme }>`
export const TextDivider = (props: {
text: string;
py?: keyof typeof spacing;
}) => {
return (
<TextDividerEl
style={{
paddingBlock: props.py ? spacing[props.py] : 0,
}}
>
<span> {props.text}</span>
</TextDividerEl>
);
};
export const TextDividerEl = styled.div<{ theme?: Theme }>`
display: flex;
align-items: center;
color: ${(p) => p.theme.colors.secondaryText};
+2 -2
View File
@@ -63,13 +63,13 @@ function createThemeObj(colors: typeof darkColors) {
scrollbarBg: colors.base2,
walletSelectorButtonHoverBg: colors.base2,
separatorLine: colors.base3,
separatorLine: colors.base4,
secondaryIconColor: colors.secondaryText,
secondaryIconHoverBg: colors.base3,
secondaryIconHoverColor: colors.primaryText,
borderColor: colors.base3,
borderColor: colors.base4,
skeletonBg: colors.base3,
selectedTextColor: colors.base1,
+1
View File
@@ -62,4 +62,5 @@ export {
MagicLink,
SignerWallet,
InjectedWallet,
setWalletAnalyticsEnabled,
} from "@thirdweb-dev/wallets";
@@ -290,7 +290,7 @@ export function SendFundsForm(props: {
</CurrencyBadge>
</Container>
<Spacer y="xl" />
<Spacer y="xxl" />
{/* Submit */}
<Button
@@ -307,6 +307,7 @@ export function SendFundsForm(props: {
style={{
alignItems: "center",
gap: spacing.sm,
padding: spacing.md,
}}
>
{sendTokenMutation.isLoading ? "Sending" : "Send"}
@@ -56,20 +56,6 @@ export const WalletSelector: React.FC<{
nonLocalWalletConfigs.filter((w) => w.category !== "socialLogin"),
);
const showNewToWallets =
isCompact && (socialWallets.length === 0 || isWalletGroupExpanded);
// groups UI is showing a social login + grouping all eoa wallets together in a group
// do this if there is social login and more than 2 eoa wallets
const showGroupsUI =
isCompact && socialWallets.length >= 1 && eoaWallets.length >= 2;
const showTOS = isCompact && (termsOfServiceUrl || privacyPolicyUrl);
const showFooter = Boolean(
(!showGroupsUI && localWalletConfig) || showNewToWallets,
);
const continueAsGuest = localWalletConfig && (
<Button
fullWidth
@@ -138,7 +124,217 @@ export const WalletSelector: React.FC<{
props.selectWallet(wallet);
};
const showSeperatorLine = showNewToWallets && !continueAsGuest && showTOS;
const connectAWallet = (
<Button
fullWidth
variant="outline"
style={{
display: "flex",
justifyContent: "center",
gap: spacing.sm,
padding: spacing.md,
}}
onClick={() => {
setIsWalletGroupExpanded(true);
}}
>
<Container flex="row" gap="xxs">
{eoaWallets.slice(0, 2).map((w) => (
<Img
key={w.id}
width={iconSize.sm}
height={iconSize.sm}
src={w.meta.iconURL}
/>
))}
</Container>
Connect a wallet
</Button>
);
const newToWallets = (
<Container
flex="row"
style={{
justifyContent: "space-between",
}}
>
<Text color="secondaryText" size="sm" weight={500}>
New to wallets?
</Text>
<Link
weight={500}
size="sm"
target="_blank"
href="https://blog.thirdweb.com/web3-wallet/"
>
Get started
</Link>
</Container>
);
const tos =
termsOfServiceUrl || privacyPolicyUrl ? (
<TOS
termsOfServiceUrl={termsOfServiceUrl}
privacyPolicyUrl={privacyPolicyUrl}
/>
) : undefined;
let topSection: React.ReactNode;
let bottomSection: React.ReactNode;
// wide modal
if (!isCompact) {
topSection = (
<WalletSelection
walletConfigs={nonLocalWalletConfigs}
selectWallet={handleSelect}
/>
);
if (continueAsGuest) {
bottomSection = (
<ScreenBottomContainer>{continueAsGuest}</ScreenBottomContainer>
);
}
}
// compact
else {
// no social logins
if (socialWallets.length === 0) {
topSection = (
<WalletSelection
walletConfigs={nonLocalWalletConfigs}
selectWallet={handleSelect}
/>
);
bottomSection = (
<>
<Line />
<Container flex="column" p="lg" gap="lg">
{newToWallets}
{continueAsGuest}
</Container>
{!continueAsGuest && <Line />}
{tos && (
<Container
px="md"
style={{
paddingBottom: spacing.md,
paddingTop: continueAsGuest ? 0 : spacing.md,
}}
>
{tos}
</Container>
)}
</>
);
}
// social logins
else {
// not expanded state
if (!isWalletGroupExpanded) {
topSection = (
<Container px="xs">
<WalletSelection
walletConfigs={socialWallets}
selectWallet={handleSelect}
/>
{eoaWallets.length > 0 && (
<>
<TextDivider text="OR" />
<Spacer y="lg" />
</>
)}
</Container>
);
// only social login - no eoa wallets
if (eoaWallets.length === 0) {
bottomSection = tos ? (
<>
<Spacer y="md" />
<Line />
{continueAsGuest && (
<Container p="lg"> {continueAsGuest}</Container>
)}
{tos && <Container p="md"> {tos} </Container>}
</>
) : (
<Spacer y="sm" />
);
}
// social login + eoa wallets
else {
// social login + More than 1 eoa wallets
if (eoaWallets.length > 1) {
bottomSection = (
<Container flex="column" gap="sm">
<Container px="lg" flex="column" gap="md">
{connectAWallet}
{continueAsGuest}
</Container>
{tos ? (
<Container p="md"> {tos} </Container>
) : (
<Spacer y="md" />
)}
</Container>
);
}
// social login + single eoa wallet
else {
bottomSection = (
<>
<Container px="lg">
<WalletSelection
walletConfigs={eoaWallets}
selectWallet={handleSelect}
/>
</Container>
{continueAsGuest && (
<Container flex="column" px="lg" gap="lg">
{continueAsGuest}
</Container>
)}
{tos ? (
<>
{continueAsGuest ? <Spacer y="md" /> : <Line />}
<Container p="md"> {tos} </Container>
</>
) : (
<>{continueAsGuest && <Spacer y="xl" />}</>
)}
</>
);
}
}
}
// expanded state
else {
topSection = (
<WalletSelection
walletConfigs={eoaWallets}
selectWallet={handleSelect}
/>
);
bottomSection = (
<ScreenBottomContainer>{newToWallets}</ScreenBottomContainer>
);
}
}
}
return (
<Container scrollY flex="column" animate="fadein" fullHeight>
@@ -160,130 +356,15 @@ export const WalletSelector: React.FC<{
<Container
expand
scrollY
px={nonLocalWalletConfigs.length === 1 ? "lg" : "md"}
px="md"
style={{
paddingTop: "2px",
}}
>
{showGroupsUI ? (
<>
{/* list of EOA wallets */}
{isWalletGroupExpanded ? (
<WalletSelection
walletConfigs={eoaWallets}
selectWallet={handleSelect}
/>
) : (
<Container px="xs">
<WalletSelection
walletConfigs={socialWallets}
selectWallet={handleSelect}
/>
<TextDivider>
<span> OR </span>
</TextDivider>
<Spacer y="lg" />
{/* connect a wallet */}
<Button
fullWidth
variant="outline"
style={{
display: "flex",
justifyContent: "center",
gap: spacing.sm,
padding: spacing.md,
}}
onClick={() => {
setIsWalletGroupExpanded(true);
}}
>
<Container flex="row" gap="xxs">
{eoaWallets.slice(0, 2).map((w) => (
<Img
key={w.id}
width={iconSize.sm}
height={iconSize.sm}
src={w.meta.iconURL}
/>
))}
</Container>
Connect a wallet
</Button>
{continueAsGuest ? (
<>
<Spacer y="md" />
{continueAsGuest}
<Spacer y="xl" />
</>
) : (
<Spacer y="xl" />
)}
</Container>
)}
</>
) : (
<WalletSelection
walletConfigs={nonLocalWalletConfigs}
selectWallet={handleSelect}
/>
)}
{topSection}
</Container>
{/* Footer */}
{showFooter && (
<ScreenBottomContainer>
{showNewToWallets && (
<Container
flex="row"
style={{
justifyContent: "space-between",
}}
>
<Text color="secondaryText" size="sm" weight={500}>
New to wallets?
</Text>
<Link
weight={500}
size="sm"
target="_blank"
href="https://blog.thirdweb.com/web3-wallet/"
>
Get started
</Link>
</Container>
)}
{!showGroupsUI && continueAsGuest}
</ScreenBottomContainer>
)}
{showTOS && !isWalletGroupExpanded && (
<div>
{showSeperatorLine && <Line />}
<Container
p="md"
style={
!showSeperatorLine
? {
paddingTop: 0,
}
: undefined
}
>
{isCompact && (
<TOS
termsOfServiceUrl={termsOfServiceUrl}
privacyPolicyUrl={privacyPolicyUrl}
/>
)}
</Container>
</div>
)}
{bottomSection}
</Container>
);
};
@@ -383,7 +464,7 @@ const WalletList = styled.ul<{ theme?: Theme }>`
margin: -2px;
padding-bottom: 0;
margin-bottom: 0;
padding-bottom: ${spacing.xl};
padding-bottom: ${spacing.lg};
`;
const WalletButton = styled.button<{ theme?: Theme }>`
@@ -428,7 +509,7 @@ function sortWalletConfigs(walletConfigs: WalletConfig[]) {
}
return 0;
})
// show the reccomended wallets even before that
// show the recommended wallets even before that
.sort((a, b) => {
if (a.recommended && !b.recommended) {
return -1;
@@ -64,15 +64,7 @@ export const EmbeddedWalletFormUI = (props: {
<GoogleIcon size={iconSize.md} />
Sign in with Google
</SocialButton>
<Spacer y="lg" />
<TextDivider>
<span>OR</span>
</TextDivider>
<Spacer y="lg" />
<TextDivider text="OR" py="lg" />
<InputSelectionUI
onSelect={(email) => props.onSelect({ email })}
placeholder="Enter your email address"
@@ -114,10 +114,10 @@ export const EmbeddedWalletOTPLoginUI: React.FC<
}}
>
{!isWideModal && <Spacer y="xl" />}
<Text>Enter the OTP sent to</Text>
<Text>Enter the verification code sent to</Text>
<Spacer y="sm" />
<Text color="primaryText">{email}</Text>
<Spacer y="xxl" />
<Spacer y="xl" />
</div>
<OTPInput
@@ -138,12 +138,12 @@ export const EmbeddedWalletOTPLoginUI: React.FC<
<FadeIn>
<Spacer y="md" />
<Text size="sm" color="danger" center>
Invalid OTP
Invalid verification code
</Text>
</FadeIn>
)}
<Spacer y="xxl" />
<Spacer y="xl" />
<Container px={isWideModal ? "xxl" : "lg"}>
{verifyStatus === "verifying" ? (
@@ -168,7 +168,7 @@ export const EmbeddedWalletOTPLoginUI: React.FC<
)}
</Container>
<Spacer y="xxl" />
<Spacer y="xl" />
{!isWideModal && <Line />}
@@ -176,7 +176,7 @@ export const EmbeddedWalletOTPLoginUI: React.FC<
{sendEmailOtpStatus === "error" && (
<>
<Text size="sm" center color="danger">
Failed to send OTP
Failed to send verification code
</Text>
</>
)}
@@ -190,14 +190,14 @@ export const EmbeddedWalletOTPLoginUI: React.FC<
textAlign: "center",
}}
>
<Text size="sm">Sending OTP</Text>
<Text size="sm">Sending verification code</Text>
<Spinner size="xs" color="secondaryText" />
</Container>
)}
{sendEmailOtpStatus === "sent" && (
<LinkButton onClick={sendEmail} type="button">
Resend OTP
Resend verification code
</LinkButton>
)}
</Container>
@@ -256,11 +256,7 @@ const MagicUI: React.FC<{
{showInputUI && (
<>
{showSeparator && (
<TextDivider>
<span> OR </span>
</TextDivider>
)}
{showSeparator && <TextDivider text="OR" />}
<InputSelectionUI
onSelect={props.onSelect}
placeholder={placeholder}
@@ -67,13 +67,7 @@ export const PaperFormUI = (props: {
Sign in with Google
</SocialButton>
<Spacer y="lg" />
<TextDivider>
<span>OR</span>
</TextDivider>
<Spacer y="lg" />
<TextDivider text="OR" py="lg" />
</>
)}
@@ -2,7 +2,6 @@ import styled from "@emotion/styled";
import { ConnectUIProps, useWalletContext } from "@thirdweb-dev/react-core";
import { PaperWallet } from "@thirdweb-dev/wallets";
import { useCallback, useEffect, useRef, useState } from "react";
import { FadeIn } from "../../../components/FadeIn";
import { OTPInput } from "../../../components/OTPInput";
import { Spacer } from "../../../components/Spacer";
import { Spinner } from "../../../components/Spinner";
@@ -135,7 +134,7 @@ export const PaperOTPLoginUI: React.FC<PaperOTPLoginUIProps> = (props) => {
}}
>
{!isWideModal && <Spacer y="lg" />}
<Text>Enter the OTP sent to</Text>
<Text>Enter the verification code sent to</Text>
<Spacer y="sm" />
<Text color="primaryText">{email}</Text>
<Spacer y="xl" />
@@ -159,6 +158,7 @@ export const PaperOTPLoginUI: React.FC<PaperOTPLoginUIProps> = (props) => {
{recoveryCodeRequired && (
<Container
animate="fadein"
px="lg"
style={{
textAlign: "center",
@@ -197,15 +197,16 @@ export const PaperOTPLoginUI: React.FC<PaperOTPLoginUIProps> = (props) => {
)}
{verifyStatus === "invalid" && (
<FadeIn>
<Container animate="fadein">
<Spacer y="md" />
<Text size="sm" color="danger" center>
Invalid OTP {recoveryCodeRequired ? "or recovery code" : ""}
Invalid verification code{" "}
{recoveryCodeRequired ? "or recovery code" : ""}
</Text>
</FadeIn>
</Container>
)}
<Spacer y={recoveryCodeRequired ? "xl" : "xxl"} />
<Spacer y="xl" />
<Container px={isWideModal ? "xxl" : "lg"}>
{verifyStatus === "verifying" ? (
@@ -230,15 +231,15 @@ export const PaperOTPLoginUI: React.FC<PaperOTPLoginUIProps> = (props) => {
)}
</Container>
<Spacer y={recoveryCodeRequired ? "xl" : "xxl"} />
<Spacer y={"xl"} />
{!isWideModal && <Line />}
<Container p={isWideModal ? undefined : "lg"}>
<Container p={isWideModal ? undefined : "lg"} animate="fadein">
{sendEmailStatus === "error" && (
<>
<Text size="sm" center color="danger">
Failed to send OTP
Failed to send verification code
</Text>
</>
)}
@@ -252,14 +253,14 @@ export const PaperOTPLoginUI: React.FC<PaperOTPLoginUIProps> = (props) => {
textAlign: "center",
}}
>
<Text size="sm">Sending OTP</Text>
<Text size="sm">Sending verification code</Text>
<Spinner size="xs" color="secondaryText" />
</Container>
)}
{typeof sendEmailStatus !== "string" && (
<LinkButton onClick={sendEmail} type="button">
Resend OTP
Resend verification code
</LinkButton>
)}
</Container>
+15
View File
@@ -1,5 +1,20 @@
# @thirdweb-dev/sdk
## 4.0.1
### Patch Changes
- [#1747](https://github.com/thirdweb-dev/js/pull/1747) [`1f3c64d3`](https://github.com/thirdweb-dev/js/commit/1f3c64d3618903b9008cc7b633ea890b508e7800) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Handle upgradeable proxies and optimize proxy resolution
- [#1695](https://github.com/thirdweb-dev/js/pull/1695) [`693f349d`](https://github.com/thirdweb-dev/js/commit/693f349db2478e1cd0fc82a9ef9882f46832b125) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Add optional pagination to getOwned NFTs
- [#1746](https://github.com/thirdweb-dev/js/pull/1746) [`0f12d1f9`](https://github.com/thirdweb-dev/js/commit/0f12d1f90320923309f085c372d3a5ed01dd4606) Thanks [@farhanW3](https://github.com/farhanW3)! - Fix for RPC Override Implementation to get user provided Url and not default RPC Url for the chain
- [#1757](https://github.com/thirdweb-dev/js/pull/1757) [`63ad0050`](https://github.com/thirdweb-dev/js/commit/63ad0050f0a24ec15b90933b5664d697618cf2d0) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Update deployment and tests for MarketplaceV3 latest
- Updated dependencies [[`63ad0050`](https://github.com/thirdweb-dev/js/commit/63ad0050f0a24ec15b90933b5664d697618cf2d0)]:
- @thirdweb-dev/contracts-js@1.3.14
## 4.0.0
### Major Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/sdk",
"version": "4.0.0",
"version": "4.0.1",
"description": "The main thirdweb SDK.",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
"license": "Apache-2.0",
@@ -135,7 +135,7 @@ export async function encodeConstructorParamsForImplementation(
compilerMetadata.abi,
);
const constructorParamTypes = constructorParams.map((p) => {
if (p.type === "tuple[]") {
if (p.type === "tuple[]" || p.type === "tuple") {
return utils.ParamType.from(p);
} else {
return p.type;
@@ -156,31 +156,13 @@ export async function encodeConstructorParamsForImplementation(
return constructorParamMap[p.name].value;
}
if (p.name && p.name.includes("nativeTokenWrapper")) {
const chainId = (await provider.getNetwork()).chainId;
let nativeTokenWrapperAddress =
getNativeTokenByChainId(chainId).wrapped.address;
if (nativeTokenWrapperAddress === constants.AddressZero) {
const deploymentInfo = await computeDeploymentInfo(
"infra",
provider,
storage,
create2Factory,
{
contractName: "WETH9",
},
clientId,
secretKey,
);
if (!caches.deploymentPresets["WETH9"]) {
caches.deploymentPresets["WETH9"] = deploymentInfo;
}
nativeTokenWrapperAddress =
deploymentInfo.transaction.predictedAddress;
}
return nativeTokenWrapperAddress;
return await nativeTokenInputArg(
provider,
storage,
create2Factory,
clientId,
secretKey,
);
} else if (p.name && p.name.includes("trustedForwarder")) {
if (compilerMetadata.name === "Pack") {
// EOAForwarder for Pack
@@ -220,6 +202,27 @@ export async function encodeConstructorParamsForImplementation(
} else if (p.name && p.name.includes("royaltyEngineAddress")) {
const chainId = (await provider.getNetwork()).chainId;
return getRoyaltyEngineV1ByChainId(chainId);
} else if (p.name && p.name.includes("marketplaceV3Params")) {
const chainId = (await provider.getNetwork()).chainId;
const royaltyEngineAddress = getRoyaltyEngineV1ByChainId(chainId);
const nativeTokenWrapper = await nativeTokenInputArg(
provider,
storage,
create2Factory,
clientId,
secretKey,
);
const extensions = constructorParamMap
? constructorParamMap["_extensions"].value
: [];
return {
extensions: extensions,
royaltyEngineAddress: royaltyEngineAddress,
nativeTokenWrapper: nativeTokenWrapper,
};
} else {
throw new Error("Can't resolve constructor arguments");
}
@@ -232,3 +235,36 @@ export async function encodeConstructorParamsForImplementation(
);
return encodedArgs;
}
async function nativeTokenInputArg(
provider: providers.Provider,
storage: ThirdwebStorage,
create2Factory: string,
clientId?: string,
secretKey?: string,
): Promise<string> {
const chainId = (await provider.getNetwork()).chainId;
let nativeTokenWrapperAddress =
getNativeTokenByChainId(chainId).wrapped.address;
if (nativeTokenWrapperAddress === constants.AddressZero) {
const deploymentInfo = await computeDeploymentInfo(
"infra",
provider,
storage,
create2Factory,
{
contractName: "WETH9",
},
clientId,
secretKey,
);
if (!caches.deploymentPresets["WETH9"]) {
caches.deploymentPresets["WETH9"] = deploymentInfo;
}
nativeTokenWrapperAddress = deploymentInfo.transaction.predictedAddress;
}
return nativeTokenWrapperAddress;
}
@@ -1,4 +1,4 @@
import { BigNumber, providers, constants, utils } from "ethers";
import { BigNumber, providers, constants, utils, Contract } from "ethers";
import { extractIPFSHashFromBytecode } from "./extractIPFSHashFromBytecode";
import { extractMinimalProxyImplementationAddress } from "./extractMinimalProxyImplementationAddress";
@@ -33,32 +33,65 @@ export async function resolveImplementation(
address: string,
provider: providers.Provider,
): Promise<{ address: string; bytecode: string }> {
let bytecode;
const bytecode = await fetchBytecode(address, provider);
// check minimal proxy first synchronously
const minimalProxyImplementationAddress =
extractMinimalProxyImplementationAddress(bytecode);
if (minimalProxyImplementationAddress) {
return {
address: minimalProxyImplementationAddress,
bytecode: await fetchBytecode(
minimalProxyImplementationAddress,
provider,
),
};
}
// check other proxy types
const impl = await Promise.all([
getImplementationFromStorageSlot(address, provider),
getImplementationFromContractCall(address, provider),
]);
for (const implementationAddress of impl) {
if (
implementationAddress &&
utils.isAddress(implementationAddress) &&
implementationAddress !== constants.AddressZero
) {
return {
address: implementationAddress,
bytecode: await fetchBytecode(implementationAddress, provider),
};
}
}
return { address, bytecode };
}
async function fetchBytecode(
address: string,
provider: providers.Provider,
): Promise<string> {
try {
bytecode = await provider.getCode(address);
const bytecode = await provider.getCode(address);
if (bytecode === "0x") {
const chain = await provider.getNetwork();
throw new Error(
`Contract at ${address} does not exist on chain '${chain.name}' (chainId: ${chain.chainId})`,
);
}
return bytecode;
} catch (e) {
throw new Error(`Failed to get bytecode for address ${address}: ${e}`);
}
}
if (bytecode === "0x") {
const chain = await provider.getNetwork();
throw new Error(
`Contract at ${address} does not exist on chain '${chain.name}' (chainId: ${chain.chainId})`,
);
}
try {
// TODO support other types of proxies
const implementationAddress =
extractMinimalProxyImplementationAddress(bytecode);
if (implementationAddress) {
return await resolveImplementation(implementationAddress, provider);
}
} catch (e) {
// ignore
}
// EIP-1967 proxy storage slots - https://eips.ethereum.org/EIPS/eip-1967
async function getImplementationFromStorageSlot(
address: string,
provider: providers.Provider,
): Promise<string | undefined> {
try {
const proxyStorage = await provider.getStorageAt(
address,
@@ -66,18 +99,36 @@ export async function resolveImplementation(
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc",
),
);
const implementationAddress = `0x${proxyStorage.slice(-40)}`;
if (
utils.isAddress(implementationAddress) &&
implementationAddress !== constants.AddressZero
) {
return await resolveImplementation(implementationAddress, provider);
}
return `0x${proxyStorage.slice(-40)}`;
} catch (e) {
// ignore
return undefined;
}
if (!bytecode) {
throw new Error(`Error fetching bytecode for ${address}`);
}
return { address, bytecode };
}
async function getImplementationFromContractCall(
address: string,
provider: providers.Provider,
): Promise<string | undefined> {
try {
const proxy = new Contract(address, UPGRADEABLE_PROXY_ABI, provider);
return await proxy.implementation();
} catch (e) {
return undefined;
}
}
const UPGRADEABLE_PROXY_ABI = [
{
type: "function",
name: "implementation",
inputs: [],
outputs: [
{
type: "address",
name: "",
internalType: "address",
},
],
stateMutability: "view",
},
];
@@ -14,7 +14,7 @@ import IMintableERC721Abi from "@thirdweb-dev/contracts-js/dist/abis/IMintableER
import MulticallAbi from "@thirdweb-dev/contracts-js/dist/abis/IMulticall.json";
import SignatureMintERC721Abi from "@thirdweb-dev/contracts-js/dist/abis/ISignatureMintERC721.json";
import SignatureMintERC721_V1Abi from "@thirdweb-dev/contracts-js/dist/abis/ISignatureMintERC721_V1.json";
import TieredDropAbi from "@thirdweb-dev/contracts-js/dist/abis/LazyMintWithTier.json";
import TieredDropAbi from "@thirdweb-dev/contracts-js/dist/abis/LazyMintWithTier_V1.json";
import SharedMetadataAbi from "@thirdweb-dev/contracts-js/dist/abis/SharedMetadata.json";
import zora_IDropERC721 from "@thirdweb-dev/contracts-js/dist/abis/zora_IERC721Drop.json";
import ILoyaltyCardAbi from "@thirdweb-dev/contracts-js/dist/abis/ILoyaltyCard.json";
+1 -1
View File
@@ -44,7 +44,7 @@ export function getChainProvider(
options.supportedChains = [
// @ts-expect-error - we know this is a chain and it will work to build the map
network,
...options.supportedChains.filter((c) => c.chainId !== network.chainId),
...options.supportedChains.filter((c) => c.chainId === network.chainId),
];
}
@@ -216,8 +216,11 @@ export class EditionDrop extends StandardErc1155<PrebuiltEditionDrop> {
*
* @returns The NFT metadata for all NFTs in the contract.
*/
public async getOwned(walletAddress?: AddressOrEns): Promise<NFT[]> {
return this.erc1155.getOwned(walletAddress);
public async getOwned(
walletAddress?: AddressOrEns,
queryParams?: QueryAllParams,
): Promise<NFT[]> {
return this.erc1155.getOwned(walletAddress, queryParams);
}
/**
@@ -190,8 +190,11 @@ export class Edition extends StandardErc1155<TokenERC1155> {
*
* @returns The NFT metadata for all NFTs in the contract.
*/
public async getOwned(walletAddress?: AddressOrEns): Promise<NFT[]> {
return this.erc1155.getOwned(walletAddress);
public async getOwned(
walletAddress?: AddressOrEns,
queryParams?: QueryAllParams,
): Promise<NFT[]> {
return this.erc1155.getOwned(walletAddress, queryParams);
}
/**
@@ -102,7 +102,10 @@ export class Erc1155Enumerable implements DetectableFeature {
*
* @returns The NFT metadata for all NFTs in the contract.
*/
public async owned(walletAddress?: AddressOrEns): Promise<NFT[]> {
public async owned(
walletAddress?: AddressOrEns,
queryParams?: QueryAllParams,
): Promise<NFT[]> {
const [address, maxId] = await Promise.all([
resolveAddress(
walletAddress || (await this.contractWrapper.getSignerAddress()),
@@ -114,7 +117,7 @@ export class Erc1155Enumerable implements DetectableFeature {
Array.from(Array(maxId.toNumber()).keys()),
]);
const ownedBalances = balances
let ownedBalances = balances
.map((b, i) => {
return {
tokenId: i,
@@ -122,6 +125,11 @@ export class Erc1155Enumerable implements DetectableFeature {
};
})
.filter((b) => b.balance.gt(0));
if (queryParams) {
const start = queryParams?.start || 0;
const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT;
ownedBalances = ownedBalances.slice(start, start + count);
}
const nfts = (
await Promise.all(
ownedBalances.map((item) => this.erc1155.get(item.tokenId.toString())),
@@ -494,12 +494,16 @@ export class Erc1155<
* @returns The NFT metadata for all NFTs in the contract.
* @twfeature ERC1155Enumerable
*/
public async getOwned(walletAddress?: AddressOrEns): Promise<NFT[]> {
public async getOwned(
walletAddress?: AddressOrEns,
queryParams?: QueryAllParams,
): Promise<NFT[]> {
if (walletAddress) {
walletAddress = await resolveAddress(walletAddress);
}
return assertEnabled(this.query, FEATURE_EDITION_ENUMERABLE).owned(
walletAddress,
queryParams,
);
}
@@ -8,6 +8,10 @@ import type { BaseERC721 } from "../../types/eips";
import { DetectableFeature } from "../interfaces/DetectableFeature";
import type { ContractWrapper } from "./contract-wrapper";
import type { Erc721 } from "./erc-721";
import {
DEFAULT_QUERY_ALL_COUNT,
QueryAllParams,
} from "../../../core/schema/QueryParams";
/**
* List owned ERC721 NFTs
@@ -46,10 +50,19 @@ export class Erc721Enumerable implements DetectableFeature {
* const nfts = await contract.nft.query.owned.all(address);
* ```
* @param walletAddress - the wallet address to query, defaults to the connected wallet
* @param queryParams - optional filtering to only fetch a subset of results.
* @returns The NFT metadata for all NFTs in the contract.
*/
public async all(walletAddress?: AddressOrEns): Promise<NFT[]> {
const tokenIds = await this.tokenIds(walletAddress);
public async all(
walletAddress?: AddressOrEns,
queryParams?: QueryAllParams,
): Promise<NFT[]> {
let tokenIds = await this.tokenIds(walletAddress);
if (queryParams) {
const start = queryParams?.start || 0;
const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT;
tokenIds = tokenIds.slice(start, start + count);
}
return await Promise.all(
tokenIds.map((tokenId) => this.erc721.get(tokenId.toString())),
);
@@ -95,13 +95,17 @@ export class StandardErc721<
* console.log(nfts);
* ```
* @param walletAddress - the wallet address to query, defaults to the connected wallet
* @param queryParams - optional filtering to only fetch a subset of results.
* @returns The NFT metadata for all NFTs in the contract.
*/
public async getOwned(walletAddress?: AddressOrEns): Promise<NFT[]> {
public async getOwned(
walletAddress?: AddressOrEns,
queryParams?: QueryAllParams,
): Promise<NFT[]> {
if (walletAddress) {
walletAddress = await resolveAddress(walletAddress);
}
return this.erc721.getOwned(walletAddress);
return this.erc721.getOwned(walletAddress, queryParams);
}
/**
+19 -6
View File
@@ -17,7 +17,10 @@ import type {
} from "@thirdweb-dev/contracts-js";
import type { ThirdwebStorage } from "@thirdweb-dev/storage";
import { BigNumber, BigNumberish, constants } from "ethers";
import type { QueryAllParams } from "../../../core/schema/QueryParams";
import {
DEFAULT_QUERY_ALL_COUNT,
type QueryAllParams,
} from "../../../core/schema/QueryParams";
import type {
NFT,
NFTMetadata,
@@ -415,25 +418,35 @@ export class Erc721<
* console.log(nfts);
* ```
* @param walletAddress - the wallet address to query, defaults to the connected wallet
* @param queryParams - optional filtering to only fetch a subset of results.
* @returns The NFT metadata for all NFTs in the contract.
* @twfeature ERC721Supply | ERC721Enumerable
*/
public async getOwned(walletAddress?: AddressOrEns) {
public async getOwned(
walletAddress?: AddressOrEns,
queryParams?: QueryAllParams,
) {
if (walletAddress) {
walletAddress = await resolveAddress(walletAddress);
}
if (this.query?.owned) {
return this.query.owned.all(walletAddress);
return this.query.owned.all(walletAddress, queryParams);
} else {
const [address, allOwners] = await Promise.all([
walletAddress || this.contractWrapper.getSignerAddress(),
this.getAllOwners(),
]);
let ownedTokens = (allOwners || []).filter(
(i) => address?.toLowerCase() === i.owner?.toLowerCase(),
);
if (queryParams) {
const start = queryParams?.start || 0;
const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT;
ownedTokens = ownedTokens.slice(start, start + count);
}
return await Promise.all(
(allOwners || [])
.filter((i) => address?.toLowerCase() === i.owner?.toLowerCase())
.map((i) => this.get(i.tokenId)),
ownedTokens.map(async (i) => this.get(i.tokenId)),
);
}
}
@@ -8,6 +8,10 @@ import type { BaseERC721 } from "../../types/eips";
import { DetectableFeature } from "../interfaces/DetectableFeature";
import type { ContractWrapper } from "./contract-wrapper";
import type { Erc721 } from "./erc-721";
import {
DEFAULT_QUERY_ALL_COUNT,
QueryAllParams,
} from "../../../core/schema/QueryParams";
/**
* List owned ERC721 NFTs
@@ -50,8 +54,16 @@ export class Erc721AQueryable implements DetectableFeature {
* @param walletAddress - the wallet address to query, defaults to the connected wallet
* @returns The NFT metadata for all NFTs in the contract.
*/
public async all(walletAddress?: AddressOrEns): Promise<NFT[]> {
const tokenIds = await this.tokenIds(walletAddress);
public async all(
walletAddress?: AddressOrEns,
queryParams?: QueryAllParams,
): Promise<NFT[]> {
let tokenIds = await this.tokenIds(walletAddress);
if (queryParams) {
const start = queryParams?.start || 0;
const count = queryParams?.count || DEFAULT_QUERY_ALL_COUNT;
tokenIds = tokenIds.slice(start, start + count);
}
return await Promise.all(
tokenIds.map((tokenId) => this.erc721.get(tokenId.toString())),
);
+1 -1
View File
@@ -61,7 +61,7 @@ export class ContractFactory extends ContractWrapper<TWFactory> {
[VoteInitializer.contractType]: 1,
[SplitInitializer.contractType]: 1,
[MarketplaceInitializer.contractType]: 2,
[MarketplaceV3Initializer.contractType]: 1,
[MarketplaceV3Initializer.contractType]: 3,
[PackInitializer.contractType]: 2,
};
+1 -1
View File
@@ -890,7 +890,7 @@ function addChainToSupportedChains(
options = {
...options,
// @ts-expect-error - we know that the network is assignable despite the readonly mismatch
supportedChains: [...(options?.supportedChains || []), network],
supportedChains: [network, ...(options?.supportedChains || [])],
};
}
return options;
+30 -46
View File
@@ -1,4 +1,3 @@
import { ThirdwebSDK } from "../../src/evm";
import { SmartContract } from "../../src/evm/contracts/smart-contract";
import {
extendedMetadataMock,
@@ -14,19 +13,19 @@ import {
tieredDropBytecode,
tieredDropCompilerMetadata,
} from "./mock/tieredDropMetadata";
import {
DirectListingsLogic__factory,
EnglishAuctionsLogic__factory,
OffersLogic__factory,
} from "@thirdweb-dev/contracts-js";
import {
marketplaceV3Bytecode,
marketplaceV3CompilerMetadata,
} from "./mock/marketplaceV3Metadata";
import {
pluginMapBytecode,
pluginMapCompilerMetadata,
} from "./mock/pluginMapMetadata";
directListingsBytecode,
directListingsCompilerMetadata,
} from "./mock/directListingsMetadata";
import { offersBytecode, offersCompilerMetadata } from "./mock/offersMetadata";
import {
englishAuctionsBytecode,
englishAuctionsCompilerMetadata,
} from "./mock/englishAuctionsMetadata";
const itIf = (condition: boolean) => (condition ? it : it.skip);
@@ -112,7 +111,7 @@ describe("Any EVM Keyless Deploy", async () => {
{
...extendedMetadataMock,
deployType: "autoFactory",
routerType: "plugin",
routerType: "dynamic",
defaultExtensions: [
{
extensionName: "DirectListingsLogic",
@@ -136,7 +135,7 @@ describe("Any EVM Keyless Deploy", async () => {
},
publisher: await adminWallet.getAddress(),
},
"ipfs://QmaE7HVb4nwHp96omxmyPc7nKPZqsGB7ZbW6psznN6cSMk",
"ipfs://QmWrPyWEMDjnR3a5zp1rJHzU1EUGx6DR2hPBVHAkGGjhgm/0",
);
transactionCount = (await sdk.deployer.getTransactionsForDeploy(publishUri))
.length;
@@ -145,7 +144,7 @@ describe("Any EVM Keyless Deploy", async () => {
publishUri,
[
walletAddress, // defaultAdmin
"ipfs://QmP2QPzc81zg5rqhU9u7cDeSyD4aZH8RdVF8Nuh6rCCgxV", // contractUri
"ipfs://QmWrPyWEMDjnR3a5zp1rJHzU1EUGx6DR2hPBVHAkGGjhgm/0", // contractUri
[], // trustedForwarders
walletAddress, // platform fee recipient
0, // platform fee bps
@@ -167,27 +166,10 @@ describe("Any EVM Keyless Deploy", async () => {
before(async () => {
[adminWallet, claimerWallet] = signers;
await mockUploadMetadataWithBytecode(
"PluginMap",
pluginMapCompilerMetadata.output.abi,
pluginMapBytecode,
"",
{
...extendedMetadataMock,
deployType: "standard",
networksForDeployment: {
allNetworks: true,
networksEnabled: [],
},
publisher: adminWallet.address,
},
"ipfs://QmQHyopzH41En8KxvYrmATLCyuTMu8Hv5TEaxLc7gWJkLm/0",
);
await mockUploadMetadataWithBytecode(
"DirectListingsLogic",
DirectListingsLogic__factory.abi,
DirectListingsLogic__factory.bytecode,
directListingsCompilerMetadata.output.abi,
directListingsBytecode,
"",
{
...extendedMetadataMock,
@@ -203,8 +185,8 @@ describe("Any EVM Keyless Deploy", async () => {
await mockUploadMetadataWithBytecode(
"OffersLogic",
OffersLogic__factory.abi,
OffersLogic__factory.bytecode,
offersCompilerMetadata.output.abi,
offersBytecode,
"",
{
...extendedMetadataMock,
@@ -220,8 +202,8 @@ describe("Any EVM Keyless Deploy", async () => {
await mockUploadMetadataWithBytecode(
"EnglishAuctionsLogic",
EnglishAuctionsLogic__factory.abi,
EnglishAuctionsLogic__factory.bytecode,
englishAuctionsCompilerMetadata.output.abi,
englishAuctionsBytecode,
"",
{
...extendedMetadataMock,
@@ -256,20 +238,22 @@ describe("Any EVM Keyless Deploy", async () => {
});
// can only work if secret key is set, skip otherwise
itIf(process.env.TW_SECRET_KEY)("deploy marketplacev3", async () => {
it("deploy marketplacev3", async () => {
notificationCounter = 0;
transactionCount = 0;
const marketplace = await deployMarketplaceV3();
expect(notificationCounter).to.greaterThanOrEqual(12);
expect(transactionCount).to.greaterThanOrEqual(6);
let plugins = await marketplace.call("getAllPlugins");
let allPlugins = plugins.map((item: any) => item.pluginAddress);
let pluginsAddresses = Array.from(new Set(allPlugins));
let extensions = await marketplace.call("getAllExtensions");
let allExtensions = extensions.map(
(item: any) => item.metadata.implementation,
);
let extensionAddresses = Array.from(new Set(allExtensions));
expect(pluginsAddresses.length).to.equal(3);
expect(extensionAddresses.length).to.equal(3);
pluginsAddresses.forEach(async (address) => {
extensionAddresses.forEach(async (address) => {
expect(address).to.not.equal(ethers.constants.AddressZero);
const code = await adminWallet.provider?.getCode(address as string);
expect(code?.length).to.be.greaterThan(2);
@@ -282,13 +266,13 @@ describe("Any EVM Keyless Deploy", async () => {
expect(notificationCounter).to.equal(2);
expect(transactionCount).to.equal(1);
plugins = await marketplace2.call("getAllPlugins");
allPlugins = plugins.map((item: any) => item.pluginAddress);
pluginsAddresses = Array.from(new Set(allPlugins));
extensions = await marketplace2.call("getAllExtensions");
allExtensions = extensions.map((item: any) => item.metadata.implementation);
extensionAddresses = Array.from(new Set(allExtensions));
expect(pluginsAddresses.length).to.equal(3);
expect(extensionAddresses.length).to.equal(3);
pluginsAddresses.forEach(async (address) => {
extensionAddresses.forEach(async (address) => {
expect(address).to.not.equal(ethers.constants.AddressZero);
const code = await adminWallet.provider?.getCode(address as string);
expect(code?.length).to.be.greaterThan(2);
+57 -23
View File
@@ -63,12 +63,20 @@ import {
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { constants, ContractInterface, ethers } from "ethers";
import hardhat from "hardhat";
import { generatePluginFunctions } from "../../src/evm/common/plugin/generatePluginFunctions";
import {
generateExtensionFunctions,
generatePluginFunctions,
} from "../../src/evm/common/plugin/generatePluginFunctions";
import { mockUploadMetadataWithBytecode } from "./utils";
import {
bytecode as TWCloneFactoryBytecode,
abi as TWCloneFactoryAbi,
} from "./metadata/TWCloneFactory";
import {
Extension,
ExtensionFunction,
ExtensionMetadata,
} from "../../src/evm/types/extensions";
// it's there, trust me bro
const hardhatEthers = (hardhat as any).ethers;
@@ -359,48 +367,68 @@ async function setupMultichainRegistry(
// Setup marketplace-v3 for tests
async function setupMarketplaceV3(): Promise<string> {
let extensions: Extension[] = [];
// Direct Listings
const directListingsPluginAddress = await deployContractAndUploadMetadata(
const directListingsExtensionAddress = await deployContractAndUploadMetadata(
DirectListingsLogic__factory.abi,
DirectListingsLogic__factory.bytecode,
signer,
[mock_weth_address],
);
const pluginsDirectListings: Plugin[] = generatePluginFunctions(
directListingsPluginAddress,
AbiSchema.parse(DirectListingsLogic__factory.abi),
);
const directListingsFunctions: ExtensionFunction[] =
generateExtensionFunctions(
AbiSchema.parse(DirectListingsLogic__factory.abi),
);
const directListingsExtensionMetadata: ExtensionMetadata = {
name: "DirectListingsLogic",
metadataURI: "",
implementation: directListingsExtensionAddress,
};
extensions.push({
metadata: directListingsExtensionMetadata,
functions: directListingsFunctions,
});
// English Auctions
const englishAuctionPluginAddress = await deployContractAndUploadMetadata(
const englishAuctionExtensionAddress = await deployContractAndUploadMetadata(
EnglishAuctionsLogic__factory.abi,
EnglishAuctionsLogic__factory.bytecode,
signer,
[mock_weth_address],
);
const pluginsEnglishAuctions: Plugin[] = generatePluginFunctions(
englishAuctionPluginAddress,
AbiSchema.parse(EnglishAuctionsLogic__factory.abi),
);
const englishAuctionsFunctions: ExtensionFunction[] =
generateExtensionFunctions(
AbiSchema.parse(EnglishAuctionsLogic__factory.abi),
);
const englishAuctionsExtensionMetadata: ExtensionMetadata = {
name: "EnglishAuctionsLogic",
metadataURI: "",
implementation: englishAuctionExtensionAddress,
};
extensions.push({
metadata: englishAuctionsExtensionMetadata,
functions: englishAuctionsFunctions,
});
// Offers
const offersLogicPluginAddress = await deployContractAndUploadMetadata(
const offersLogicExtensionAddress = await deployContractAndUploadMetadata(
OffersLogic__factory.abi,
OffersLogic__factory.bytecode,
signer,
);
const pluginsOffers: Plugin[] = generatePluginFunctions(
offersLogicPluginAddress,
const offersFunctions: ExtensionFunction[] = generateExtensionFunctions(
AbiSchema.parse(OffersLogic__factory.abi),
);
// Map
const pluginMapAddress = await deployContractAndUploadMetadata(
PluginMap__factory.abi,
PluginMap__factory.bytecode,
signer,
[[...pluginsDirectListings, ...pluginsEnglishAuctions, ...pluginsOffers]],
);
const offersExtensionMetadata: ExtensionMetadata = {
name: "OffersLogic",
metadataURI: "",
implementation: offersLogicExtensionAddress,
};
extensions.push({
metadata: offersExtensionMetadata,
functions: offersFunctions,
});
// Router
const royaltyEngineAddress = constants.AddressZero;
@@ -408,7 +436,13 @@ async function setupMarketplaceV3(): Promise<string> {
MarketplaceV3__factory.abi,
MarketplaceV3__factory.bytecode,
signer,
[pluginMapAddress, royaltyEngineAddress],
[
{
extensions: extensions,
royaltyEngineAddress: royaltyEngineAddress,
nativeTokenWrapper: mock_weth_address,
},
],
"MarketplaceV3",
);
return marketplaceV3Address;
+96
View File
@@ -287,4 +287,100 @@ describe("Edition Contract", async () => {
expect(nfts[0].supply).to.be.equal("5");
expect(nfts[0].metadata.id).to.be.equal("1");
});
it("should respect pagination for getOwned (for edition.ts)", async () => {
const nfts = [] as { metadata: { name: string }; supply: number }[];
for (let i = 0; i < 10; i++) {
nfts.push({
metadata: { name: `Test${i}` },
supply: 10,
});
}
await bundleContract.mintBatch(nfts);
const total = await bundleContract.getTotalCount();
expect(total.toNumber()).to.eq(10);
const nftPage1 = await bundleContract.getOwned(adminWallet.address, {
count: 2,
start: 0,
});
expect(nftPage1).to.be.an("array").length(2);
expect(nftPage1[0].metadata.id).to.eq("0");
expect(nftPage1[1].metadata.id).to.eq("1");
const nftPage2 = await bundleContract.getOwned(adminWallet.address, {
count: 3,
start: 2,
});
expect(nftPage2).to.be.an("array").length(3);
expect(nftPage2[0].metadata.id).to.eq("2");
expect(nftPage2[1].metadata.id).to.eq("3");
expect(nftPage2[2].metadata.id).to.eq("4");
});
it("should respect pagination for getOwned (for erc-1155.ts)", async () => {
const nfts = [] as { metadata: { name: string }; supply: number }[];
for (let i = 0; i < 10; i++) {
nfts.push({
metadata: { name: `Test${i}` },
supply: 10,
});
}
await bundleContract.mintBatch(nfts);
const total = await bundleContract.getTotalCount();
expect(total.toNumber()).to.eq(10);
const nftPage1 = await bundleContract.erc1155.getOwned(
adminWallet.address,
{
count: 2,
start: 0,
},
);
expect(nftPage1).to.be.an("array").length(2);
expect(nftPage1[0].metadata.id).to.eq("0");
expect(nftPage1[1].metadata.id).to.eq("1");
const nftPage2 = await bundleContract.erc1155.getOwned(
adminWallet.address,
{
count: 3,
start: 2,
},
);
expect(nftPage2).to.be.an("array").length(3);
expect(nftPage2[0].metadata.id).to.eq("2");
expect(nftPage2[1].metadata.id).to.eq("3");
expect(nftPage2[2].metadata.id).to.eq("4");
});
it("getOwned should return all items when queryParams.count is greater than the total supply (edition.ts)", async () => {
const nfts = [] as { metadata: { name: string }; supply: number }[];
for (let i = 0; i < 10; i++) {
nfts.push({
metadata: { name: `Test${i}` },
supply: 10,
});
}
await bundleContract.mintBatch(nfts);
const items = await bundleContract.getOwned(undefined, {
count: 1000,
start: 0,
});
expect(items).to.be.an("array").length(nfts.length);
});
it("getOwned should return all items when queryParams.count is greater than the total supply (erc-1155.ts)", async () => {
const nfts = [] as { metadata: { name: string }; supply: number }[];
for (let i = 0; i < 10; i++) {
nfts.push({
metadata: { name: `Test${i}` },
supply: 10,
});
}
await bundleContract.mintBatch(nfts);
const items = await bundleContract.getOwned(undefined, {
count: 1000,
start: 0,
});
expect(items).to.be.an("array").length(nfts.length);
});
});
+28 -19
View File
@@ -46,11 +46,11 @@ describe("Marketplace V3", async () => {
MarketplaceV3Initializer.contractType,
{
name: "Test Marketplace",
platform_fee_recipient: adminWallet.address,
},
),
"marketplace-v3",
);
dummyNftContract = await sdk.getNFTCollection(
await sdk.deployer.deployBuiltInContract(
NFTCollectionInitializer.contractType,
@@ -228,8 +228,9 @@ describe("Marketplace V3", async () => {
isReservedListing: false,
});
const listing =
await marketplaceContract.directListings.getListing(listingId);
const listing = await marketplaceContract.directListings.getListing(
listingId,
);
expect(listing.currencyContractAddress.toLowerCase()).to.equal(
NATIVE_TOKEN_ADDRESS.toLowerCase(),
);
@@ -374,10 +375,12 @@ describe("Marketplace V3", async () => {
});
it("should return correct listing", async () => {
const listingOne =
await marketplaceContract.directListings.getListing(directListingOneId);
const listingTwo =
await marketplaceContract.directListings.getListing(directListingTwoId);
const listingOne = await marketplaceContract.directListings.getListing(
directListingOneId,
);
const listingTwo = await marketplaceContract.directListings.getListing(
directListingTwoId,
);
assert.equal(listingOne.tokenId.toString(), "0");
assert.equal(listingOne.asset.id.toString(), "0");
assert.equal(listingOne.asset.name, "Test 0");
@@ -463,8 +466,9 @@ describe("Marketplace V3", async () => {
});
it("should correctly cancel a direct listing", async () => {
const listing =
await marketplaceContract.directListings.getListing(directListingId);
const listing = await marketplaceContract.directListings.getListing(
directListingId,
);
assert.equal(listing.quantity.toString(), "1");
await marketplaceContract.directListings.cancelListing(directListingId);
@@ -646,10 +650,12 @@ describe("Marketplace V3", async () => {
});
it("should return correct auction", async () => {
const auctionOne =
await marketplaceContract.englishAuctions.getAuction(auctionOneId);
const auctionTwo =
await marketplaceContract.englishAuctions.getAuction(auctionTwoId);
const auctionOne = await marketplaceContract.englishAuctions.getAuction(
auctionOneId,
);
const auctionTwo = await marketplaceContract.englishAuctions.getAuction(
auctionTwoId,
);
assert.equal(auctionOne.tokenId.toString(), "2");
assert.equal(auctionOne.asset.id.toString(), "2");
assert.equal(auctionOne.asset.name, "Test 3");
@@ -692,8 +698,9 @@ describe("Marketplace V3", async () => {
await sdk.updateSignerOrProvider(bobWallet);
await marketplaceContract.englishAuctions.makeBid(auctionId, 0.3);
let winningBid =
await marketplaceContract.englishAuctions.getWinningBid(auctionId);
let winningBid = await marketplaceContract.englishAuctions.getWinningBid(
auctionId,
);
assert.equal(winningBid?.bidderAddress, bobWallet.address);
assert.equal(
@@ -706,8 +713,9 @@ describe("Marketplace V3", async () => {
await sdk.updateSignerOrProvider(samWallet);
await marketplaceContract.englishAuctions.makeBid(auctionId, 0.6);
winningBid =
await marketplaceContract.englishAuctions.getWinningBid(auctionId);
winningBid = await marketplaceContract.englishAuctions.getWinningBid(
auctionId,
);
assert.equal(winningBid?.bidderAddress, samWallet.address);
assert.equal(
winningBid?.bidAmount.toString(),
@@ -1095,8 +1103,9 @@ describe("Marketplace V3", async () => {
it("should not allow you to update an active direct listing", async () => {
const pricePerToken = ethers.utils.parseUnits("0.1");
const directListing =
await marketplaceContract.directListings.getListing(directListingId);
const directListing = await marketplaceContract.directListings.getListing(
directListingId,
);
assert.equal(
directListing.pricePerToken.toString(),
pricePerToken.toString(),
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+66
View File
@@ -285,4 +285,70 @@ describe("NFT Contract", async () => {
expect(records[0].tokenId).to.eq(1);
expect(records[1].tokenId).to.eq(2);
});
it("should respect pagination for getOwned (erc-721-standard.ts)", async () => {
const _tokenIds: number[] = Array.from({ length: 11 }, (_, index) => index); // [0, 1, ... 10]
const metadata = _tokenIds.map((num) => ({ name: `Test${num}` }));
await nftContract.mintBatch(metadata);
const nftPage1 = await nftContract.getOwned(undefined, {
count: 2,
start: 0,
});
expect(nftPage1).to.be.an("array").length(2);
expect(nftPage1[0].metadata.id).to.eq("0");
expect(nftPage1[1].metadata.id).to.eq("1");
const nftPage2 = await nftContract.getOwned(undefined, {
count: 3,
start: 2,
});
expect(nftPage2).to.be.an("array").length(3);
expect(nftPage2[0].metadata.id).to.eq("2");
expect(nftPage2[1].metadata.id).to.eq("3");
expect(nftPage2[2].metadata.id).to.eq("4");
});
it("should respect pagination for getOwned (erc-721.ts)", async () => {
const _tokenIds: number[] = Array.from({ length: 11 }, (_, index) => index); // [0, 1, ... 10]
const metadata = _tokenIds.map((num) => ({ name: `Test${num}` }));
await nftContract.mintBatch(metadata);
const nftPage1 = await nftContract.erc721.getOwned(undefined, {
count: 2,
start: 0,
});
expect(nftPage1).to.be.an("array").length(2);
expect(nftPage1[0].metadata.id).to.eq("0");
expect(nftPage1[1].metadata.id).to.eq("1");
const nftPage2 = await nftContract.erc721.getOwned(undefined, {
count: 3,
start: 2,
});
expect(nftPage2).to.be.an("array").length(3);
expect(nftPage2[0].metadata.id).to.eq("2");
expect(nftPage2[1].metadata.id).to.eq("3");
expect(nftPage2[2].metadata.id).to.eq("4");
});
it("getOwned should return all item when queryParams.count is greater than the total supply (erc-721-standard.ts)", async () => {
const _tokenIds: number[] = Array.from({ length: 11 }, (_, index) => index); // [0, 1, ... 10]
const metadata = _tokenIds.map((num) => ({ name: `Test${num}` }));
await nftContract.mintBatch(metadata);
const nfts = await nftContract.getOwned(undefined, {
count: 1000,
start: 0,
});
expect(nfts).to.be.an("array").length(_tokenIds.length);
});
it("getOwned should return all items when queryParams.count is greater than the total supply (erc-721.ts)", async () => {
const _tokenIds: number[] = Array.from({ length: 11 }, (_, index) => index); // [0, 1, ... 10]
const metadata = _tokenIds.map((num) => ({ name: `Test${num}` }));
await nftContract.mintBatch(metadata);
const nfts = await nftContract.erc721.getOwned(undefined, {
count: 1000,
start: 0,
});
expect(nfts).to.be.an("array").length(_tokenIds.length);
});
});
+8
View File
@@ -1,5 +1,13 @@
# @thirdweb-dev/service-utils
## 0.4.7
### Patch Changes
- [#1752](https://github.com/thirdweb-dev/js/pull/1752) [`1fbbc2d2`](https://github.com/thirdweb-dev/js/commit/1fbbc2d27d88af6029267e6993dd79e077a60ab2) Thanks [@ElasticBottle](https://github.com/ElasticBottle)! - chore(service-utils): add `redirecrUrls` type to `ApiKeyMetadata`
- [#1751](https://github.com/thirdweb-dev/js/pull/1751) [`95380eae`](https://github.com/thirdweb-dev/js/commit/95380eaed4aad93d47ece4da2b45fdbba2d14205) Thanks [@arcoraven](https://github.com/arcoraven)! - Add walletType to usage payload
## 0.4.6
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/service-utils",
"version": "0.4.6",
"version": "0.4.7",
"main": "dist/thirdweb-dev-service-utils.cjs.js",
"module": "dist/thirdweb-dev-service-utils.esm.js",
"exports": {
@@ -35,6 +35,7 @@ const usageEventSchema = z.object({
creatorWalletAddress: z.string().optional(),
clientId: z.string().optional(),
walletAddress: z.string().optional(),
walletType: z.string().optional(),
chainId: z.number().int().positive().optional(),
provider: z.string().optional(),
mimeType: z.string().optional(),
+1
View File
@@ -29,6 +29,7 @@ export type ApiKeyMetadata = {
walletAddresses: string[];
domains: string[];
bundleIds: string[];
redirectUrls: string[];
services: {
name: string;
targetAddresses: string[];
+1
View File
@@ -8,6 +8,7 @@ export const validApiKeyMeta: ApiKeyMetadata = {
walletAddresses: [],
domains: ["example.com", "*.example.com"],
bundleIds: [],
redirectUrls: [],
accountId: "test-account-id",
accountStatus: "noCustomer",
accountPlan: "free",
+9
View File
@@ -1,5 +1,14 @@
# @thirdweb-dev/unity-js-bridge
## 0.2.88
### Patch Changes
- Updated dependencies [[`1f3c64d3`](https://github.com/thirdweb-dev/js/commit/1f3c64d3618903b9008cc7b633ea890b508e7800), [`74941603`](https://github.com/thirdweb-dev/js/commit/74941603a96456da46a47147f67c98235ac55022), [`4b98e487`](https://github.com/thirdweb-dev/js/commit/4b98e487d4b47225d7095e5444dc5e7608db48a3), [`693f349d`](https://github.com/thirdweb-dev/js/commit/693f349db2478e1cd0fc82a9ef9882f46832b125), [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9), [`0f12d1f9`](https://github.com/thirdweb-dev/js/commit/0f12d1f90320923309f085c372d3a5ed01dd4606), [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e), [`63ad0050`](https://github.com/thirdweb-dev/js/commit/63ad0050f0a24ec15b90933b5664d697618cf2d0)]:
- @thirdweb-dev/sdk@4.0.1
- @thirdweb-dev/wallets@2.0.2
- @thirdweb-dev/auth@4.0.2
## 0.2.87
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/unity-js-bridge",
"version": "0.2.87",
"version": "0.2.88",
"main": "dist/thirdweb-unity-bridge.js",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/unity-js-bridge",
"license": "Apache-2.0",
+16
View File
@@ -1,5 +1,21 @@
# @thirdweb-dev/wallets
## 2.0.2
### Patch Changes
- [#1744](https://github.com/thirdweb-dev/js/pull/1744) [`74941603`](https://github.com/thirdweb-dev/js/commit/74941603a96456da46a47147f67c98235ac55022) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix executeBatch() type mismatches
- [#1730](https://github.com/thirdweb-dev/js/pull/1730) [`4b98e487`](https://github.com/thirdweb-dev/js/commit/4b98e487d4b47225d7095e5444dc5e7608db48a3) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add wallet analytics
- [#1754](https://github.com/thirdweb-dev/js/pull/1754) [`dcdb0dcb`](https://github.com/thirdweb-dev/js/commit/dcdb0dcb838168a22c8335738852316dfb6e6fc9) Thanks [@iketw](https://github.com/iketw)! - Fix typos in SmartWallet api
- [#1753](https://github.com/thirdweb-dev/js/pull/1753) [`b3b9edca`](https://github.com/thirdweb-dev/js/commit/b3b9edca29e7d4053b14270a61caa89c34fecf9e) Thanks [@iketw](https://github.com/iketw)! - Minor bug and UI fix for connecting an external app to a smart wallet
- Updated dependencies [[`1f3c64d3`](https://github.com/thirdweb-dev/js/commit/1f3c64d3618903b9008cc7b633ea890b508e7800), [`693f349d`](https://github.com/thirdweb-dev/js/commit/693f349db2478e1cd0fc82a9ef9882f46832b125), [`0f12d1f9`](https://github.com/thirdweb-dev/js/commit/0f12d1f90320923309f085c372d3a5ed01dd4606), [`63ad0050`](https://github.com/thirdweb-dev/js/commit/63ad0050f0a24ec15b90933b5664d697618cf2d0)]:
- @thirdweb-dev/sdk@4.0.1
- @thirdweb-dev/contracts-js@1.3.14
## 2.0.1
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/wallets",
"version": "2.0.1",
"version": "2.0.2",
"main": "dist/thirdweb-dev-wallets.cjs.js",
"module": "dist/thirdweb-dev-wallets.esm.js",
"types": "dist/thirdweb-dev-wallets.cjs.d.ts",
@@ -44,7 +44,7 @@ export class WalletConnectV2Handler extends WalletConnectHandler {
};
this.#core = new Core({
projectId: options?.walletConenctV2ProjectId || TW_WC_PROJECT_ID,
projectId: options?.walletConnectV2ProjectId || TW_WC_PROJECT_ID,
relayUrl: options?.walletConnectV2RelayUrl || WC_RELAY_URL,
});
}
@@ -177,6 +177,7 @@ export class WalletConnectV2Handler extends WalletConnectHandler {
const signature = await signerSign.signTransaction(signTransaction);
response = formatJsonRpcResult(id, signature);
break;
default:
const error = {
id,
@@ -8,9 +8,8 @@ export type WalletConnectMetadata = IWeb3Wallet["metadata"];
// connect dapp support through wcv2 protocol
export type WalletConnectReceiverConfig = {
enableConnectApp?: boolean;
wcVersion?: "v1" | "v2";
walletConnectWalletMetadata?: WCMetadata;
walletConenctV2ProjectId?: string;
walletConnectV2ProjectId?: string;
walletConnectV2RelayUrl?: string;
wcStorage?: SyncStorage;
};
@@ -186,7 +186,9 @@ export class SmartWalletConnector extends Connector<SmartWalletConnectionArgs> {
* @param transactions
* @returns the transaction receipt
*/
async executeBatch(transactions: Transaction[]): Promise<TransactionResult> {
async executeBatch(
transactions: Transaction<any>[],
): Promise<TransactionResult> {
if (!this.accountApi) {
throw new Error("Personal wallet not connected");
}
+1
View File
@@ -53,6 +53,7 @@ export { getInjectedPhantomProvider } from "./connectors/phantom/getInjectedPhan
export { getInjectedRainbowProvider } from "./connectors/rainbow/getInjectedRainbowProvider";
export { getInjectedCoinbaseProvider } from "./connectors/coinbase-wallet/getInjectedCoinbaseProvider";
export { assertWindowEthereum } from "./utils/assertWindowEthereum";
export * from "./utils/setWalletAnaltyicsEnabled";
// ThirdwebEmbeddedWalletSdk
export * from "./connectors/embedded-wallet/implementations";
@@ -0,0 +1,31 @@
import { isWalletAnalyticsEnabled } from "./setWalletAnaltyicsEnabled";
const ANALYTICS_ENDPOINT = "https://c.thirdweb.com/event";
export function track(args: {
clientId: string;
source: string;
action: string;
walletType: string;
walletAddress: string;
}) {
if (!isWalletAnalyticsEnabled()) {
return;
}
const { clientId, walletType, walletAddress, source, action } = args;
const body = {
source,
action,
walletAddress,
walletType,
};
// don't block on analytic calls
fetch(ANALYTICS_ENDPOINT, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-client-id": clientId,
},
body: JSON.stringify(body),
});
}
@@ -0,0 +1,9 @@
let walletAnalyticsEnabled = true;
export function isWalletAnalyticsEnabled() {
return walletAnalyticsEnabled;
}
export function setWalletAnalyticsEnabled(enabled: boolean) {
walletAnalyticsEnabled = enabled;
}
+14
View File
@@ -5,6 +5,7 @@ import { DEFAULT_DAPP_META } from "../constants/dappMeta";
import { EVMWallet } from "../interfaces";
import { ConnectParams, Connector } from "../interfaces/connector";
import { AbstractWallet } from "./abstract";
import { track } from "../utils/analytics";
// eslint-disable-next-line @typescript-eslint/ban-types
export type WalletOptions<TOpts extends Record<string, any> = {}> = {
@@ -13,6 +14,7 @@ export type WalletOptions<TOpts extends Record<string, any> = {}> = {
walletStorage?: AsyncStorage;
dappMetadata?: DAppMetaData;
clientId?: string;
analytics?: "enabled" | "disabled";
} & TOpts;
export type WalletMeta = {
@@ -113,6 +115,7 @@ export abstract class AbstractClientWallet<
chainId: await this.getChainId(),
});
this.#trackConnection(address);
return address;
}
@@ -122,12 +125,23 @@ export abstract class AbstractClientWallet<
try {
const address = await connector.connect(connectOptions);
this.#trackConnection(address);
return address;
} catch (error) {
throw new Error((error as Error).message);
}
}
#trackConnection(address: string) {
track({
clientId: this.options?.clientId || "",
source: "connectWallet",
action: "connect",
walletType: this.walletId,
walletAddress: address,
});
}
async #subscribeToEvents(connector: Connector) {
// subscribe to connector for events
connector.on("connect", (data) => {
@@ -67,7 +67,7 @@ export class SmartWallet
this.#wcWallet = this.enableConnectApp
? new WalletConnectV2Handler({
walletConnectWalletMetadata: options?.walletConnectWalletMetadata,
walletConenctV2ProjectId: options?.walletConenctV2ProjectId,
walletConnectV2ProjectId: options?.walletConnectV2ProjectId,
walletConnectV2RelayUrl: options?.walletConnectV2RelayUrl,
})
: new NoOpWalletConnectHandler();
@@ -120,7 +120,9 @@ export class SmartWallet
* @param transactions
* @returns the transaction receipt
*/
async executeBatch(transactions: Transaction[]): Promise<TransactionResult> {
async executeBatch(
transactions: Transaction<any>[],
): Promise<TransactionResult> {
const connector = await this.getConnector();
return connector.executeBatch(transactions);
}
+5 -5
View File
@@ -380,8 +380,8 @@ importers:
packages/contracts-js:
dependencies:
'@thirdweb-dev/contracts':
specifier: 3.10.1-0
version: 3.10.1-0([email protected])
specifier: 3.10.2-3
version: 3.10.2-3([email protected])
devDependencies:
'@babel/preset-env':
specifier: ^7.22.9
@@ -12030,8 +12030,8 @@ packages:
use-sync-external-store: 1.2.0([email protected])
dev: false
/@thirdweb-dev/[email protected].1-0([email protected]):
resolution: {integrity: sha512-s+Wj0hZ6OFu2B+iykEf8N+7uyCUzLQHVQYGWYPiuMwqi0urYiiJyseRe1/jhZ9IkXD+RA4pCOyYrtXfT6r8m3Q==}
/@thirdweb-dev/[email protected].2-3([email protected]):
resolution: {integrity: sha512-QWO9HT4k3s86oMyE/SbDWhgm/Na9FnxOkVjhyuOigmrwq5NlNp7NCcmecQgILxvUiLXO9if9OeFlYCFGsJinng==}
dependencies:
'@chainlink/contracts': 0.6.1([email protected])
'@openzeppelin/contracts': 4.9.3
@@ -25539,7 +25539,7 @@ packages:
engines: {node: '>=12.0.0'}
hasBin: true
peerDependencies:
protobufjs: '>=7.2.4'
protobufjs: ^7.0.0
dependencies:
chalk: 4.1.2
escodegen: 1.14.3