thirdweb 5.88.8-nightly-1fa36c1d56758788a8f9053f8929497bacb2b115-20250225000329 → 5.89.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/dist/cjs/adapters/ethers5.js +2 -0
- package/dist/cjs/adapters/ethers5.js.map +1 -1
- package/dist/cjs/auth/verify-hash.js +2 -1
- package/dist/cjs/auth/verify-hash.js.map +1 -1
- package/dist/cjs/contract/actions/resolve-abi.js +9 -11
- package/dist/cjs/contract/actions/resolve-abi.js.map +1 -1
- package/dist/cjs/exports/extensions/erc721.js +4 -2
- package/dist/cjs/exports/extensions/erc721.js.map +1 -1
- package/dist/cjs/extensions/erc721/read/getNFT.js +30 -7
- package/dist/cjs/extensions/erc721/read/getNFT.js.map +1 -1
- package/dist/cjs/extensions/erc721/read/getNFTs.js.map +1 -1
- package/dist/cjs/gas/fee-data.js +25 -16
- package/dist/cjs/gas/fee-data.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/Modal/ConnectModalContent.js +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/Modal/ConnectModalContent.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/SignatureScreen.js +2 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/SignatureScreen.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/useConnectModal.js +3 -3
- package/dist/cjs/react/web/ui/ConnectWallet/useConnectModal.js.map +1 -1
- package/dist/cjs/react/web/ui/PayEmbed.js +5 -0
- package/dist/cjs/react/web/ui/PayEmbed.js.map +1 -1
- package/dist/cjs/transaction/actions/estimate-gas-cost.js +1 -1
- package/dist/cjs/transaction/actions/estimate-gas-cost.js.map +1 -1
- package/dist/cjs/transaction/actions/to-serializable-transaction.js +3 -1
- package/dist/cjs/transaction/actions/to-serializable-transaction.js.map +1 -1
- package/dist/cjs/transaction/prepare-transaction.js +8 -0
- package/dist/cjs/transaction/prepare-transaction.js.map +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/version.js.map +1 -1
- package/dist/cjs/wallets/smart/lib/calls.js +13 -7
- package/dist/cjs/wallets/smart/lib/calls.js.map +1 -1
- package/dist/cjs/wallets/smart/lib/userop.js +7 -4
- package/dist/cjs/wallets/smart/lib/userop.js.map +1 -1
- package/dist/esm/adapters/ethers5.js +2 -0
- package/dist/esm/adapters/ethers5.js.map +1 -1
- package/dist/esm/auth/verify-hash.js +2 -1
- package/dist/esm/auth/verify-hash.js.map +1 -1
- package/dist/esm/contract/actions/resolve-abi.js +9 -11
- package/dist/esm/contract/actions/resolve-abi.js.map +1 -1
- package/dist/esm/exports/extensions/erc721.js +1 -0
- package/dist/esm/exports/extensions/erc721.js.map +1 -1
- package/dist/esm/extensions/erc721/read/getNFT.js +30 -7
- package/dist/esm/extensions/erc721/read/getNFT.js.map +1 -1
- package/dist/esm/extensions/erc721/read/getNFTs.js.map +1 -1
- package/dist/esm/gas/fee-data.js +25 -16
- package/dist/esm/gas/fee-data.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/Modal/ConnectModalContent.js +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/Modal/ConnectModalContent.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/SignatureScreen.js +2 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/SignatureScreen.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/useConnectModal.js +3 -3
- package/dist/esm/react/web/ui/ConnectWallet/useConnectModal.js.map +1 -1
- package/dist/esm/react/web/ui/PayEmbed.js +5 -0
- package/dist/esm/react/web/ui/PayEmbed.js.map +1 -1
- package/dist/esm/transaction/actions/estimate-gas-cost.js +1 -1
- package/dist/esm/transaction/actions/estimate-gas-cost.js.map +1 -1
- package/dist/esm/transaction/actions/to-serializable-transaction.js +3 -1
- package/dist/esm/transaction/actions/to-serializable-transaction.js.map +1 -1
- package/dist/esm/transaction/prepare-transaction.js +7 -0
- package/dist/esm/transaction/prepare-transaction.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/esm/wallets/smart/lib/calls.js +13 -7
- package/dist/esm/wallets/smart/lib/calls.js.map +1 -1
- package/dist/esm/wallets/smart/lib/userop.js +7 -4
- package/dist/esm/wallets/smart/lib/userop.js.map +1 -1
- package/dist/types/adapters/ethers5.d.ts.map +1 -1
- package/dist/types/auth/verify-hash.d.ts.map +1 -1
- package/dist/types/chains/types.d.ts +2 -0
- package/dist/types/chains/types.d.ts.map +1 -1
- package/dist/types/contract/actions/resolve-abi.d.ts.map +1 -1
- package/dist/types/exports/extensions/erc721.d.ts +1 -0
- package/dist/types/exports/extensions/erc721.d.ts.map +1 -1
- package/dist/types/extensions/erc721/read/getNFT.d.ts +19 -0
- package/dist/types/extensions/erc721/read/getNFT.d.ts.map +1 -1
- package/dist/types/extensions/erc721/read/getNFTs.d.ts +7 -0
- package/dist/types/extensions/erc721/read/getNFTs.d.ts.map +1 -1
- package/dist/types/gas/fee-data.d.ts +6 -5
- package/dist/types/gas/fee-data.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/Modal/ConnectModalContent.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/screens/SignatureScreen.d.ts +1 -0
- package/dist/types/react/web/ui/ConnectWallet/screens/SignatureScreen.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/useConnectModal.d.ts +8 -0
- package/dist/types/react/web/ui/ConnectWallet/useConnectModal.d.ts.map +1 -1
- package/dist/types/react/web/ui/PayEmbed.d.ts +4 -0
- package/dist/types/react/web/ui/PayEmbed.d.ts.map +1 -1
- package/dist/types/transaction/actions/to-serializable-transaction.d.ts +2 -0
- package/dist/types/transaction/actions/to-serializable-transaction.d.ts.map +1 -1
- package/dist/types/transaction/prepare-transaction.d.ts +3 -0
- package/dist/types/transaction/prepare-transaction.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/version.d.ts.map +1 -1
- package/dist/types/wallets/smart/lib/calls.d.ts.map +1 -1
- package/dist/types/wallets/smart/lib/userop.d.ts +2 -0
- package/dist/types/wallets/smart/lib/userop.d.ts.map +1 -1
- package/package.json +27 -27
- package/src/adapters/ethers5.ts +5 -1
- package/src/auth/verify-hash.ts +2 -1
- package/src/auth/verify-typed-data.test.ts +4 -2
- package/src/chains/types.ts +3 -0
- package/src/contract/actions/resolve-abi.ts +27 -25
- package/src/exports/extensions/erc721.ts +1 -0
- package/src/extensions/erc721/read/getNFT.ts +37 -7
- package/src/extensions/erc721/read/getNFTs.ts +7 -0
- package/src/gas/fee-data.ts +35 -20
- package/src/react/web/ui/ConnectWallet/Modal/ConnectModalContent.tsx +1 -0
- package/src/react/web/ui/ConnectWallet/screens/Buy/fiat/currencies.test.tsx +1 -2
- package/src/react/web/ui/ConnectWallet/screens/SignatureScreen.tsx +3 -0
- package/src/react/web/ui/ConnectWallet/useConnectModal.tsx +11 -2
- package/src/react/web/ui/PayEmbed.tsx +11 -0
- package/src/transaction/actions/estimate-gas-cost.ts +1 -1
- package/src/transaction/actions/to-serializable-transaction.ts +46 -35
- package/src/transaction/prepare-transaction.ts +11 -0
- package/src/version.ts +1 -1
- package/src/wallets/smart/lib/calls.ts +18 -9
- package/src/wallets/smart/lib/userop.ts +11 -3
- package/src/wallets/smart/smart-wallet-integration-v07.test.ts +7 -4
- package/src/wallets/smart/smart-wallet-modular.test.ts +2 -1
@@ -6,6 +6,7 @@ import {
|
|
6
6
|
type TokenURIParams,
|
7
7
|
tokenURI,
|
8
8
|
} from "../__generated__/IERC721A/read/tokenURI.js";
|
9
|
+
import { tokenByIndex } from "../__generated__/IERC721Enumerable/read/tokenByIndex.js";
|
9
10
|
|
10
11
|
export { isTokenURISupported as isGetNFTSupported } from "../__generated__/IERC721A/read/tokenURI.js";
|
11
12
|
|
@@ -19,6 +20,13 @@ export type GetNFTParams = Prettify<
|
|
19
20
|
* Whether to include the owner of the NFT.
|
20
21
|
*/
|
21
22
|
includeOwner?: boolean;
|
23
|
+
/**
|
24
|
+
* Whether to check and fetch tokenID by index, in case of non-sequential IDs.
|
25
|
+
*
|
26
|
+
* It should be set to true if it's an ERC721Enumerable contract, and has `tokenByIndex` function.
|
27
|
+
* In this case, the provided tokenId will be considered as token-index and actual tokenId will be fetched from the contract.
|
28
|
+
*/
|
29
|
+
tokenByIndex?: boolean;
|
22
30
|
}
|
23
31
|
>;
|
24
32
|
|
@@ -35,15 +43,37 @@ export type GetNFTParams = Prettify<
|
|
35
43
|
* tokenId: 1n,
|
36
44
|
* });
|
37
45
|
* ```
|
46
|
+
*
|
47
|
+
* * @example
|
48
|
+
* ```ts
|
49
|
+
* import { getNFT } from "thirdweb/extensions/erc721";
|
50
|
+
*
|
51
|
+
*
|
52
|
+
* const nft = await getNFT({
|
53
|
+
* contract,
|
54
|
+
* tokenId: 1n,
|
55
|
+
* tokenByIndex: true // use this flag if the contract supports `tokenByIndex` and the above tokenId should be treated as an index.
|
56
|
+
* });
|
57
|
+
* ```
|
38
58
|
*/
|
39
59
|
export async function getNFT(
|
40
60
|
options: BaseTransactionOptions<GetNFTParams>,
|
41
61
|
): Promise<NFT> {
|
62
|
+
let tokenId = options.tokenId;
|
63
|
+
if (options.tokenByIndex) {
|
64
|
+
try {
|
65
|
+
tokenId = await tokenByIndex({
|
66
|
+
contract: options.contract,
|
67
|
+
index: options.tokenId,
|
68
|
+
});
|
69
|
+
} catch {}
|
70
|
+
}
|
71
|
+
|
42
72
|
const [uri, owner] = await Promise.all([
|
43
|
-
tokenURI(options).catch(() => null),
|
73
|
+
tokenURI({ contract: options.contract, tokenId }).catch(() => null),
|
44
74
|
options.includeOwner
|
45
75
|
? import("../__generated__/IERC721A/read/ownerOf.js")
|
46
|
-
.then((m) => m.ownerOf(options))
|
76
|
+
.then((m) => m.ownerOf({ contract: options.contract, tokenId }))
|
47
77
|
.catch(() => null)
|
48
78
|
: null,
|
49
79
|
]);
|
@@ -51,12 +81,12 @@ export async function getNFT(
|
|
51
81
|
if (!uri?.trim()) {
|
52
82
|
return parseNFT(
|
53
83
|
{
|
54
|
-
id:
|
84
|
+
id: tokenId,
|
55
85
|
type: "ERC721",
|
56
86
|
uri: "",
|
57
87
|
},
|
58
88
|
{
|
59
|
-
tokenId
|
89
|
+
tokenId,
|
60
90
|
tokenUri: "",
|
61
91
|
type: "ERC721",
|
62
92
|
owner,
|
@@ -67,15 +97,15 @@ export async function getNFT(
|
|
67
97
|
return parseNFT(
|
68
98
|
await fetchTokenMetadata({
|
69
99
|
client: options.contract.client,
|
70
|
-
tokenId
|
100
|
+
tokenId,
|
71
101
|
tokenUri: uri,
|
72
102
|
}).catch(() => ({
|
73
|
-
id:
|
103
|
+
id: tokenId,
|
74
104
|
type: "ERC721",
|
75
105
|
uri,
|
76
106
|
})),
|
77
107
|
{
|
78
|
-
tokenId:
|
108
|
+
tokenId: tokenId,
|
79
109
|
tokenUri: uri,
|
80
110
|
type: "ERC721",
|
81
111
|
owner,
|
@@ -34,6 +34,13 @@ export type GetNFTsParams = {
|
|
34
34
|
* @default false
|
35
35
|
*/
|
36
36
|
includeOwners?: boolean;
|
37
|
+
/**
|
38
|
+
* Whether to check and fetch tokenID by index, in case of non-sequential IDs.
|
39
|
+
*
|
40
|
+
* It should be set to true if it's an ERC721Enumerable contract, and has `tokenByIndex` function.
|
41
|
+
* In this case, the provided tokenId will be considered as token-index and actual tokenId will be fetched from the contract.
|
42
|
+
*/
|
43
|
+
tokenByIndex?: boolean;
|
37
44
|
};
|
38
45
|
|
39
46
|
/**
|
package/src/gas/fee-data.ts
CHANGED
@@ -40,6 +40,8 @@ const FORCE_GAS_PRICE_CHAIN_IDS = [
|
|
40
40
|
1942999413, // Humanity Testnet
|
41
41
|
1952959480, // Lumia Testnet
|
42
42
|
994873017, // Lumia Mainnet
|
43
|
+
19011, // Homeverse Mainnet
|
44
|
+
40875, // Homeverse Testnet
|
43
45
|
];
|
44
46
|
|
45
47
|
/**
|
@@ -50,11 +52,13 @@ export async function getGasOverridesForTransaction(
|
|
50
52
|
transaction: PreparedTransaction,
|
51
53
|
): Promise<FeeDataParams> {
|
52
54
|
// first check for explicit values
|
53
|
-
const [maxFeePerGas, maxPriorityFeePerGas, gasPrice] =
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
const [maxFeePerGas, maxPriorityFeePerGas, gasPrice, type] =
|
56
|
+
await Promise.all([
|
57
|
+
resolvePromisedValue(transaction.maxFeePerGas),
|
58
|
+
resolvePromisedValue(transaction.maxPriorityFeePerGas),
|
59
|
+
resolvePromisedValue(transaction.gasPrice),
|
60
|
+
resolvePromisedValue(transaction.type),
|
61
|
+
]);
|
58
62
|
|
59
63
|
// Exit early if the user explicitly provided enough options
|
60
64
|
if (maxFeePerGas !== undefined && maxPriorityFeePerGas !== undefined) {
|
@@ -63,6 +67,7 @@ export async function getGasOverridesForTransaction(
|
|
63
67
|
maxPriorityFeePerGas,
|
64
68
|
};
|
65
69
|
}
|
70
|
+
|
66
71
|
if (typeof gasPrice === "bigint") {
|
67
72
|
return { gasPrice };
|
68
73
|
}
|
@@ -71,6 +76,7 @@ export async function getGasOverridesForTransaction(
|
|
71
76
|
const defaultGasOverrides = await getDefaultGasOverrides(
|
72
77
|
transaction.client,
|
73
78
|
transaction.chain,
|
79
|
+
type === "legacy" ? "legacy" : "eip1559", // 7702, 2930, and eip1559 all qualify as "eip1559" fee type
|
74
80
|
);
|
75
81
|
|
76
82
|
if (transaction.chain.experimental?.increaseZeroByteCount) {
|
@@ -89,7 +95,7 @@ export async function getGasOverridesForTransaction(
|
|
89
95
|
}
|
90
96
|
|
91
97
|
// return as is
|
92
|
-
if (defaultGasOverrides.gasPrice) {
|
98
|
+
if (defaultGasOverrides.gasPrice !== undefined) {
|
93
99
|
return defaultGasOverrides;
|
94
100
|
}
|
95
101
|
|
@@ -101,6 +107,8 @@ export async function getGasOverridesForTransaction(
|
|
101
107
|
};
|
102
108
|
}
|
103
109
|
|
110
|
+
export type FeeType = "legacy" | "eip1559";
|
111
|
+
|
104
112
|
/**
|
105
113
|
* Retrieves the default gas overrides for a given client and chain ID.
|
106
114
|
* If the fee data contains both maxFeePerGas and maxPriorityFeePerGas, it returns an object with those values.
|
@@ -113,20 +121,27 @@ export async function getGasOverridesForTransaction(
|
|
113
121
|
export async function getDefaultGasOverrides(
|
114
122
|
client: ThirdwebClient,
|
115
123
|
chain: Chain,
|
124
|
+
feeType?: FeeType,
|
116
125
|
) {
|
117
|
-
//
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
126
|
+
// give priority to the transaction fee type over the chain fee type
|
127
|
+
const resolvedFeeType = feeType ?? chain.feeType;
|
128
|
+
// if chain is configured to force legacy transactions or is in the legacy chain list
|
129
|
+
if (
|
130
|
+
resolvedFeeType === "legacy" ||
|
131
|
+
FORCE_GAS_PRICE_CHAIN_IDS.includes(chain.id)
|
132
|
+
) {
|
133
|
+
return {
|
134
|
+
gasPrice: await getGasPrice({ client, chain, percentMultiplier: 10 }),
|
135
|
+
};
|
136
|
+
}
|
137
|
+
const feeData = await getDynamicFeeData(client, chain);
|
138
|
+
if (feeData.maxFeePerGas !== null && feeData.maxPriorityFeePerGas !== null) {
|
139
|
+
return {
|
140
|
+
maxFeePerGas: feeData.maxFeePerGas,
|
141
|
+
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
|
142
|
+
};
|
129
143
|
}
|
144
|
+
// TODO: resolvedFeeType here could be "EIP1559", but we could not get EIP1559 fee data. should we throw?
|
130
145
|
return {
|
131
146
|
gasPrice: await getGasPrice({ client, chain, percentMultiplier: 10 }),
|
132
147
|
};
|
@@ -154,7 +169,7 @@ async function getDynamicFeeData(
|
|
154
169
|
eth_maxPriorityFeePerGas(rpcRequest).catch(() => null),
|
155
170
|
]);
|
156
171
|
|
157
|
-
const baseBlockFee = block?.baseFeePerGas
|
172
|
+
const baseBlockFee = block?.baseFeePerGas;
|
158
173
|
|
159
174
|
const chainId = chain.id;
|
160
175
|
// flag chain testnet & flag chain
|
@@ -172,7 +187,7 @@ async function getDynamicFeeData(
|
|
172
187
|
maxPriorityFeePerGas_ = maxPriorityFeePerGas;
|
173
188
|
}
|
174
189
|
|
175
|
-
if (maxPriorityFeePerGas_ == null) {
|
190
|
+
if (maxPriorityFeePerGas_ == null || baseBlockFee == null) {
|
176
191
|
// chain does not support eip-1559, return null for both
|
177
192
|
return { maxFeePerGas: null, maxPriorityFeePerGas: null };
|
178
193
|
}
|
@@ -235,6 +235,7 @@ export const ConnectModalContent = (props: {
|
|
235
235
|
const signatureScreen = (
|
236
236
|
<SignatureScreen
|
237
237
|
onDone={onClose}
|
238
|
+
onClose={onClose}
|
238
239
|
modalSize={props.size}
|
239
240
|
termsOfServiceUrl={props.meta.termsOfServiceUrl}
|
240
241
|
privacyPolicyUrl={props.meta.privacyPolicyUrl}
|
@@ -8,7 +8,7 @@ import { currencies, getCurrencyMeta, usdCurrency } from "./currencies.js";
|
|
8
8
|
|
9
9
|
describe("Currency Utilities", () => {
|
10
10
|
it("should have correct number of currencies", () => {
|
11
|
-
expect(currencies.length).toBe(
|
11
|
+
expect(currencies.length).toBe(7);
|
12
12
|
});
|
13
13
|
|
14
14
|
it("should have USD as the first currency", () => {
|
@@ -19,7 +19,6 @@ describe("Currency Utilities", () => {
|
|
19
19
|
for (const currency of currencies) {
|
20
20
|
expect(currency).toHaveProperty("shorthand");
|
21
21
|
expect(currency).toHaveProperty("name");
|
22
|
-
expect(currency).toHaveProperty("icon");
|
23
22
|
}
|
24
23
|
});
|
25
24
|
|
@@ -32,6 +32,7 @@ type Status = "signing" | "failed" | "idle";
|
|
32
32
|
|
33
33
|
export const SignatureScreen: React.FC<{
|
34
34
|
onDone: (() => void) | undefined;
|
35
|
+
onClose?: (() => void) | undefined;
|
35
36
|
modalSize: "compact" | "wide";
|
36
37
|
termsOfServiceUrl?: string;
|
37
38
|
privacyPolicyUrl?: string;
|
@@ -42,6 +43,7 @@ export const SignatureScreen: React.FC<{
|
|
42
43
|
const {
|
43
44
|
onDone,
|
44
45
|
modalSize,
|
46
|
+
onClose,
|
45
47
|
termsOfServiceUrl,
|
46
48
|
privacyPolicyUrl,
|
47
49
|
connectLocale,
|
@@ -145,6 +147,7 @@ export const SignatureScreen: React.FC<{
|
|
145
147
|
variant="secondary"
|
146
148
|
data-testid="disconnect-button"
|
147
149
|
onClick={() => {
|
150
|
+
onClose?.();
|
148
151
|
disconnect(wallet);
|
149
152
|
}}
|
150
153
|
style={{
|
@@ -6,6 +6,7 @@ import type { Wallet } from "../../../../wallets/interfaces/wallet.js";
|
|
6
6
|
import type { SmartWalletOptions } from "../../../../wallets/smart/types.js";
|
7
7
|
import type { AppMetadata } from "../../../../wallets/types.js";
|
8
8
|
import type { Theme } from "../../../core/design-system/index.js";
|
9
|
+
import type { SiweAuthOptions } from "../../../core/hooks/auth/useSiweAuth.js";
|
9
10
|
import { SetRootElementContext } from "../../../core/providers/RootElementContext.js";
|
10
11
|
import { WalletUIStatesProvider } from "../../providers/wallet-ui-states-provider.js";
|
11
12
|
import { canFitWideModal } from "../../utils/canFitWideModal.js";
|
@@ -62,6 +63,7 @@ export function useConnectModal() {
|
|
62
63
|
<Modal
|
63
64
|
{...props}
|
64
65
|
onConnect={(w) => {
|
66
|
+
if (props.auth) return;
|
65
67
|
resolve(w);
|
66
68
|
cleanup();
|
67
69
|
}}
|
@@ -129,8 +131,7 @@ function Modal(
|
|
129
131
|
onClose={props.onClose}
|
130
132
|
shouldSetActive={props.setActive === undefined ? true : props.setActive}
|
131
133
|
accountAbstraction={props.accountAbstraction}
|
132
|
-
|
133
|
-
auth={undefined}
|
134
|
+
auth={props.auth}
|
134
135
|
chain={props.chain}
|
135
136
|
client={props.client}
|
136
137
|
connectLocale={props.connectLocale}
|
@@ -432,6 +433,14 @@ export type UseConnectModalOptions = {
|
|
432
433
|
* If you want to hide the branding, set this prop to `false`
|
433
434
|
*/
|
434
435
|
showThirdwebBranding?: boolean;
|
436
|
+
|
437
|
+
/**
|
438
|
+
* Enable SIWE (Sign in with Ethererum) by passing an object of type `SiweAuthOptions` to
|
439
|
+
* enforce the users to sign a message after connecting their wallet to authenticate themselves.
|
440
|
+
*
|
441
|
+
* Refer to the [`SiweAuthOptions`](https://portal.thirdweb.com/references/typescript/v5/SiweAuthOptions) for more details
|
442
|
+
*/
|
443
|
+
auth?: SiweAuthOptions;
|
435
444
|
};
|
436
445
|
|
437
446
|
// TODO: consilidate Button/Embed/Modal props into one type with extras
|
@@ -130,6 +130,11 @@ export type PayEmbedProps = {
|
|
130
130
|
*/
|
131
131
|
hiddenWallets?: WalletId[];
|
132
132
|
|
133
|
+
/**
|
134
|
+
* The wallet that should be pre-selected in the PayEmbed UI.
|
135
|
+
*/
|
136
|
+
activeWallet?: Wallet;
|
137
|
+
|
133
138
|
style?: React.CSSProperties;
|
134
139
|
|
135
140
|
className?: string;
|
@@ -308,6 +313,12 @@ export function PayEmbed(props: PayEmbedProps) {
|
|
308
313
|
}
|
309
314
|
}, [props.connectOptions?.chains, connectionManager]);
|
310
315
|
|
316
|
+
useEffect(() => {
|
317
|
+
if (props.activeWallet) {
|
318
|
+
connectionManager.setActiveWallet(props.activeWallet);
|
319
|
+
}
|
320
|
+
}, [props.activeWallet, connectionManager]);
|
321
|
+
|
311
322
|
let content = null;
|
312
323
|
const metadata =
|
313
324
|
props.payOptions && "metadata" in props.payOptions
|
@@ -38,7 +38,7 @@ export async function estimateGasCost(
|
|
38
38
|
transaction.chain,
|
39
39
|
);
|
40
40
|
const gasPrice = fees.maxFeePerGas || fees.gasPrice;
|
41
|
-
if (
|
41
|
+
if (gasPrice === undefined) {
|
42
42
|
throw new Error(
|
43
43
|
`Unable to determine gas price for chain ${transaction.chain.id}`,
|
44
44
|
);
|
@@ -75,42 +75,52 @@ export async function toSerializableTransaction(
|
|
75
75
|
const rpcRequest = getRpcClient(options.transaction);
|
76
76
|
const chainId = options.transaction.chain.id;
|
77
77
|
const from = options.from;
|
78
|
-
let [
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
78
|
+
let [
|
79
|
+
data,
|
80
|
+
nonce,
|
81
|
+
gas,
|
82
|
+
feeData,
|
83
|
+
to,
|
84
|
+
accessList,
|
85
|
+
value,
|
86
|
+
authorizationList,
|
87
|
+
type,
|
88
|
+
] = await Promise.all([
|
89
|
+
encode(options.transaction),
|
90
|
+
(async () => {
|
91
|
+
// if the user has specified a nonce, use that
|
92
|
+
const resolvedNonce = await resolvePromisedValue(
|
93
|
+
options.transaction.nonce,
|
94
|
+
);
|
95
|
+
if (resolvedNonce !== undefined) {
|
96
|
+
return resolvedNonce;
|
97
|
+
}
|
89
98
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
99
|
+
return from // otherwise get the next nonce (import the method to do so)
|
100
|
+
? await import("../../rpc/actions/eth_getTransactionCount.js").then(
|
101
|
+
({ eth_getTransactionCount }) =>
|
102
|
+
eth_getTransactionCount(rpcRequest, {
|
103
|
+
address:
|
104
|
+
typeof from === "string"
|
105
|
+
? getAddress(from)
|
106
|
+
: getAddress(from.address),
|
107
|
+
blockTag: "pending",
|
108
|
+
}),
|
109
|
+
)
|
110
|
+
: undefined;
|
111
|
+
})(),
|
112
|
+
// takes the same options as the sendTransaction function thankfully!
|
113
|
+
estimateGas({
|
114
|
+
...options,
|
115
|
+
from: options.from,
|
116
|
+
}),
|
117
|
+
getGasOverridesForTransaction(options.transaction),
|
118
|
+
resolvePromisedValue(options.transaction.to),
|
119
|
+
resolvePromisedValue(options.transaction.accessList),
|
120
|
+
resolvePromisedValue(options.transaction.value),
|
121
|
+
resolvePromisedValue(options.transaction.authorizationList),
|
122
|
+
resolvePromisedValue(options.transaction.type),
|
123
|
+
]);
|
114
124
|
|
115
125
|
const extraGas = await resolvePromisedValue(options.transaction.extraGas);
|
116
126
|
if (extraGas) {
|
@@ -126,6 +136,7 @@ export async function toSerializableTransaction(
|
|
126
136
|
accessList,
|
127
137
|
value,
|
128
138
|
authorizationList,
|
139
|
+
type,
|
129
140
|
...feeData,
|
130
141
|
} satisfies SerializableTransaction;
|
131
142
|
}
|
@@ -17,6 +17,7 @@ export type StaticPrepareTransactionOptions = {
|
|
17
17
|
maxFeePerGas?: bigint | undefined;
|
18
18
|
maxPriorityFeePerGas?: bigint | undefined;
|
19
19
|
maxFeePerBlobGas?: bigint | undefined;
|
20
|
+
type?: undefined | TransactionType;
|
20
21
|
nonce?: number | undefined;
|
21
22
|
extraGas?: bigint | undefined;
|
22
23
|
// eip7702
|
@@ -34,6 +35,16 @@ export type StaticPrepareTransactionOptions = {
|
|
34
35
|
};
|
35
36
|
};
|
36
37
|
|
38
|
+
type TransactionType = "legacy" | "eip1559" | "eip2930" | "eip4844" | "eip7702";
|
39
|
+
|
40
|
+
export const TransactionTypeMap: Record<TransactionType, number> = {
|
41
|
+
legacy: 0,
|
42
|
+
eip1559: 1,
|
43
|
+
eip2930: 2,
|
44
|
+
eip4844: 3,
|
45
|
+
eip7702: 4,
|
46
|
+
};
|
47
|
+
|
37
48
|
export type EIP712TransactionOptions = {
|
38
49
|
// constant or user input
|
39
50
|
gasPerPubdata?: bigint | undefined;
|
package/src/version.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export const version = "5.
|
1
|
+
export const version = "5.89.1";
|
@@ -8,6 +8,7 @@ import { prepareContractCall } from "../../../transaction/prepare-contract-call.
|
|
8
8
|
import type { PreparedTransaction } from "../../../transaction/prepare-transaction.js";
|
9
9
|
import { readContract } from "../../../transaction/read-contract.js";
|
10
10
|
import { isHex, stringToHex } from "../../../utils/encoding/hex.js";
|
11
|
+
import { withCache } from "../../../utils/promise/withCache.js";
|
11
12
|
import type { SendTransactionOption } from "../../interfaces/wallet.js";
|
12
13
|
import { DEFAULT_ACCOUNT_FACTORY_V0_6 } from "./constants.js";
|
13
14
|
|
@@ -90,15 +91,23 @@ export async function predictAddress(args: {
|
|
90
91
|
"Account address is required to predict the smart wallet address.",
|
91
92
|
);
|
92
93
|
}
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
94
|
+
return withCache(
|
95
|
+
async () => {
|
96
|
+
const saltHex =
|
97
|
+
accountSalt && isHex(accountSalt)
|
98
|
+
? accountSalt
|
99
|
+
: stringToHex(accountSalt ?? "");
|
100
|
+
return readContract({
|
101
|
+
contract: factoryContract,
|
102
|
+
method: "function getAddress(address, bytes) returns (address)",
|
103
|
+
params: [adminAddress, saltHex],
|
104
|
+
});
|
105
|
+
},
|
106
|
+
{
|
107
|
+
cacheKey: `${args.factoryContract.chain.id}-${args.factoryContract.address}-${args.adminAddress}-${args.accountSalt}`,
|
108
|
+
cacheTime: 1000 * 60 * 60 * 24, // 1 day
|
109
|
+
},
|
110
|
+
);
|
102
111
|
}
|
103
112
|
|
104
113
|
/**
|
@@ -136,6 +136,7 @@ export async function createUnsignedUserOp(args: {
|
|
136
136
|
adminAddress: string;
|
137
137
|
sponsorGas: boolean;
|
138
138
|
waitForDeployment?: boolean;
|
139
|
+
isDeployedOverride?: boolean;
|
139
140
|
overrides?: SmartWalletOptions["overrides"];
|
140
141
|
}): Promise<UserOperationV06 | UserOperationV07> {
|
141
142
|
const {
|
@@ -146,6 +147,7 @@ export async function createUnsignedUserOp(args: {
|
|
146
147
|
overrides,
|
147
148
|
sponsorGas,
|
148
149
|
waitForDeployment = true,
|
150
|
+
isDeployedOverride,
|
149
151
|
} = args;
|
150
152
|
const chain = executeTx.chain;
|
151
153
|
const client = executeTx.client;
|
@@ -163,7 +165,11 @@ export async function createUnsignedUserOp(args: {
|
|
163
165
|
|
164
166
|
const [isDeployed, callData, callGasLimit, gasFees, nonce] =
|
165
167
|
await Promise.all([
|
166
|
-
|
168
|
+
typeof isDeployedOverride === "boolean"
|
169
|
+
? isDeployedOverride
|
170
|
+
: isContractDeployed(accountContract).then(
|
171
|
+
(isDeployed) => isDeployed || isAccountDeploying(accountContract),
|
172
|
+
),
|
167
173
|
encode(executeTx),
|
168
174
|
resolvePromisedValue(executeTx.gas),
|
169
175
|
getGasFees({
|
@@ -299,7 +305,7 @@ async function populateUserOp_v0_7(args: {
|
|
299
305
|
|
300
306
|
let factory: string | undefined;
|
301
307
|
let factoryData: Hex;
|
302
|
-
if (isDeployed
|
308
|
+
if (isDeployed) {
|
303
309
|
factoryData = "0x";
|
304
310
|
if (waitForDeployment) {
|
305
311
|
// lock until account is deployed if needed to avoid 'sender already created' errors when sending multiple transactions in parallel
|
@@ -462,7 +468,7 @@ async function populateUserOp_v0_6(args: {
|
|
462
468
|
const { chain, client } = bundlerOptions;
|
463
469
|
let initCode: Hex;
|
464
470
|
|
465
|
-
if (isDeployed
|
471
|
+
if (isDeployed) {
|
466
472
|
initCode = "0x";
|
467
473
|
if (waitForDeployment) {
|
468
474
|
// lock until account is deployed if needed to avoid 'sender already created' errors when sending multiple transactions in parallel
|
@@ -699,6 +705,7 @@ export async function createAndSignUserOp(options: {
|
|
699
705
|
client: ThirdwebClient;
|
700
706
|
smartWalletOptions: SmartWalletOptions;
|
701
707
|
waitForDeployment?: boolean;
|
708
|
+
isDeployedOverride?: boolean;
|
702
709
|
}) {
|
703
710
|
const config = options.smartWalletOptions;
|
704
711
|
const factoryContract = getContract({
|
@@ -757,6 +764,7 @@ export async function createAndSignUserOp(options: {
|
|
757
764
|
sponsorGas: "sponsorGas" in config ? config.sponsorGas : config.gasless,
|
758
765
|
overrides: config.overrides,
|
759
766
|
waitForDeployment: options.waitForDeployment,
|
767
|
+
isDeployedOverride: options.isDeployedOverride,
|
760
768
|
});
|
761
769
|
const signedUserOp = await signUserOp({
|
762
770
|
client: options.client,
|
@@ -49,7 +49,8 @@ const contract = getContract({
|
|
49
49
|
address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8",
|
50
50
|
});
|
51
51
|
|
52
|
-
|
52
|
+
// FIXME: SKIP ALL OF THIS IT IS FLAKY
|
53
|
+
describe.skip(
|
53
54
|
"SmartWallet 0.7 core tests",
|
54
55
|
{
|
55
56
|
retry: 0,
|
@@ -102,14 +103,15 @@ describe.runIf(process.env.TW_SECRET_KEY)(
|
|
102
103
|
expect(isValid).toEqual(true);
|
103
104
|
});
|
104
105
|
|
105
|
-
|
106
|
+
// FIXME: flaky test - skipped
|
107
|
+
it.skip("should use ERC-1271 signatures after deployment", async () => {
|
106
108
|
await deploySmartAccount({
|
107
109
|
chain,
|
108
110
|
client,
|
109
111
|
smartAccount,
|
110
112
|
accountContract,
|
111
113
|
});
|
112
|
-
await new Promise((resolve) => setTimeout(resolve,
|
114
|
+
await new Promise((resolve) => setTimeout(resolve, 3000)); // pause for a second to prevent race condition
|
113
115
|
|
114
116
|
const signature = await smartAccount.signMessage({
|
115
117
|
message: "hello world",
|
@@ -135,7 +137,8 @@ describe.runIf(process.env.TW_SECRET_KEY)(
|
|
135
137
|
expect(isValid).toEqual(true);
|
136
138
|
});
|
137
139
|
|
138
|
-
|
140
|
+
// FIXME: flaky test - skipped
|
141
|
+
it.skip("should use ERC-1271 typed data signatures after deployment", async () => {
|
139
142
|
await deploySmartAccount({
|
140
143
|
chain,
|
141
144
|
client,
|
@@ -28,7 +28,8 @@ const client = TEST_CLIENT;
|
|
28
28
|
const DEFAULT_FACTORY_ADDRESS = "0xB1846E893CA01c5Dcdaa40371C1e13f2e0Df5717";
|
29
29
|
const DEFAULT_VALIDATOR_ADDRESS = "0x7D3631d823e0De311DC86f580946EeF2eEC81fba";
|
30
30
|
|
31
|
-
|
31
|
+
// FIXME: This test is flaky and needs to be fixed
|
32
|
+
describe.skip.sequential(
|
32
33
|
"SmartWallet modular tests",
|
33
34
|
{
|
34
35
|
retry: 0,
|