Compare commits
23
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
068db44603 | ||
|
|
dd7d0fca2d | ||
|
|
526176c471 | ||
|
|
09120c923c | ||
|
|
d1f8e95162 | ||
|
|
6573556d0e | ||
|
|
fc62b91ee5 | ||
|
|
08e9cd206b | ||
|
|
fb0f12ae28 | ||
|
|
c710fc1c62 | ||
|
|
f41ee6fb1c | ||
|
|
513c332ed0 | ||
|
|
693f349db2 | ||
|
|
63ad0050f0 | ||
|
|
dcdb0dcb83 | ||
|
|
b3b9edca29 | ||
|
|
1fbbc2d27d | ||
|
|
4b98e487d4 | ||
|
|
95380eaed4 | ||
|
|
1f3c64d361 | ||
|
|
bb1666b92b | ||
|
|
0f12d1f903 | ||
|
|
74941603a9 |
@@ -1,5 +1,19 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 4.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@2.0.3
|
||||
|
||||
## 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,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "4.0.1",
|
||||
"version": "4.0.3",
|
||||
"main": "dist/thirdweb-dev-auth.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth.esm.js",
|
||||
"browser": {
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# thirdweb
|
||||
|
||||
## 0.13.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`526176c4`](https://github.com/thirdweb-dev/js/commit/526176c47108c91d83bcfc5f0ca556274e6462d6), [`d1f8e951`](https://github.com/thirdweb-dev/js/commit/d1f8e951623f1691fdfe3d1e8645970d0a52eb06), [`09120c92`](https://github.com/thirdweb-dev/js/commit/09120c923cca804b9d4f5f779e5a53c97ecc8223), [`6573556d`](https://github.com/thirdweb-dev/js/commit/6573556d0e03efa0d6a157fccb0a1c08dd22d7cd)]:
|
||||
- @thirdweb-dev/sdk@4.0.2
|
||||
- @thirdweb-dev/wallets@2.0.3
|
||||
- @thirdweb-dev/auth@4.0.3
|
||||
|
||||
## 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,7 +1,7 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.13.1",
|
||||
"version": "0.13.3",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# @thirdweb-dev/react-core
|
||||
|
||||
## 4.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1758](https://github.com/thirdweb-dev/js/pull/1758) [`08e9cd20`](https://github.com/thirdweb-dev/js/commit/08e9cd206bcc37cf1e84a878dc78bc4f38e5092c) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Add pagination to useOwnedNFTs
|
||||
|
||||
- Updated dependencies [[`526176c4`](https://github.com/thirdweb-dev/js/commit/526176c47108c91d83bcfc5f0ca556274e6462d6), [`d1f8e951`](https://github.com/thirdweb-dev/js/commit/d1f8e951623f1691fdfe3d1e8645970d0a52eb06), [`09120c92`](https://github.com/thirdweb-dev/js/commit/09120c923cca804b9d4f5f779e5a53c97ecc8223), [`6573556d`](https://github.com/thirdweb-dev/js/commit/6573556d0e03efa0d6a157fccb0a1c08dd22d7cd)]:
|
||||
- @thirdweb-dev/sdk@4.0.2
|
||||
- @thirdweb-dev/wallets@2.0.3
|
||||
- @thirdweb-dev/auth@4.0.3
|
||||
|
||||
## 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,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-core",
|
||||
"version": "4.0.1",
|
||||
"version": "4.0.3",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -225,11 +225,12 @@ export function useTotalCirculatingSupply(
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: ownedNFTs, isLoading, error } = useOwnedNFTs(contract, "{{wallet_address}}");
|
||||
* const { data: ownedNFTs, isLoading, error } = useOwnedNFTs(contract, "{{wallet_address}}", { start: 0, count: 100 });
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a {@link NFTContract}
|
||||
* @param ownerWalletAddress - the wallet address to get owned tokens for
|
||||
* @param queryParams - query params to pass to the query for pagination
|
||||
* @returns a response object that includes the list of owned tokens
|
||||
* @beta
|
||||
* @twfeature ERC721Enumerable | ERC1155Enumerable | ERC721Supply
|
||||
@@ -238,6 +239,7 @@ export function useTotalCirculatingSupply(
|
||||
export function useOwnedNFTs<TContract extends NFTContract>(
|
||||
contract: RequiredParam<TContract>,
|
||||
ownerWalletAddress: RequiredParam<WalletAddress>,
|
||||
queryParams?: QueryAllParams,
|
||||
) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
const { erc721, erc1155 } = getErcs(contract);
|
||||
@@ -248,10 +250,10 @@ export function useOwnedNFTs<TContract extends NFTContract>(
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(ownerWalletAddress, "No wallet address provided");
|
||||
if (erc721) {
|
||||
return await erc721.getOwned(ownerWalletAddress);
|
||||
return await erc721.getOwned(ownerWalletAddress, queryParams);
|
||||
}
|
||||
if (erc1155) {
|
||||
return await erc1155.getOwned(ownerWalletAddress);
|
||||
return await erc1155.getOwned(ownerWalletAddress, queryParams);
|
||||
}
|
||||
invariant(false, "Unknown NFT type");
|
||||
},
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# @thirdweb-dev/react-native-compat
|
||||
|
||||
## 0.3.8
|
||||
|
||||
## 0.3.7
|
||||
|
||||
## 0.3.6
|
||||
|
||||
## 0.3.5
|
||||
|
||||
@@ -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.8",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,55 @@
|
||||
# @thirdweb-dev/react-native
|
||||
|
||||
## 0.3.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1724](https://github.com/thirdweb-dev/js/pull/1724) [`fc62b91e`](https://github.com/thirdweb-dev/js/commit/fc62b91ee55b0adba01298f33b21352004d1b71d) Thanks [@iketw](https://github.com/iketw)! - Adds Google sign in to embeddedWallet in React Native
|
||||
|
||||
You need to add the `react-native-inappbrowser-reborn` package to your app, then you can do:
|
||||
|
||||
```javascript
|
||||
<ThirdwebProvider
|
||||
activeChain={activeChain}
|
||||
clientId={"your-client-id"}
|
||||
supportedWallets={[
|
||||
embeddedWallet({
|
||||
// if this is true AND oauthOptions is not set we set it to false internally
|
||||
email: true,
|
||||
// if this is set we enable Sign in with Google
|
||||
oauthOptions: {
|
||||
redirectUrl: "test15app://",
|
||||
providers: ["google"],
|
||||
},
|
||||
}),
|
||||
]}
|
||||
>
|
||||
<App />
|
||||
</ThirdwebProvider>
|
||||
```
|
||||
|
||||
- Updated dependencies [[`526176c4`](https://github.com/thirdweb-dev/js/commit/526176c47108c91d83bcfc5f0ca556274e6462d6), [`d1f8e951`](https://github.com/thirdweb-dev/js/commit/d1f8e951623f1691fdfe3d1e8645970d0a52eb06), [`09120c92`](https://github.com/thirdweb-dev/js/commit/09120c923cca804b9d4f5f779e5a53c97ecc8223), [`08e9cd20`](https://github.com/thirdweb-dev/js/commit/08e9cd206bcc37cf1e84a878dc78bc4f38e5092c), [`6573556d`](https://github.com/thirdweb-dev/js/commit/6573556d0e03efa0d6a157fccb0a1c08dd22d7cd)]:
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 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/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
- @thirdweb-dev/[email protected]
|
||||
|
||||
## 0.3.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native",
|
||||
"version": "0.3.6",
|
||||
"version": "0.3.8",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -89,7 +89,8 @@
|
||||
"amazon-cognito-identity-js": "^6.3.3",
|
||||
"react-native-quick-base64": "^2.0.7",
|
||||
"react-native-quick-crypto": "^0.6.1",
|
||||
"react-native-aes-gcm-crypto": "^0.2.2"
|
||||
"react-native-aes-gcm-crypto": "^0.2.2",
|
||||
"react-native-inappbrowser-reborn": "^3.7.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ethers": ">=5.5.1 <6",
|
||||
|
||||
@@ -10,3 +10,4 @@ export * from "./right-arrow";
|
||||
export * from "./wallet";
|
||||
export * from "./money";
|
||||
export * from "./switch";
|
||||
export * from "./svgs";
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
export const GOOGLE_ICON = `<svg height={height} viewBox="0 0 24 24" width={width}>
|
||||
<path
|
||||
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
|
||||
fill="#4285F4"
|
||||
/>
|
||||
<path
|
||||
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
|
||||
fill="#34A853"
|
||||
/>
|
||||
<path
|
||||
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
|
||||
fill="#FBBC05"
|
||||
/>
|
||||
<path
|
||||
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
|
||||
fill="#EA4335"
|
||||
/>
|
||||
<path d="M1 1h22v22H1z" fill="none" />
|
||||
</svg>`;
|
||||
|
||||
export const EMAIL_WALLET_ICON = `<svg width="48" height="48" viewBox="0 0 48 48" fill="none">
|
||||
<g clip-path="url(#clip0_3589_8649)">
|
||||
<rect width="48" height="48" rx="8" fill="url(#paint0_linear_3589_8649)"/>
|
||||
|
||||
@@ -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",
|
||||
|
||||
+7
-3
@@ -238,7 +238,8 @@ export const ConnectWalletDetailsModal = ({
|
||||
) : null}
|
||||
</BaseButton>
|
||||
) : null}
|
||||
{activeWallet?.walletId === EmbeddedWallet.id ? (
|
||||
{activeWallet?.walletId === EmbeddedWallet.id &&
|
||||
(activeWallet as EmbeddedWallet).getEmail() ? (
|
||||
<Box flexDirection="row" alignItems="center" mt="md">
|
||||
<ActiveDot width={10} height={10} />
|
||||
<Text variant="bodySmallSecondary" ml="xxs">
|
||||
@@ -246,7 +247,11 @@ export const ConnectWalletDetailsModal = ({
|
||||
</Text>
|
||||
</Box>
|
||||
) : null}
|
||||
<Box flexDirection="row" justifyContent="space-evenly" mt="md">
|
||||
<Box
|
||||
flexDirection="row"
|
||||
justifyContent="space-evenly"
|
||||
marginVertical="md"
|
||||
>
|
||||
<SendButton supportedTokens={supportedTokens} />
|
||||
<ReceiveButton />
|
||||
</Box>
|
||||
@@ -330,7 +335,6 @@ const styles = StyleSheet.create({
|
||||
alignContent: "flex-start",
|
||||
alignItems: "flex-start",
|
||||
justifyContent: "flex-start",
|
||||
marginTop: 24,
|
||||
marginBottom: 8,
|
||||
},
|
||||
});
|
||||
|
||||
+2
-2
@@ -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
|
||||
|
||||
+8
-2
@@ -1,7 +1,6 @@
|
||||
import { AddressDisplay } from "../base/AddressDisplay";
|
||||
import BaseButton from "../base/BaseButton";
|
||||
import Text from "../base/Text";
|
||||
import { WalletIcon } from "../base/WalletIcon";
|
||||
import { useENS, useWallet } from "@thirdweb-dev/react-core";
|
||||
import { StyleSheet } from "react-native";
|
||||
import { LocalWallet, walletIds } from "@thirdweb-dev/wallets";
|
||||
@@ -11,6 +10,7 @@ import { useMemo, useState } from "react";
|
||||
import { TextBalance } from "../base/TextBalance";
|
||||
import { SupportedTokens } from "../SendFunds/defaultTokens";
|
||||
import { SMART_WALLET_ICON } from "../../assets/svgs";
|
||||
import { ImageSvgUri } from "../base";
|
||||
|
||||
export type ConnectWalletDetailsProps = {
|
||||
address?: string;
|
||||
@@ -90,7 +90,13 @@ export const WalletDetailsButton = ({
|
||||
alignContent="center"
|
||||
justifyContent="flex-start"
|
||||
>
|
||||
<WalletIcon size={32} iconUri={avatarUrl || walletIconUrl} />
|
||||
<Box borderRadius="lg" overflow="hidden">
|
||||
<ImageSvgUri
|
||||
width={32}
|
||||
height={32}
|
||||
imageUrl={avatarUrl || walletIconUrl}
|
||||
/>
|
||||
</Box>
|
||||
<Box ml="md" justifyContent="center" alignItems="flex-start">
|
||||
{activeWallet?.walletId === LocalWallet.id ? (
|
||||
<Text variant="bodySmall" color="red">
|
||||
|
||||
+2
-2
@@ -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();
|
||||
|
||||
+3
-5
@@ -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);
|
||||
@@ -261,9 +261,7 @@ export function ChooseWallet({
|
||||
) : null}
|
||||
{showToSPrivacyPolicy ? (
|
||||
<Box
|
||||
mt="md"
|
||||
pt="md"
|
||||
height={50}
|
||||
mt="sm"
|
||||
marginHorizontal={!isConnectAWalletEnabled ? "xl" : "none"}
|
||||
alignItems="center"
|
||||
>
|
||||
|
||||
@@ -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(
|
||||
@@ -60,8 +62,8 @@ export const ConnectWalletFlow = () => {
|
||||
|
||||
const onChooseWallet = useCallback(
|
||||
(wallet: WalletConfig, data?: any) => {
|
||||
setActiveWallet(wallet);
|
||||
setSelectionData(data);
|
||||
setActiveWallet(wallet);
|
||||
|
||||
// If the wallet has no custom connect UI, then connect it
|
||||
if (!wallet.connectUI) {
|
||||
@@ -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
-1
@@ -30,7 +30,7 @@ export function ConnectingWallet({
|
||||
subHeaderText={subHeaderText}
|
||||
onClose={onClose}
|
||||
/>
|
||||
<WalletLoadingThumbnail imageSize={100}>
|
||||
<WalletLoadingThumbnail imageSize={85}>
|
||||
<ImageSvgUri height={80} width={80} imageUrl={wallet.meta.iconURL} />
|
||||
</WalletLoadingThumbnail>
|
||||
<View style={styles.connectingContainer}>
|
||||
|
||||
+2
-2
@@ -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}>
|
||||
|
||||
+2
-2
@@ -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) {
|
||||
|
||||
+3
-3
@@ -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<
|
||||
@@ -131,7 +131,7 @@ export const SmartWalletFlow = ({
|
||||
onBackPress={onConnectingBackPress}
|
||||
onClose={onConnectingClosePress}
|
||||
/>
|
||||
<WalletLoadingThumbnail imageSize={100}>
|
||||
<WalletLoadingThumbnail imageSize={85}>
|
||||
<ImageSvgUri
|
||||
height={80}
|
||||
width={80}
|
||||
|
||||
@@ -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 MODAL_HEIGHT = Dimensions.get("window").height * 0.7;
|
||||
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,12 +139,12 @@ const SendFundsForm = ({
|
||||
onTokenSelectorPress: () => void;
|
||||
token?: TokenInfo;
|
||||
}) => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
const chain = useChain();
|
||||
const wallet = useWallet();
|
||||
const chainId = useChainId();
|
||||
const [receiverAddress, setReceiverAddress] = useState("");
|
||||
const [amount, setAmount] = useState("");
|
||||
const [amount, setAmount] = useState("0");
|
||||
const [showIcon, setShowIcon] = useState(false);
|
||||
const tokenAddress = token?.address;
|
||||
|
||||
@@ -313,6 +313,7 @@ const SendFundsForm = ({
|
||||
editable={!sendTokenMutation.isLoading}
|
||||
returnKeyType={"done"}
|
||||
keyboardType="numeric"
|
||||
value={amount}
|
||||
clearTextOnFocus={false}
|
||||
style={{
|
||||
color: theme.colors.textPrimary,
|
||||
@@ -322,8 +323,6 @@ const SendFundsForm = ({
|
||||
paddingHorizontal: 16,
|
||||
}}
|
||||
onChangeText={setAmount}
|
||||
placeholder="0"
|
||||
placeholderTextColor={theme.colors.textPrimary}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
/>
|
||||
@@ -348,11 +347,18 @@ const SendFundsForm = ({
|
||||
}}
|
||||
>
|
||||
{sendTokenMutation.isLoading ? (
|
||||
<ActivityIndicator size="small" color={theme.colors.textPrimary} />
|
||||
<ActivityIndicator
|
||||
size="small"
|
||||
color={theme.colors.accentButtonTextColor}
|
||||
/>
|
||||
) : showIcon ? (
|
||||
<CheckIcon width={20} height={13} color={theme.colors.textPrimary} />
|
||||
<CheckIcon
|
||||
width={20}
|
||||
height={13}
|
||||
color={theme.colors.accentButtonTextColor}
|
||||
/>
|
||||
) : (
|
||||
<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();
|
||||
|
||||
@@ -35,7 +35,7 @@ const ImageSvgUri = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Box style={{ width: width, height: height }}>
|
||||
<Box width={width} height={height}>
|
||||
{error ? (
|
||||
<SvgUri width={width} height={height} uri={resolvedImageUrl} />
|
||||
) : (
|
||||
|
||||
@@ -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);
|
||||
@@ -72,6 +72,7 @@ export const NetworkButton = ({
|
||||
<>
|
||||
<BaseButton
|
||||
p={padding || "sm"}
|
||||
paddingVertical="xs"
|
||||
borderRadius="md"
|
||||
borderWidth={0.5}
|
||||
flexDirection="row"
|
||||
@@ -82,13 +83,8 @@ export const NetworkButton = ({
|
||||
{...props}
|
||||
>
|
||||
<Box flexDirection="row" alignItems="center">
|
||||
<ChainIcon chainIconUrl={chain?.icon?.url} size={32} />
|
||||
<Box
|
||||
ml="md"
|
||||
alignItems="flex-start"
|
||||
justifyContent="center"
|
||||
height={36}
|
||||
>
|
||||
<ChainIcon chainIconUrl={chain?.icon?.url} size={28} />
|
||||
<Box ml="md" alignItems="flex-start" justifyContent="center">
|
||||
<Text variant="bodyLarge">{chain?.name || "Unknown Network"}</Text>
|
||||
{isSwitching ? (
|
||||
<Box flexDirection="row" alignItems="center">
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -4,20 +4,27 @@ import ImageSvgUri from "./ImageSvgUri";
|
||||
import { Label } from "./Label";
|
||||
import Text from "./Text";
|
||||
import Box from "./Box";
|
||||
import { Palette } from "../../styles/colors";
|
||||
|
||||
type WalletButtonProps = {
|
||||
onPress?: () => void;
|
||||
walletIconUrl: string;
|
||||
name: string;
|
||||
nameColor?: keyof Palette;
|
||||
labelText?: string;
|
||||
recommended?: boolean;
|
||||
iconWidth?: number;
|
||||
iconHeight?: number;
|
||||
} & React.ComponentProps<typeof BaseButton>;
|
||||
|
||||
export const WalletButton = ({
|
||||
iconWidth = 48,
|
||||
iconHeight = 48,
|
||||
mb,
|
||||
onPress,
|
||||
walletIconUrl,
|
||||
name,
|
||||
nameColor = "textPrimary",
|
||||
labelText,
|
||||
recommended,
|
||||
...props
|
||||
@@ -36,9 +43,15 @@ export const WalletButton = ({
|
||||
{...props}
|
||||
>
|
||||
<Box flexDirection="row" justifyContent="flex-start" alignItems="center">
|
||||
<ImageSvgUri imageUrl={walletIconUrl} width={48} height={48} />
|
||||
<ImageSvgUri
|
||||
imageUrl={walletIconUrl}
|
||||
width={iconWidth}
|
||||
height={iconHeight}
|
||||
/>
|
||||
<Box ml="sm" alignItems="flex-start">
|
||||
<Text variant="bodyLarge">{name}</Text>
|
||||
<Text variant="bodyLarge" color={nameColor}>
|
||||
{name}
|
||||
</Text>
|
||||
{recommended ? <Text variant="link">Recommended</Text> : null}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
+32
-1
@@ -1,12 +1,13 @@
|
||||
import {
|
||||
EmbeddedWalletConnectionArgs,
|
||||
EmbeddedWalletConnectorOptions,
|
||||
OauthOption,
|
||||
} from "./types";
|
||||
import type { Chain } from "@thirdweb-dev/chains";
|
||||
import { Connector, normalizeChainId } from "@thirdweb-dev/wallets";
|
||||
import { providers, Signer } from "ethers";
|
||||
import { utils } from "ethers";
|
||||
import { sendEmailOTP, validateEmailOTP } from "./embedded/auth";
|
||||
import { sendEmailOTP, socialLogin, validateEmailOTP } from "./embedded/auth";
|
||||
import { getEthersSigner } from "./embedded/signer";
|
||||
import { logoutUser } from "./embedded/helpers/auth/logout";
|
||||
import {
|
||||
@@ -83,6 +84,36 @@ export class EmbeddedWalletConnector extends Connector<EmbeddedWalletConnectionA
|
||||
return sendEmailOTP(email, this.options.clientId);
|
||||
}
|
||||
|
||||
async socialLogin(oauthOption: OauthOption) {
|
||||
try {
|
||||
const { email } = await socialLogin(oauthOption, this.options.clientId);
|
||||
this.email = email;
|
||||
saveConnectedEmail(email);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Error while signing in with: ${oauthOption.provider}. ${error}`,
|
||||
);
|
||||
if (error instanceof Error) {
|
||||
return { error: error.message };
|
||||
} else {
|
||||
return { error: "An unknown error occurred" };
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await this.getSigner();
|
||||
this.emit("connected");
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
return { error: error.message };
|
||||
} else {
|
||||
return { error: "Error getting the signer" };
|
||||
}
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
async disconnect(): Promise<void> {
|
||||
clearConnectedEmail();
|
||||
await logoutUser(this.options.clientId);
|
||||
|
||||
@@ -19,6 +19,9 @@ import { postPaperAuth, prePaperAuth } from "./helpers/auth/middleware";
|
||||
import { isDeviceSharePresentForUser } from "./helpers/storage/local";
|
||||
import { getCognitoUser, setCognitoUser } from "./helpers/storage/state";
|
||||
import { SendEmailOtpReturnType } from "@thirdweb-dev/wallets";
|
||||
import { InAppBrowser } from "react-native-inappbrowser-reborn";
|
||||
import { OauthOption } from "../types";
|
||||
import { ROUTE_HEADLESS_GOOGLE_LOGIN } from "./helpers/constants";
|
||||
|
||||
export async function sendEmailOTP(
|
||||
email: string,
|
||||
@@ -122,3 +125,74 @@ export async function validateEmailOTP({
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function socialLogin(oauthOptions: OauthOption, clientId: string) {
|
||||
const headlessLoginLinkWithParams = `${ROUTE_HEADLESS_GOOGLE_LOGIN}?authProvider=${encodeURIComponent(
|
||||
"google",
|
||||
)}&baseUrl=${encodeURIComponent(
|
||||
"https://ews.thirdweb.com",
|
||||
)}&platform=${encodeURIComponent("mobile")}`;
|
||||
|
||||
const resp = await fetch(headlessLoginLinkWithParams);
|
||||
|
||||
if (!resp.ok) {
|
||||
throw new Error("Error getting headless login link");
|
||||
}
|
||||
|
||||
const json = await resp.json();
|
||||
|
||||
const { platformLoginLink } = json;
|
||||
|
||||
const completeLoginUrl = `${platformLoginLink}?developerClientId=${encodeURIComponent(
|
||||
clientId || "",
|
||||
)}&platform=${encodeURIComponent("mobile")}&redirectUrl=${encodeURIComponent(
|
||||
oauthOptions.redirectUrl,
|
||||
)}`;
|
||||
|
||||
const result = await InAppBrowser.openAuth(
|
||||
completeLoginUrl,
|
||||
oauthOptions.redirectUrl,
|
||||
{
|
||||
// iOS Properties
|
||||
ephemeralWebSession: false,
|
||||
// Android Properties
|
||||
showTitle: false,
|
||||
enableUrlBarHiding: false,
|
||||
enableDefaultShare: false,
|
||||
},
|
||||
);
|
||||
|
||||
if (result.type !== "success") {
|
||||
throw new Error("Error signing in. Please try again later.");
|
||||
}
|
||||
|
||||
const decodedUrl = decodeURIComponent(result.url);
|
||||
|
||||
const parts = decodedUrl.split("?authResult=");
|
||||
if (parts.length < 2) {
|
||||
throw new Error("Malformed response from the login redirect");
|
||||
}
|
||||
const authResult = parts[1];
|
||||
const { storedToken } = JSON.parse(authResult);
|
||||
|
||||
try {
|
||||
const toStoreToken: AuthStoredTokenWithCookieReturnType["storedToken"] = {
|
||||
jwtToken: storedToken.jwtToken,
|
||||
authDetails: storedToken.authDetails,
|
||||
authProvider: storedToken.authProvider,
|
||||
developerClientId: storedToken.developerClientId,
|
||||
cookieString: storedToken.cookieString,
|
||||
// we should always store the jwt cookie since there's no concept of cookie in react native
|
||||
shouldStoreCookieString: true,
|
||||
isNewUser: storedToken.isNewUser,
|
||||
};
|
||||
|
||||
await postPaperAuth(toStoreToken, clientId);
|
||||
|
||||
return { storedToken, email: storedToken.authDetails.email };
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Malformed response from post authentication: ${JSON.stringify(e)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+2
@@ -30,4 +30,6 @@ export const ROUTE_STORE_USER_SHARES = `${ROUTE_2022_08_12_API_BASE_PATH}/embedd
|
||||
export const ROUTE_GET_USER_SHARES = `${ROUTE_2022_08_12_API_BASE_PATH}/embedded-wallet/get-shares`;
|
||||
export const ROUTE_VERIFY_THIRDWEB_CLIENT_ID = `${ROUTE_2022_08_12_API_BASE_PATH}/embedded-wallet/verify-thirdweb-client-id`;
|
||||
|
||||
export const ROUTE_HEADLESS_GOOGLE_LOGIN = `${BASE_URL}/api/2022-08-12/embedded-wallet/headless-login-link`;
|
||||
|
||||
export const ROUTE_AUTH_COGNITO_ID_TOKEN = `${ROUTE_2022_08_12_API_BASE_PATH}/embedded-wallet/cognito-id-token`;
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
import { Chain } from "@thirdweb-dev/chains";
|
||||
import { WalletOptions } from "@thirdweb-dev/wallets";
|
||||
|
||||
import type {
|
||||
RecoveryShareManagement,
|
||||
PaperConstructorType,
|
||||
AuthProvider,
|
||||
} from "@paperxyz/embedded-wallet-service-sdk";
|
||||
|
||||
export type OauthOptions = {
|
||||
providers: AuthProvider[];
|
||||
redirectUrl: string;
|
||||
};
|
||||
|
||||
export type OauthOption = {
|
||||
provider: AuthProvider;
|
||||
redirectUrl: string;
|
||||
};
|
||||
|
||||
export interface EmbeddedConnectorOptions {
|
||||
chains?: Chain[];
|
||||
chainId?: number;
|
||||
|
||||
@@ -12,12 +12,14 @@ 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 { StyleSheet } from "react-native";
|
||||
import { EmbeddedSocialConnection } from "./EmbeddedSocialConnection";
|
||||
import { useGlobalTheme } from "../../../providers/ui-context-provider";
|
||||
|
||||
const OTP_LENGTH = 6;
|
||||
|
||||
@@ -26,8 +28,9 @@ export const EmbeddedConnectionUI: React.FC<ConnectUIProps<EmbeddedWallet>> = ({
|
||||
goBack,
|
||||
selectionData,
|
||||
onLocallyConnected,
|
||||
...props
|
||||
}) => {
|
||||
const theme = useAppTheme();
|
||||
const theme = useGlobalTheme();
|
||||
const inputRefs = useRef<(TextInput | null)[]>([]);
|
||||
const [values, setValues] = useState<string[]>(
|
||||
new Array(OTP_LENGTH).fill(""),
|
||||
@@ -104,6 +107,7 @@ export const EmbeddedConnectionUI: React.FC<ConnectUIProps<EmbeddedWallet>> = ({
|
||||
inputRefs.current[i]?.setNativeProps({ text: newValues[i] });
|
||||
}
|
||||
setValues(newValues);
|
||||
Clipboard.setStringAsync("");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -157,6 +161,18 @@ export const EmbeddedConnectionUI: React.FC<ConnectUIProps<EmbeddedWallet>> = ({
|
||||
});
|
||||
};
|
||||
|
||||
if (selectionData?.oauthOptions) {
|
||||
return (
|
||||
<EmbeddedSocialConnection
|
||||
connected={() => {}}
|
||||
goBack={goBack}
|
||||
onLocallyConnected={onLocallyConnected}
|
||||
selectionData={selectionData}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box marginHorizontal="xl">
|
||||
<ConnectWalletHeader
|
||||
@@ -198,10 +214,8 @@ export const EmbeddedConnectionUI: React.FC<ConnectUIProps<EmbeddedWallet>> = ({
|
||||
<TextInput
|
||||
ref={(ref) => (inputRefs.current[index] = ref)}
|
||||
style={{
|
||||
fontSize: 20,
|
||||
...styles.textInput,
|
||||
color: theme.colors.textPrimary,
|
||||
textAlign: "center",
|
||||
height: 50,
|
||||
}}
|
||||
keyboardType="number-pad"
|
||||
editable={!checkingOtp}
|
||||
@@ -246,3 +260,11 @@ export const EmbeddedConnectionUI: React.FC<ConnectUIProps<EmbeddedWallet>> = ({
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
textInput: {
|
||||
fontSize: 20,
|
||||
textAlign: "center",
|
||||
height: 50,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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,21 +9,30 @@ 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 { GOOGLE_ICON } from "../../../assets/svgs";
|
||||
import { WalletButton } from "../../../components/base/WalletButton";
|
||||
import { AuthProvider } from "@paperxyz/embedded-wallet-service-sdk";
|
||||
import { OauthOptions } from "../../connectors/embedded-wallet/types";
|
||||
import { useGlobalTheme } from "../../../providers/ui-context-provider";
|
||||
|
||||
/**
|
||||
* UI for selecting wallet - this UI is rendered in the wallet selection screen
|
||||
*/
|
||||
export const EmailSelectionUI: React.FC<SelectUIProps<EmbeddedWallet>> = ({
|
||||
onSelect,
|
||||
walletConfig,
|
||||
}) => {
|
||||
const theme = useAppTheme();
|
||||
const [email, setEmail] = useState<string>("");
|
||||
export const EmailSelectionUI: React.FC<
|
||||
SelectUIProps<EmbeddedWallet> & {
|
||||
oauthOptions?: OauthOptions;
|
||||
email?: boolean;
|
||||
}
|
||||
> = ({ onSelect, walletConfig, oauthOptions, email }) => {
|
||||
const theme = useGlobalTheme();
|
||||
const [emailInput, setEmailInput] = useState<string>("");
|
||||
const [errorMessage, setErrorMessage] = useState<string>("");
|
||||
const [isFetching, setIsFetching] = useState<boolean>(false);
|
||||
const createWalletInstance = useCreateWalletInstance();
|
||||
const [emailWallet, setEmailWallet] = useState<EmbeddedWallet | null>(null);
|
||||
|
||||
const isEmailEnabled = email === false ? false : true;
|
||||
|
||||
useEffect(() => {
|
||||
const emailWalletInstance = createWalletInstance(
|
||||
walletConfig,
|
||||
@@ -39,17 +47,18 @@ export const EmailSelectionUI: React.FC<SelectUIProps<EmbeddedWallet>> = ({
|
||||
};
|
||||
|
||||
const handleNetworkCall = () => {
|
||||
if (validateEmail(email)) {
|
||||
if (validateEmail(emailInput)) {
|
||||
setErrorMessage("");
|
||||
setIsFetching(true);
|
||||
|
||||
emailWallet
|
||||
?.sendEmailOTP(email)
|
||||
?.sendEmailOTP(emailInput)
|
||||
.then((response) => {
|
||||
onSelect({
|
||||
...response,
|
||||
email,
|
||||
email: emailInput,
|
||||
emailWallet,
|
||||
oauthOptions: undefined,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -65,58 +74,109 @@ export const EmailSelectionUI: React.FC<SelectUIProps<EmbeddedWallet>> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const onGoogleSignInPress = () => {
|
||||
onSelect({
|
||||
email: emailInput,
|
||||
emailWallet,
|
||||
oauthOptions: {
|
||||
provider: oauthOptions?.providers[0],
|
||||
redirectUrl: oauthOptions?.redirectUrl,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Box paddingHorizontal="xl" mt="lg">
|
||||
<TextInput
|
||||
textInputProps={{
|
||||
placeholder: "Enter your email address",
|
||||
placeholderTextColor: theme.colors.textSecondary,
|
||||
onChangeText: setEmail,
|
||||
style: {
|
||||
fontSize: 14,
|
||||
color: theme.colors.textPrimary,
|
||||
lineHeight: 16,
|
||||
padding: 0,
|
||||
flex: 1,
|
||||
},
|
||||
value: email,
|
||||
keyboardType: "email-address",
|
||||
returnKeyType: "done",
|
||||
autoCapitalize: "none",
|
||||
autoCorrect: false,
|
||||
autoComplete: "off",
|
||||
clearTextOnFocus: false,
|
||||
}}
|
||||
containerProps={{
|
||||
paddingHorizontal: "sm",
|
||||
paddingVertical: "sm",
|
||||
justifyContent: "flex-start",
|
||||
}}
|
||||
/>
|
||||
<BaseButton
|
||||
mt="md"
|
||||
paddingVertical="md"
|
||||
borderRadius="lg"
|
||||
borderWidth={1}
|
||||
borderColor="border"
|
||||
backgroundColor="accentButtonColor"
|
||||
onPress={handleNetworkCall}
|
||||
>
|
||||
{isFetching ? (
|
||||
<ActivityIndicator
|
||||
size={"small"}
|
||||
color={theme.colors.accentButtonTextColor}
|
||||
{oauthOptions?.providers.includes(AuthProvider.GOOGLE) ? (
|
||||
<Box justifyContent="center">
|
||||
<WalletButton
|
||||
iconHeight={28}
|
||||
iconWidth={28}
|
||||
borderRadius="lg"
|
||||
borderWidth={1}
|
||||
borderColor="buttonBackgroundColor"
|
||||
backgroundColor="buttonBackgroundColor"
|
||||
nameColor="buttonTextColor"
|
||||
justifyContent="center"
|
||||
name="Sign in with Google"
|
||||
walletIconUrl={GOOGLE_ICON}
|
||||
onPress={onGoogleSignInPress}
|
||||
/>
|
||||
) : (
|
||||
<Text
|
||||
variant="bodySmall"
|
||||
color="accentButtonTextColor"
|
||||
fontWeight="700"
|
||||
{isEmailEnabled ? (
|
||||
<Box
|
||||
mb="md"
|
||||
mt="md"
|
||||
flexDirection="row"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
>
|
||||
<Box height={1} flex={1} backgroundColor="border" />
|
||||
<Text
|
||||
variant="subHeader"
|
||||
textAlign="center"
|
||||
marginHorizontal="xxs"
|
||||
>
|
||||
OR
|
||||
</Text>
|
||||
<Box height={1} flex={1} backgroundColor="border" />
|
||||
</Box>
|
||||
) : null}
|
||||
</Box>
|
||||
) : null}
|
||||
{isEmailEnabled ? (
|
||||
<>
|
||||
<TextInput
|
||||
textInputProps={{
|
||||
placeholder: "Enter your email address",
|
||||
placeholderTextColor: theme.colors.textSecondary,
|
||||
onChangeText: setEmailInput,
|
||||
style: {
|
||||
fontSize: 14,
|
||||
color: theme.colors.textPrimary,
|
||||
lineHeight: 16,
|
||||
padding: 0,
|
||||
flex: 1,
|
||||
},
|
||||
value: emailInput,
|
||||
keyboardType: "email-address",
|
||||
returnKeyType: "done",
|
||||
autoCapitalize: "none",
|
||||
autoCorrect: false,
|
||||
autoComplete: "off",
|
||||
clearTextOnFocus: false,
|
||||
}}
|
||||
containerProps={{
|
||||
paddingHorizontal: "sm",
|
||||
paddingVertical: "sm",
|
||||
justifyContent: "flex-start",
|
||||
}}
|
||||
/>
|
||||
<BaseButton
|
||||
mt="md"
|
||||
paddingVertical="md"
|
||||
borderRadius="lg"
|
||||
borderWidth={1}
|
||||
borderColor="border"
|
||||
backgroundColor="accentButtonColor"
|
||||
onPress={handleNetworkCall}
|
||||
>
|
||||
Continue
|
||||
</Text>
|
||||
)}
|
||||
</BaseButton>
|
||||
{isFetching ? (
|
||||
<ActivityIndicator
|
||||
size={"small"}
|
||||
color={theme.colors.accentButtonTextColor}
|
||||
/>
|
||||
) : (
|
||||
<Text
|
||||
variant="bodySmall"
|
||||
color="accentButtonTextColor"
|
||||
fontWeight="700"
|
||||
>
|
||||
Continue
|
||||
</Text>
|
||||
)}
|
||||
</BaseButton>
|
||||
</>
|
||||
) : null}
|
||||
{errorMessage ? (
|
||||
<Text variant="error" mt="xxs">
|
||||
{errorMessage}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import React from "react";
|
||||
import { ActivityIndicator } from "react-native";
|
||||
import { EmbeddedWallet } from "./EmbeddedWallet";
|
||||
import {
|
||||
ConnectUIProps,
|
||||
useSetConnectedWallet,
|
||||
useSetConnectionStatus,
|
||||
} from "@thirdweb-dev/react-core";
|
||||
import { GOOGLE_ICON } from "../../../assets";
|
||||
import { ConnectWalletHeader } from "../../../components/ConnectWalletFlow/ConnectingWallet/ConnectingWalletHeader";
|
||||
import { Box, Text, WalletButton } from "../../../components/base";
|
||||
|
||||
export const EmbeddedSocialConnection: React.FC<
|
||||
ConnectUIProps<EmbeddedWallet>
|
||||
> = ({ goBack, selectionData, onLocallyConnected }) => {
|
||||
const setConnectedWallet = useSetConnectedWallet();
|
||||
const setConnectionStatus = useSetConnectionStatus();
|
||||
const [errorMessage, setErrorMessage] = useState<string>();
|
||||
|
||||
const handleGoogleLogin = useCallback(() => {
|
||||
setErrorMessage("");
|
||||
|
||||
setTimeout(() => {
|
||||
(selectionData.emailWallet as EmbeddedWallet)
|
||||
.socialLogin(selectionData?.oauthOptions)
|
||||
.then(async (response) => {
|
||||
if (response?.success) {
|
||||
if (onLocallyConnected) {
|
||||
onLocallyConnected(selectionData.emailWallet);
|
||||
} else {
|
||||
await setConnectedWallet(selectionData.emailWallet);
|
||||
setConnectionStatus("connected");
|
||||
}
|
||||
} else {
|
||||
setErrorMessage(
|
||||
response?.error || "Error login in. Please try again later.",
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error validating otp: ", error);
|
||||
setErrorMessage("Error login in. Please try again later.");
|
||||
});
|
||||
}, 0);
|
||||
}, [
|
||||
onLocallyConnected,
|
||||
selectionData.emailWallet,
|
||||
selectionData.oauthOptions,
|
||||
setConnectedWallet,
|
||||
setConnectionStatus,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
handleGoogleLogin();
|
||||
}, [handleGoogleLogin]);
|
||||
|
||||
return (
|
||||
<Box marginHorizontal="xl" height={200}>
|
||||
<ConnectWalletHeader
|
||||
middleContent={
|
||||
<WalletButton
|
||||
iconHeight={28}
|
||||
iconWidth={28}
|
||||
borderRadius="lg"
|
||||
justifyContent="center"
|
||||
name="Sign In"
|
||||
walletIconUrl={GOOGLE_ICON}
|
||||
/>
|
||||
}
|
||||
subHeaderText={""}
|
||||
onBackPress={goBack}
|
||||
onClose={goBack}
|
||||
/>
|
||||
<Box flex={1} justifyContent="center" alignItems="center">
|
||||
{!errorMessage ? (
|
||||
<ActivityIndicator size="large" />
|
||||
) : (
|
||||
<Text variant="error" numberOfLines={1}>
|
||||
{errorMessage}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -5,7 +5,10 @@ import {
|
||||
walletIds,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
import type { EmbeddedWalletConnector as EmbeddedConnectorType } from "../../connectors/embedded-wallet/embedded-connector";
|
||||
import { EmbeddedWalletConnectionArgs } from "../../connectors/embedded-wallet/types";
|
||||
import {
|
||||
EmbeddedWalletConnectionArgs,
|
||||
OauthOption,
|
||||
} from "../../connectors/embedded-wallet/types";
|
||||
import { EmbeddedWalletConnector } from "../../connectors/embedded-wallet/embedded-connector";
|
||||
import { EMAIL_WALLET_ICON } from "../../../assets/svgs";
|
||||
|
||||
@@ -43,8 +46,6 @@ export class EmbeddedWallet extends AbstractClientWallet<
|
||||
return this.connector;
|
||||
}
|
||||
|
||||
// my methods
|
||||
|
||||
initializeConnector() {
|
||||
this.connector = new EmbeddedWalletConnector({
|
||||
...this.options,
|
||||
@@ -63,6 +64,10 @@ export class EmbeddedWallet extends AbstractClientWallet<
|
||||
return this.connector?.sendEmailOtp(email);
|
||||
}
|
||||
|
||||
async socialLogin(oauthOption: OauthOption) {
|
||||
return this.connector?.socialLogin(oauthOption);
|
||||
}
|
||||
|
||||
onConnected = () => {
|
||||
this.emit("message", { type: "connected" });
|
||||
};
|
||||
|
||||
@@ -6,16 +6,40 @@ import {
|
||||
} from "@thirdweb-dev/react-core";
|
||||
import { EmbeddedConnectionUI } from "./EmbeddedConnectionUI";
|
||||
import { EmailSelectionUI } from "./EmbeddedSelectionUI";
|
||||
import { AuthProvider } from "@paperxyz/embedded-wallet-service-sdk";
|
||||
|
||||
type OAuthProvider = "google"; // currently we only have one
|
||||
|
||||
export type EmbeddedWalletConfig = {
|
||||
recommended?: boolean;
|
||||
// @default true - set false to disable
|
||||
email?: boolean;
|
||||
|
||||
// @default { providers: ['google'] } - set false to disable
|
||||
oauthOptions?:
|
||||
| {
|
||||
providers: OAuthProvider[];
|
||||
redirectUrl: string;
|
||||
}
|
||||
| false;
|
||||
};
|
||||
|
||||
export const embeddedWallet = (
|
||||
config?: EmbeddedWalletConfig,
|
||||
): WalletConfig<EmbeddedWallet> => {
|
||||
const selectUI = (props: SelectUIProps<EmbeddedWallet>) => (
|
||||
<EmailSelectionUI {...props} />
|
||||
<EmailSelectionUI
|
||||
{...props}
|
||||
oauthOptions={
|
||||
config?.oauthOptions
|
||||
? {
|
||||
providers: [AuthProvider.GOOGLE],
|
||||
redirectUrl: config.oauthOptions.redirectUrl,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
// you cannot disable both email and oauth
|
||||
email={!config?.oauthOptions && !config?.email ? true : config?.email}
|
||||
/>
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -29,6 +53,5 @@ export const embeddedWallet = (
|
||||
},
|
||||
selectUI: selectUI,
|
||||
connectUI: EmbeddedConnectionUI,
|
||||
recommended: config?.recommended,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
+2
-2
@@ -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(() => {
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# @thirdweb-dev/react
|
||||
|
||||
## 4.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1766](https://github.com/thirdweb-dev/js/pull/1766) [`dd7d0fca`](https://github.com/thirdweb-dev/js/commit/dd7d0fca2d14a529343396a31939d49b1a074d3e) Thanks [@MananTank](https://github.com/MananTank)! - Fix Continue as Guest button missing when Social + Guest login is setup in ConnectWallet Modal
|
||||
|
||||
- [#1692](https://github.com/thirdweb-dev/js/pull/1692) [`fb0f12ae`](https://github.com/thirdweb-dev/js/commit/fb0f12ae2835f4eba60ba4a74b453151cab0d393) Thanks [@etnlbck](https://github.com/etnlbck)! - Refactored OTPInput component to be simpler to read
|
||||
|
||||
- Updated dependencies [[`526176c4`](https://github.com/thirdweb-dev/js/commit/526176c47108c91d83bcfc5f0ca556274e6462d6), [`d1f8e951`](https://github.com/thirdweb-dev/js/commit/d1f8e951623f1691fdfe3d1e8645970d0a52eb06), [`09120c92`](https://github.com/thirdweb-dev/js/commit/09120c923cca804b9d4f5f779e5a53c97ecc8223), [`08e9cd20`](https://github.com/thirdweb-dev/js/commit/08e9cd206bcc37cf1e84a878dc78bc4f38e5092c), [`6573556d`](https://github.com/thirdweb-dev/js/commit/6573556d0e03efa0d6a157fccb0a1c08dd22d7cd)]:
|
||||
- @thirdweb-dev/sdk@4.0.2
|
||||
- @thirdweb-dev/react-core@4.0.3
|
||||
- @thirdweb-dev/wallets@2.0.3
|
||||
|
||||
## 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,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "4.0.1",
|
||||
"version": "4.0.3",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -36,7 +36,7 @@ export function OTPInput(props: {
|
||||
data-error={props.isInvalid}
|
||||
ref={(e) => (boxEls.current[i] = e)}
|
||||
key={i}
|
||||
value={otp[i] === undefined ? "" : otp[i]}
|
||||
value={otp[i] ?? ""}
|
||||
type="number"
|
||||
variant="outline"
|
||||
onPaste={(e) => {
|
||||
@@ -44,7 +44,7 @@ export function OTPInput(props: {
|
||||
const newOTP = pastedData
|
||||
.slice(0, props.digits)
|
||||
.split("")
|
||||
.filter((n) => /[0-9]/.test(n))
|
||||
.filter((n) => /\d/.test(n))
|
||||
.map(Number);
|
||||
|
||||
setOTP(newOTP);
|
||||
@@ -100,7 +100,7 @@ export function OTPInput(props: {
|
||||
}
|
||||
}
|
||||
|
||||
if (!/[0-9]/.test(value) && value !== "") {
|
||||
if (!/\d/.test(value) && value !== "") {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,218 @@ 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 || continueAsGuest ? (
|
||||
<>
|
||||
<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 +357,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 +465,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 +510,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>
|
||||
|
||||
@@ -1,5 +1,32 @@
|
||||
# @thirdweb-dev/sdk
|
||||
|
||||
## 4.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1764](https://github.com/thirdweb-dev/js/pull/1764) [`526176c4`](https://github.com/thirdweb-dev/js/commit/526176c47108c91d83bcfc5f0ca556274e6462d6) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Perf improvement for marketplace methods
|
||||
|
||||
- [#1763](https://github.com/thirdweb-dev/js/pull/1763) [`d1f8e951`](https://github.com/thirdweb-dev/js/commit/d1f8e951623f1691fdfe3d1e8645970d0a52eb06) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Improve fetchPublishedContractFromPolygon
|
||||
|
||||
- [#1765](https://github.com/thirdweb-dev/js/pull/1765) [`09120c92`](https://github.com/thirdweb-dev/js/commit/09120c923cca804b9d4f5f779e5a53c97ecc8223) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Perf improvement for getting deployment info
|
||||
|
||||
- [#1762](https://github.com/thirdweb-dev/js/pull/1762) [`6573556d`](https://github.com/thirdweb-dev/js/commit/6573556d0e03efa0d6a157fccb0a1c08dd22d7cd) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Perf improvement for drop-claim-condition
|
||||
|
||||
## 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,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/sdk",
|
||||
"version": "4.0.0",
|
||||
"version": "4.0.2",
|
||||
"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;
|
||||
}
|
||||
|
||||
@@ -50,18 +50,18 @@ export async function fetchPublishedContractFromPolygon(
|
||||
});
|
||||
|
||||
// get the metadata for each version
|
||||
const versionMetadata = await Promise.all(
|
||||
allVersions.map(async (c) => {
|
||||
return {
|
||||
name: c.id,
|
||||
publishedTimestamp: c.timestamp,
|
||||
publishedMetadata: await fetchAndCacheDeployMetadata(
|
||||
c.metadataUri,
|
||||
storage,
|
||||
),
|
||||
};
|
||||
}),
|
||||
);
|
||||
const versionMetadata = (
|
||||
await Promise.all(
|
||||
allVersions.map((c) =>
|
||||
fetchAndCacheDeployMetadata(c.metadataUri, storage),
|
||||
),
|
||||
)
|
||||
).map((item, index) => ({
|
||||
name: allVersions[index].id,
|
||||
publishedTimestamp: allVersions[index].timestamp,
|
||||
publishedMetadata: item,
|
||||
}));
|
||||
|
||||
// find the version that matches the version string
|
||||
const versionMatch = versionMetadata.find(
|
||||
(metadata) =>
|
||||
|
||||
@@ -37,15 +37,13 @@ export async function getDeploymentInfo(
|
||||
secretKey?: string,
|
||||
): Promise<DeploymentPreset[]> {
|
||||
caches.deploymentPresets = {};
|
||||
|
||||
const create2FactoryAddress = create2Factory
|
||||
? create2Factory
|
||||
: await getCreate2FactoryAddress(provider);
|
||||
|
||||
const [create2FactoryAddress, { compilerMetadata, extendedMetadata }] =
|
||||
await Promise.all([
|
||||
create2Factory ? create2Factory : getCreate2FactoryAddress(provider),
|
||||
fetchAndCacheDeployMetadata(metadataUri, storage),
|
||||
]);
|
||||
const customParams: ConstructorParamMap = {};
|
||||
const finalDeploymentInfo: DeploymentPreset[] = [];
|
||||
const { compilerMetadata, extendedMetadata } =
|
||||
await fetchAndCacheDeployMetadata(metadataUri, storage);
|
||||
const defaultExtensions = extendedMetadata?.defaultExtensions;
|
||||
|
||||
if (extendedMetadata?.routerType === "plugin" && defaultExtensions) {
|
||||
@@ -65,16 +63,16 @@ export async function getDeploymentInfo(
|
||||
|
||||
const pluginMetadata = (
|
||||
await Promise.all(
|
||||
publishedExtensions.map(async (c) => {
|
||||
return fetchAndCacheDeployMetadata(c.metadataUri, storage);
|
||||
}),
|
||||
publishedExtensions.map((c) =>
|
||||
fetchAndCacheDeployMetadata(c.metadataUri, storage),
|
||||
),
|
||||
)
|
||||
).map((fetchedMetadata) => fetchedMetadata.compilerMetadata);
|
||||
|
||||
// get deployment info for all plugins
|
||||
const pluginDeploymentInfo = await Promise.all(
|
||||
pluginMetadata.map(async (metadata) => {
|
||||
const info = await computeDeploymentInfo(
|
||||
pluginMetadata.map((metadata) =>
|
||||
computeDeploymentInfo(
|
||||
"plugin",
|
||||
provider,
|
||||
storage,
|
||||
@@ -82,9 +80,8 @@ export async function getDeploymentInfo(
|
||||
{ metadata: metadata },
|
||||
clientId,
|
||||
secretKey,
|
||||
);
|
||||
return info;
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// create constructor param input for PluginMap
|
||||
@@ -142,8 +139,8 @@ export async function getDeploymentInfo(
|
||||
|
||||
// get deployment info for all extensions
|
||||
const extensionDeploymentInfo = await Promise.all(
|
||||
extensionMetadata.map(async (metadata) => {
|
||||
const info = await computeDeploymentInfo(
|
||||
extensionMetadata.map((metadata) =>
|
||||
computeDeploymentInfo(
|
||||
"extension",
|
||||
provider,
|
||||
storage,
|
||||
@@ -151,9 +148,8 @@ export async function getDeploymentInfo(
|
||||
{ metadata: metadata },
|
||||
clientId,
|
||||
secretKey,
|
||||
);
|
||||
return info;
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// create constructor param input for BaseRouter
|
||||
@@ -179,29 +175,30 @@ export async function getDeploymentInfo(
|
||||
finalDeploymentInfo.push(...extensionDeploymentInfo);
|
||||
}
|
||||
|
||||
const implementationDeployInfo = await computeDeploymentInfo(
|
||||
"implementation",
|
||||
provider,
|
||||
storage,
|
||||
create2FactoryAddress,
|
||||
{
|
||||
metadata: compilerMetadata,
|
||||
constructorParams: customParams,
|
||||
},
|
||||
clientId,
|
||||
secretKey,
|
||||
);
|
||||
|
||||
// get clone factory
|
||||
const factoryInfo = await computeDeploymentInfo(
|
||||
"infra",
|
||||
provider,
|
||||
storage,
|
||||
create2FactoryAddress,
|
||||
{ contractName: "TWCloneFactory" },
|
||||
clientId,
|
||||
secretKey,
|
||||
);
|
||||
const [implementationDeployInfo, factoryInfo] = await Promise.all([
|
||||
computeDeploymentInfo(
|
||||
"implementation",
|
||||
provider,
|
||||
storage,
|
||||
create2FactoryAddress,
|
||||
{
|
||||
metadata: compilerMetadata,
|
||||
constructorParams: customParams,
|
||||
},
|
||||
clientId,
|
||||
secretKey,
|
||||
),
|
||||
// get clone factory
|
||||
computeDeploymentInfo(
|
||||
"infra",
|
||||
provider,
|
||||
storage,
|
||||
create2FactoryAddress,
|
||||
{ contractName: "TWCloneFactory" },
|
||||
clientId,
|
||||
secretKey,
|
||||
),
|
||||
]);
|
||||
|
||||
finalDeploymentInfo.push(factoryInfo);
|
||||
finalDeploymentInfo.push(...Object.values(caches.deploymentPresets));
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -46,8 +46,10 @@ export async function isTokenApprovedForTransfer(
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
const erc165 = new Contract(assetContract, ERC165Abi, provider) as IERC165;
|
||||
const isERC721 = await erc165.supportsInterface(InterfaceId_IERC721);
|
||||
const isERC1155 = await erc165.supportsInterface(InterfaceId_IERC1155);
|
||||
const [isERC721, isERC1155] = await Promise.all([
|
||||
erc165.supportsInterface(InterfaceId_IERC721),
|
||||
erc165.supportsInterface(InterfaceId_IERC1155),
|
||||
]);
|
||||
if (isERC721) {
|
||||
const asset = new Contract(assetContract, ERC721Abi, provider) as IERC721;
|
||||
|
||||
@@ -108,11 +110,9 @@ export async function handleTokenApproval(
|
||||
contractWrapper.options,
|
||||
contractWrapper.storage,
|
||||
);
|
||||
const isERC721 = await erc165.read("supportsInterface", [
|
||||
InterfaceId_IERC721,
|
||||
]);
|
||||
const isERC1155 = await erc165.read("supportsInterface", [
|
||||
InterfaceId_IERC1155,
|
||||
const [isERC721, isERC1155] = await Promise.all([
|
||||
erc165.read("supportsInterface", [InterfaceId_IERC721]),
|
||||
erc165.read("supportsInterface", [InterfaceId_IERC1155]),
|
||||
]);
|
||||
// check for token approval
|
||||
if (isERC721) {
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -100,11 +100,14 @@ export class DropClaimConditions<
|
||||
public async getActive(
|
||||
options?: ClaimConditionFetchOptions,
|
||||
): Promise<ClaimCondition> {
|
||||
const cc = await this.get();
|
||||
const metadata = await this.metadata.get();
|
||||
const [cc, metadata, tokenDecimals] = await Promise.all([
|
||||
this.get(),
|
||||
this.metadata.get(),
|
||||
this.getTokenDecimals(),
|
||||
]);
|
||||
return await transformResultToClaimCondition(
|
||||
cc,
|
||||
await this.getTokenDecimals(),
|
||||
tokenDecimals,
|
||||
this.contractWrapper.getProvider(),
|
||||
metadata.merkle || {},
|
||||
this.storage,
|
||||
@@ -236,12 +239,6 @@ export class DropClaimConditions<
|
||||
let activeConditionIndex: BigNumber;
|
||||
let claimCondition: ClaimCondition;
|
||||
|
||||
const decimals = await this.getTokenDecimals();
|
||||
const quantityWithDecimals = utils.parseUnits(
|
||||
AmountSchema.parse(quantity),
|
||||
decimals,
|
||||
);
|
||||
|
||||
if (addressToCheck === undefined) {
|
||||
try {
|
||||
addressToCheck = await this.contractWrapper.getSignerAddress();
|
||||
@@ -255,7 +252,15 @@ export class DropClaimConditions<
|
||||
return [ClaimEligibility.NoWallet];
|
||||
}
|
||||
|
||||
const resolvedAddress = await resolveAddress(addressToCheck);
|
||||
const [resolvedAddress, decimals] = await Promise.all([
|
||||
resolveAddress(addressToCheck),
|
||||
this.getTokenDecimals(),
|
||||
]);
|
||||
|
||||
const quantityWithDecimals = utils.parseUnits(
|
||||
AmountSchema.parse(quantity),
|
||||
decimals,
|
||||
);
|
||||
|
||||
try {
|
||||
claimCondition = await this.getActive();
|
||||
@@ -487,7 +492,7 @@ export class DropClaimConditions<
|
||||
}
|
||||
}
|
||||
|
||||
// if not within a browser conetext, check for wallet balance.
|
||||
// if not within a browser context, check for wallet balance.
|
||||
// In browser context, let the wallet do that job
|
||||
if (claimCondition.price.gt(0) && isNode()) {
|
||||
const totalPrice = claimCondition.price.mul(BigNumber.from(quantity));
|
||||
@@ -528,8 +533,10 @@ export class DropClaimConditions<
|
||||
const merkleRoot = claimCondition.merkleRoot;
|
||||
const merkleRootArray = utils.stripZeros(merkleRoot);
|
||||
if (merkleRootArray.length > 0) {
|
||||
const metadata = await this.metadata.get();
|
||||
const resolvedAddress = await resolveAddress(claimerAddress);
|
||||
const [metadata, resolvedAddress] = await Promise.all([
|
||||
this.metadata.get(),
|
||||
resolveAddress(claimerAddress),
|
||||
]);
|
||||
return await fetchSnapshotEntryForAddress(
|
||||
resolvedAddress,
|
||||
merkleRoot.toString(),
|
||||
@@ -820,13 +827,14 @@ export class DropClaimConditions<
|
||||
decimals = 0,
|
||||
address?: string,
|
||||
): Promise<ClaimVerification> {
|
||||
const addressToClaim = address
|
||||
? address
|
||||
: await this.contractWrapper.getSignerAddress();
|
||||
const [addressToClaim, activeClaimConditions] = await Promise.all([
|
||||
address ? address : this.contractWrapper.getSignerAddress(),
|
||||
this.getActive(),
|
||||
]);
|
||||
return prepareClaim(
|
||||
addressToClaim,
|
||||
quantity,
|
||||
await this.getActive(),
|
||||
activeClaimConditions,
|
||||
async () => (await this.metadata.get()).merkle,
|
||||
decimals,
|
||||
this.contractWrapper,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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())),
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -285,12 +285,11 @@ export class MarketplaceAuction {
|
||||
async (
|
||||
listings: NewAuctionListing[],
|
||||
): Promise<Transaction<TransactionResultWithId[]>> => {
|
||||
const data = await Promise.all(
|
||||
listings.map(async (listing) => {
|
||||
const tx = await this.createListing.prepare(listing);
|
||||
return tx.encode();
|
||||
}),
|
||||
);
|
||||
const data = (
|
||||
await Promise.all(
|
||||
listings.map((listing) => this.createListing.prepare(listing)),
|
||||
)
|
||||
).map((tx) => tx.encode());
|
||||
|
||||
return Transaction.fromContractWrapper({
|
||||
contractWrapper: this.contractWrapper,
|
||||
@@ -576,7 +575,7 @@ export class MarketplaceAuction {
|
||||
const [currentBidBufferBps, winningBid, listing] = await Promise.all([
|
||||
this.getBidBufferBps(),
|
||||
this.getWinningBid(listingId),
|
||||
await this.validateListing(BigNumber.from(listingId)),
|
||||
this.validateListing(BigNumber.from(listingId)),
|
||||
]);
|
||||
|
||||
const currentBidOrReservePrice = winningBid
|
||||
|
||||
@@ -239,12 +239,11 @@ export class MarketplaceDirect {
|
||||
async (
|
||||
listings: NewDirectListing[],
|
||||
): Promise<Transaction<TransactionResultWithId[]>> => {
|
||||
const data = await Promise.all(
|
||||
listings.map(async (listing) => {
|
||||
const tx = await this.createListing.prepare(listing);
|
||||
return tx.encode();
|
||||
}),
|
||||
);
|
||||
const data = (
|
||||
await Promise.all(
|
||||
listings.map((listing) => this.createListing.prepare(listing)),
|
||||
)
|
||||
).map((tx) => tx.encode());
|
||||
|
||||
return Transaction.fromContractWrapper({
|
||||
contractWrapper: this.contractWrapper,
|
||||
|
||||
@@ -414,12 +414,11 @@ export class MarketplaceV3DirectListings<TContract extends DirectListingsLogic>
|
||||
async (
|
||||
listings: DirectListingInputParams[],
|
||||
): Promise<Transaction<TransactionResultWithId[]>> => {
|
||||
const data = await Promise.all(
|
||||
listings.map(async (listing) => {
|
||||
const tx = await this.createListing.prepare(listing);
|
||||
return tx.encode();
|
||||
}),
|
||||
);
|
||||
const data = (
|
||||
await Promise.all(
|
||||
listings.map((listing) => this.createListing.prepare(listing)),
|
||||
)
|
||||
).map((tx) => tx.encode());
|
||||
|
||||
return Transaction.fromContractWrapper({
|
||||
contractWrapper: this
|
||||
|
||||
@@ -404,12 +404,11 @@ export class MarketplaceV3EnglishAuctions<
|
||||
async (
|
||||
listings: EnglishAuctionInputParams[],
|
||||
): Promise<Transaction<TransactionResultWithId[]>> => {
|
||||
const data = await Promise.all(
|
||||
listings.map(async (listing) => {
|
||||
const tx = await this.createAuction.prepare(listing);
|
||||
return tx.encode();
|
||||
}),
|
||||
);
|
||||
const data = (
|
||||
await Promise.all(
|
||||
listings.map((listing) => this.createAuction.prepare(listing)),
|
||||
)
|
||||
).map((tx) => tx.encode());
|
||||
|
||||
return Transaction.fromContractWrapper({
|
||||
contractWrapper: this
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user