thirdweb 5.81.0 → 5.82.0
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/dist/cjs/adapters/ethers5.js +1 -1
- package/dist/cjs/adapters/ethers5.js.map +1 -1
- package/dist/cjs/auth/verify-hash.js +13 -8
- package/dist/cjs/auth/verify-hash.js.map +1 -1
- package/dist/cjs/contract/types.js +3 -0
- package/dist/cjs/contract/types.js.map +1 -0
- package/dist/cjs/exports/thirdweb.js +5 -1
- package/dist/cjs/exports/thirdweb.js.map +1 -1
- package/dist/cjs/exports/transaction.js +3 -1
- package/dist/cjs/exports/transaction.js.map +1 -1
- package/dist/cjs/exports/wallets.js +3 -1
- package/dist/cjs/exports/wallets.js.map +1 -1
- package/dist/cjs/extensions/erc721/lazyMinting/read/getBatchesToReveal.js +1 -1
- package/dist/cjs/extensions/erc721/lazyMinting/read/getBatchesToReveal.js.map +1 -1
- package/dist/cjs/extensions/types.js +3 -0
- package/dist/cjs/extensions/types.js.map +1 -0
- package/dist/cjs/gas/estimate-l1-fee.js +3 -4
- package/dist/cjs/gas/estimate-l1-fee.js.map +1 -1
- package/dist/cjs/react/core/hooks/contract/useReadContract.js +31 -29
- package/dist/cjs/react/core/hooks/contract/useReadContract.js.map +1 -1
- package/dist/cjs/react/core/hooks/types.js +3 -0
- package/dist/cjs/react/core/hooks/types.js.map +1 -0
- package/dist/cjs/transaction/actions/eip7702/authorization.js +33 -0
- package/dist/cjs/transaction/actions/eip7702/authorization.js.map +1 -0
- package/dist/cjs/transaction/actions/estimate-gas.js +16 -4
- package/dist/cjs/transaction/actions/estimate-gas.js.map +1 -1
- package/dist/cjs/transaction/actions/send-transaction.js +32 -1
- package/dist/cjs/transaction/actions/send-transaction.js.map +1 -1
- package/dist/cjs/transaction/actions/to-serializable-transaction.js +13 -4
- package/dist/cjs/transaction/actions/to-serializable-transaction.js.map +1 -1
- package/dist/cjs/transaction/prepare-transaction.js.map +1 -1
- package/dist/cjs/transaction/serialize-transaction.js +11 -0
- package/dist/cjs/transaction/serialize-transaction.js.map +1 -1
- package/dist/cjs/utils/abi/decodeError.js +3 -3
- package/dist/cjs/utils/abi/decodeError.js.map +1 -1
- package/dist/cjs/utils/abi/decodeFunctionData.js +3 -3
- package/dist/cjs/utils/abi/decodeFunctionData.js.map +1 -1
- package/dist/cjs/utils/abi/decodeFunctionResult.js +3 -3
- package/dist/cjs/utils/abi/decodeFunctionResult.js.map +1 -1
- package/dist/cjs/utils/hashing/hashMessage.js +2 -2
- package/dist/cjs/utils/hashing/hashMessage.js.map +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/wallets/create-wallet.js +16 -0
- package/dist/cjs/wallets/create-wallet.js.map +1 -1
- package/dist/cjs/wallets/private-key.js +9 -0
- package/dist/cjs/wallets/private-key.js.map +1 -1
- package/dist/cjs/wallets/smart/index.js +20 -19
- package/dist/cjs/wallets/smart/index.js.map +1 -1
- package/dist/cjs/wallets/smart/lib/signing.js +139 -54
- package/dist/cjs/wallets/smart/lib/signing.js.map +1 -1
- package/dist/cjs/wallets/smart/presets/7579.js +11 -10
- package/dist/cjs/wallets/smart/presets/7579.js.map +1 -1
- package/dist/esm/adapters/ethers5.js +1 -1
- package/dist/esm/adapters/ethers5.js.map +1 -1
- package/dist/esm/auth/verify-hash.js +13 -9
- package/dist/esm/auth/verify-hash.js.map +1 -1
- package/dist/esm/contract/types.js +2 -0
- package/dist/esm/contract/types.js.map +1 -0
- package/dist/esm/exports/thirdweb.js +2 -0
- package/dist/esm/exports/thirdweb.js.map +1 -1
- package/dist/esm/exports/transaction.js +1 -0
- package/dist/esm/exports/transaction.js.map +1 -1
- package/dist/esm/exports/wallets.js +1 -0
- package/dist/esm/exports/wallets.js.map +1 -1
- package/dist/esm/extensions/erc721/lazyMinting/read/getBatchesToReveal.js +1 -1
- package/dist/esm/extensions/erc721/lazyMinting/read/getBatchesToReveal.js.map +1 -1
- package/dist/esm/extensions/types.js +2 -0
- package/dist/esm/extensions/types.js.map +1 -0
- package/dist/esm/gas/estimate-l1-fee.js +2 -3
- package/dist/esm/gas/estimate-l1-fee.js.map +1 -1
- package/dist/esm/react/core/hooks/contract/useReadContract.js +31 -29
- package/dist/esm/react/core/hooks/contract/useReadContract.js.map +1 -1
- package/dist/esm/react/core/hooks/types.js +2 -0
- package/dist/esm/react/core/hooks/types.js.map +1 -0
- package/dist/esm/transaction/actions/eip7702/authorization.js +30 -0
- package/dist/esm/transaction/actions/eip7702/authorization.js.map +1 -0
- package/dist/esm/transaction/actions/estimate-gas.js +16 -4
- package/dist/esm/transaction/actions/estimate-gas.js.map +1 -1
- package/dist/esm/transaction/actions/send-transaction.js +32 -1
- package/dist/esm/transaction/actions/send-transaction.js.map +1 -1
- package/dist/esm/transaction/actions/to-serializable-transaction.js +13 -4
- package/dist/esm/transaction/actions/to-serializable-transaction.js.map +1 -1
- package/dist/esm/transaction/prepare-transaction.js.map +1 -1
- package/dist/esm/transaction/serialize-transaction.js +11 -0
- package/dist/esm/transaction/serialize-transaction.js.map +1 -1
- package/dist/esm/utils/abi/decodeError.js +3 -3
- package/dist/esm/utils/abi/decodeError.js.map +1 -1
- package/dist/esm/utils/abi/decodeFunctionData.js +3 -3
- package/dist/esm/utils/abi/decodeFunctionData.js.map +1 -1
- package/dist/esm/utils/abi/decodeFunctionResult.js +3 -3
- package/dist/esm/utils/abi/decodeFunctionResult.js.map +1 -1
- package/dist/esm/utils/hashing/hashMessage.js +1 -1
- package/dist/esm/utils/hashing/hashMessage.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/wallets/create-wallet.js +16 -0
- package/dist/esm/wallets/create-wallet.js.map +1 -1
- package/dist/esm/wallets/private-key.js +9 -0
- package/dist/esm/wallets/private-key.js.map +1 -1
- package/dist/esm/wallets/smart/index.js +20 -19
- package/dist/esm/wallets/smart/index.js.map +1 -1
- package/dist/esm/wallets/smart/lib/signing.js +137 -53
- package/dist/esm/wallets/smart/lib/signing.js.map +1 -1
- package/dist/esm/wallets/smart/presets/7579.js +11 -10
- package/dist/esm/wallets/smart/presets/7579.js.map +1 -1
- package/dist/types/auth/verify-hash.d.ts +6 -0
- package/dist/types/auth/verify-hash.d.ts.map +1 -1
- package/dist/types/contract/types.d.ts +7 -0
- package/dist/types/contract/types.d.ts.map +1 -0
- package/dist/types/exports/thirdweb.d.ts +6 -0
- package/dist/types/exports/thirdweb.d.ts.map +1 -1
- package/dist/types/exports/transaction.d.ts +5 -0
- package/dist/types/exports/transaction.d.ts.map +1 -1
- package/dist/types/exports/wallets.d.ts +1 -0
- package/dist/types/exports/wallets.d.ts.map +1 -1
- package/dist/types/extensions/erc721/lazyMinting/read/getBatchesToReveal.d.ts +1 -1
- package/dist/types/extensions/erc721/lazyMinting/read/getBatchesToReveal.d.ts.map +1 -1
- package/dist/types/extensions/types.d.ts +4 -0
- package/dist/types/extensions/types.d.ts.map +1 -0
- package/dist/types/gas/estimate-l1-fee.d.ts.map +1 -1
- package/dist/types/react/core/hooks/contract/useReadContract.d.ts +9 -16
- package/dist/types/react/core/hooks/contract/useReadContract.d.ts.map +1 -1
- package/dist/types/react/core/hooks/types.d.ts +13 -0
- package/dist/types/react/core/hooks/types.d.ts.map +1 -0
- package/dist/types/transaction/actions/eip7702/authorization.d.ts +48 -0
- package/dist/types/transaction/actions/eip7702/authorization.d.ts.map +1 -0
- package/dist/types/transaction/actions/estimate-gas.d.ts +3 -1
- package/dist/types/transaction/actions/estimate-gas.d.ts.map +1 -1
- package/dist/types/transaction/actions/send-transaction.d.ts +31 -0
- package/dist/types/transaction/actions/send-transaction.d.ts.map +1 -1
- package/dist/types/transaction/actions/to-serializable-transaction.d.ts +19 -2
- package/dist/types/transaction/actions/to-serializable-transaction.d.ts.map +1 -1
- package/dist/types/transaction/prepare-transaction.d.ts +2 -0
- package/dist/types/transaction/prepare-transaction.d.ts.map +1 -1
- package/dist/types/transaction/serialize-transaction.d.ts +2 -0
- package/dist/types/transaction/serialize-transaction.d.ts.map +1 -1
- package/dist/types/utils/abi/decodeError.d.ts +2 -2
- package/dist/types/utils/abi/decodeError.d.ts.map +1 -1
- package/dist/types/utils/abi/decodeFunctionData.d.ts +6 -4
- package/dist/types/utils/abi/decodeFunctionData.d.ts.map +1 -1
- package/dist/types/utils/abi/decodeFunctionResult.d.ts +6 -4
- package/dist/types/utils/abi/decodeFunctionResult.d.ts.map +1 -1
- package/dist/types/utils/hashing/hashMessage.d.ts +1 -1
- package/dist/types/utils/hashing/hashMessage.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/wallets/create-wallet.d.ts +16 -0
- package/dist/types/wallets/create-wallet.d.ts.map +1 -1
- package/dist/types/wallets/interfaces/wallet.d.ts +9 -0
- package/dist/types/wallets/interfaces/wallet.d.ts.map +1 -1
- package/dist/types/wallets/private-key.d.ts.map +1 -1
- package/dist/types/wallets/smart/lib/signing.d.ts +46 -2
- package/dist/types/wallets/smart/lib/signing.d.ts.map +1 -1
- package/dist/types/wallets/smart/presets/7579.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/adapters/ethers5.ts +1 -1
- package/src/auth/verify-hash.ts +12 -9
- package/src/contract/types.ts +8 -0
- package/src/exports/thirdweb.ts +10 -0
- package/src/exports/transaction.ts +9 -0
- package/src/exports/wallets.ts +2 -0
- package/src/extensions/erc721/lazyMinting/read/getBatchesToReveal.ts +2 -2
- package/src/extensions/types.ts +6 -0
- package/src/gas/estimate-l1-fee.ts +2 -3
- package/src/react/core/hooks/contract/useReadContract.ts +83 -74
- package/src/react/core/hooks/types.ts +13 -0
- package/src/transaction/actions/eip7702/authorization.test.ts +27 -0
- package/src/transaction/actions/eip7702/authorization.ts +58 -0
- package/src/transaction/actions/estimate-gas.ts +26 -9
- package/src/transaction/actions/send-transaction.ts +32 -2
- package/src/transaction/actions/to-serializable-transaction.test.ts +68 -0
- package/src/transaction/actions/to-serializable-transaction.ts +42 -30
- package/src/transaction/prepare-transaction.test.ts +28 -0
- package/src/transaction/prepare-transaction.ts +3 -0
- package/src/transaction/serialize-transaction.test.ts +108 -1
- package/src/transaction/serialize-transaction.ts +18 -0
- package/src/utils/abi/decodeError.ts +5 -4
- package/src/utils/abi/decodeFunctionData.ts +7 -5
- package/src/utils/abi/decodeFunctionResult.ts +7 -5
- package/src/utils/hashing/hashMessage.ts +1 -1
- package/src/utils/signatures/sign-message.test.ts +2 -2
- package/src/version.ts +1 -1
- package/src/wallets/create-wallet.ts +16 -0
- package/src/wallets/interfaces/wallet.ts +15 -0
- package/src/wallets/private-key.test.ts +1 -0
- package/src/wallets/private-key.ts +10 -0
- package/src/wallets/smart/index.ts +20 -19
- package/src/wallets/smart/lib/signing.ts +154 -59
- package/src/wallets/smart/presets/7579.ts +13 -12
- package/src/wallets/smart/smart-wallet-integration-v07.test.ts +49 -9
- package/src/wallets/smart/smart-wallet-integration.test.ts +48 -1
@@ -3,6 +3,7 @@ import { getRpcClient } from "../../rpc/rpc.js";
|
|
3
3
|
import { getAddress } from "../../utils/address.js";
|
4
4
|
import { isZkSyncChain } from "../../utils/any-evm/zksync/isZkSyncChain.js";
|
5
5
|
import { resolvePromisedValue } from "../../utils/promise/resolve-promised-value.js";
|
6
|
+
import type { Account } from "../../wallets/interfaces/wallet.js";
|
6
7
|
import type { PreparedTransaction } from "../prepare-transaction.js";
|
7
8
|
import type { SerializableTransaction } from "../serialize-transaction.js";
|
8
9
|
import { encode } from "./encode.js";
|
@@ -15,9 +16,9 @@ export type ToSerializableTransactionOptions = {
|
|
15
16
|
// biome-ignore lint/suspicious/noExplicitAny: TODO: fix later
|
16
17
|
transaction: PreparedTransaction<any>;
|
17
18
|
/**
|
18
|
-
* The from address to use for gas estimation.
|
19
|
+
* The from address or account to use for gas estimation and authorization signing.
|
19
20
|
*/
|
20
|
-
from?: string;
|
21
|
+
from?: string | Account;
|
21
22
|
};
|
22
23
|
|
23
24
|
/**
|
@@ -55,7 +56,12 @@ export async function toSerializableTransaction(
|
|
55
56
|
);
|
56
57
|
const { gas, maxFeePerGas, maxPriorityFeePerGas } = await getZkGasFees({
|
57
58
|
transaction: options.transaction,
|
58
|
-
from:
|
59
|
+
from:
|
60
|
+
typeof options.from === "string" // Is this just an address?
|
61
|
+
? getAddress(options.from)
|
62
|
+
: options.from !== undefined // Is this an account?
|
63
|
+
? getAddress(options.from.address)
|
64
|
+
: undefined,
|
59
65
|
});
|
60
66
|
// passing these values here will avoid re-fetching them below
|
61
67
|
options.transaction = {
|
@@ -69,34 +75,39 @@ export async function toSerializableTransaction(
|
|
69
75
|
const rpcRequest = getRpcClient(options.transaction);
|
70
76
|
const chainId = options.transaction.chain.id;
|
71
77
|
const from = options.from;
|
72
|
-
let [data, nonce, gas, feeData, to, accessList, value] =
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
78
|
+
let [data, nonce, gas, feeData, to, accessList, value, authorizationList] =
|
79
|
+
await Promise.all([
|
80
|
+
encode(options.transaction),
|
81
|
+
(async () => {
|
82
|
+
// if the user has specified a nonce, use that
|
83
|
+
const resolvedNonce = await resolvePromisedValue(
|
84
|
+
options.transaction.nonce,
|
85
|
+
);
|
86
|
+
if (resolvedNonce !== undefined) {
|
87
|
+
return resolvedNonce;
|
88
|
+
}
|
82
89
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
90
|
+
return from // otherwise get the next nonce (import the method to do so)
|
91
|
+
? await import("../../rpc/actions/eth_getTransactionCount.js").then(
|
92
|
+
({ eth_getTransactionCount }) =>
|
93
|
+
eth_getTransactionCount(rpcRequest, {
|
94
|
+
address: typeof from === "string" ? from : from?.address,
|
95
|
+
blockTag: "pending",
|
96
|
+
}),
|
97
|
+
)
|
98
|
+
: undefined;
|
99
|
+
})(),
|
100
|
+
// takes the same options as the sendTransaction function thankfully!
|
101
|
+
estimateGas({
|
102
|
+
...options,
|
103
|
+
from: options.from,
|
104
|
+
}),
|
105
|
+
getGasOverridesForTransaction(options.transaction),
|
106
|
+
resolvePromisedValue(options.transaction.to),
|
107
|
+
resolvePromisedValue(options.transaction.accessList),
|
108
|
+
resolvePromisedValue(options.transaction.value),
|
109
|
+
resolvePromisedValue(options.transaction.authorizationList),
|
110
|
+
]);
|
100
111
|
|
101
112
|
const extraGas = await resolvePromisedValue(options.transaction.extraGas);
|
102
113
|
if (extraGas) {
|
@@ -111,6 +122,7 @@ export async function toSerializableTransaction(
|
|
111
122
|
nonce,
|
112
123
|
accessList,
|
113
124
|
value,
|
125
|
+
authorizationList,
|
114
126
|
...feeData,
|
115
127
|
} satisfies SerializableTransaction;
|
116
128
|
}
|
@@ -1,9 +1,13 @@
|
|
1
1
|
import { describe, expect, test as it } from "vitest";
|
2
|
+
import { TEST_ACCOUNT_B } from "~test/test-wallets.js";
|
2
3
|
import { TEST_WALLET_A, TEST_WALLET_B } from "../../test/src/addresses.js";
|
3
4
|
import { FORKED_ETHEREUM_CHAIN } from "../../test/src/chains.js";
|
4
5
|
import { TEST_CLIENT } from "../../test/src/test-clients.js";
|
6
|
+
import { defineChain } from "../chains/utils.js";
|
5
7
|
import { toWei } from "../utils/units.js";
|
8
|
+
import { signAuthorization } from "./actions/eip7702/authorization.js";
|
6
9
|
import { estimateGas } from "./actions/estimate-gas.js";
|
10
|
+
import { toSerializableTransaction } from "./actions/to-serializable-transaction.js";
|
7
11
|
import { prepareTransaction } from "./prepare-transaction.js";
|
8
12
|
|
9
13
|
describe.runIf(process.env.TW_SECRET_KEY)("prepareTransaction", () => {
|
@@ -18,6 +22,30 @@ describe.runIf(process.env.TW_SECRET_KEY)("prepareTransaction", () => {
|
|
18
22
|
expect(preparedTx.value).toMatchInlineSnapshot("100000000000000000n");
|
19
23
|
});
|
20
24
|
|
25
|
+
it("should accept an authorization list", async () => {
|
26
|
+
const authorization = await signAuthorization({
|
27
|
+
account: TEST_ACCOUNT_B,
|
28
|
+
request: {
|
29
|
+
address: TEST_WALLET_B,
|
30
|
+
chainId: 911867,
|
31
|
+
nonce: 0n,
|
32
|
+
},
|
33
|
+
});
|
34
|
+
const preparedTx = prepareTransaction({
|
35
|
+
chain: defineChain(911867),
|
36
|
+
client: TEST_CLIENT,
|
37
|
+
to: TEST_WALLET_B,
|
38
|
+
value: 0n,
|
39
|
+
authorizationList: [authorization],
|
40
|
+
});
|
41
|
+
|
42
|
+
const serializableTx = await toSerializableTransaction({
|
43
|
+
transaction: preparedTx,
|
44
|
+
});
|
45
|
+
|
46
|
+
expect(serializableTx.authorizationList).toEqual([authorization]);
|
47
|
+
});
|
48
|
+
|
21
49
|
// skip this test if there is no secret key available to test with
|
22
50
|
// TODO: remove reliance on secret key during unit tests entirely
|
23
51
|
it.runIf(process.env.TW_SECRET_KEY)(
|
@@ -5,6 +5,7 @@ import type { ThirdwebClient } from "../client/client.js";
|
|
5
5
|
import type { ThirdwebContract } from "../contract/contract.js";
|
6
6
|
import type { PreparedMethod } from "../utils/abi/prepare-method.js";
|
7
7
|
import type { PromisedObject } from "../utils/promise/resolve-promised-value.js";
|
8
|
+
import type { SignedAuthorization } from "./actions/eip7702/authorization.js";
|
8
9
|
|
9
10
|
export type StaticPrepareTransactionOptions = {
|
10
11
|
accessList?: AccessList | undefined;
|
@@ -18,6 +19,8 @@ export type StaticPrepareTransactionOptions = {
|
|
18
19
|
maxFeePerBlobGas?: bigint | undefined;
|
19
20
|
nonce?: number | undefined;
|
20
21
|
extraGas?: bigint | undefined;
|
22
|
+
// eip7702
|
23
|
+
authorizationList?: SignedAuthorization[] | undefined;
|
21
24
|
// zksync specific
|
22
25
|
eip712?: EIP712TransactionOptions | undefined;
|
23
26
|
// tw specific
|
@@ -1,13 +1,15 @@
|
|
1
1
|
import * as ox__Hex from "ox/Hex";
|
2
2
|
import * as ox__TransactionEnvelopeEip1559 from "ox/TransactionEnvelopeEip1559";
|
3
3
|
import * as ox__TransactionEnvelopeEip2930 from "ox/TransactionEnvelopeEip2930";
|
4
|
+
import * as ox__TransactionEnvelopeEip7702 from "ox/TransactionEnvelopeEip7702";
|
4
5
|
import * as ox__TransactionEnvelopeLegacy from "ox/TransactionEnvelopeLegacy";
|
5
|
-
import { describe, expect, test } from "vitest";
|
6
|
+
import { assertType, describe, expect, test } from "vitest";
|
6
7
|
|
7
8
|
import { type Address, checksumAddress } from "../utils/address.js";
|
8
9
|
import { fromGwei, toWei } from "../utils/units.js";
|
9
10
|
import { serializeTransaction } from "./serialize-transaction.js";
|
10
11
|
|
12
|
+
import { wagmiTokenContractConfig } from "../../test/src/abis/wagmiToken.js";
|
11
13
|
import { ANVIL_PKEY_A, TEST_ACCOUNT_B } from "../../test/src/test-wallets.js";
|
12
14
|
import { keccak256 } from "../utils/hashing/keccak256.js";
|
13
15
|
import { sign } from "../utils/signatures/sign.js";
|
@@ -530,6 +532,111 @@ describe("eip2930", () => {
|
|
530
532
|
});
|
531
533
|
});
|
532
534
|
|
535
|
+
describe("eip7702", () => {
|
536
|
+
const baseEip7702 = {
|
537
|
+
...BASE_TRANSACTION,
|
538
|
+
authorizationList: [
|
539
|
+
{
|
540
|
+
address: wagmiTokenContractConfig.address.toLowerCase() as Address,
|
541
|
+
chainId: 1,
|
542
|
+
nonce: 420n,
|
543
|
+
r: ox__Hex.toBigInt(
|
544
|
+
"0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe",
|
545
|
+
),
|
546
|
+
s: ox__Hex.toBigInt(
|
547
|
+
"0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe",
|
548
|
+
),
|
549
|
+
yParity: 0,
|
550
|
+
},
|
551
|
+
{
|
552
|
+
address: "0x0000000000000000000000000000000000000000",
|
553
|
+
chainId: 10,
|
554
|
+
nonce: 69n,
|
555
|
+
r: ox__Hex.toBigInt(
|
556
|
+
"0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe",
|
557
|
+
),
|
558
|
+
s: ox__Hex.toBigInt(
|
559
|
+
"0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe",
|
560
|
+
),
|
561
|
+
yParity: 1,
|
562
|
+
},
|
563
|
+
],
|
564
|
+
chainId: 1,
|
565
|
+
} as const;
|
566
|
+
|
567
|
+
test("default", () => {
|
568
|
+
const serialized = serializeTransaction({ transaction: baseEip7702 });
|
569
|
+
assertType<ox__TransactionEnvelopeEip7702.Serialized>(
|
570
|
+
serialized as `0x04${string}`,
|
571
|
+
);
|
572
|
+
expect(serialized).toMatchInlineSnapshot(
|
573
|
+
`"0x04f8e3018203118080809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0f8baf85c0194fba3912ca04dd458c843e2ee08967fc04f3579c28201a480a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fef85a0a9400000000000000000000000000000000000000004501a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe"`,
|
574
|
+
);
|
575
|
+
const tx = ox__TransactionEnvelopeEip7702.deserialize(
|
576
|
+
serialized as ox__TransactionEnvelopeEip7702.Serialized,
|
577
|
+
);
|
578
|
+
expect({
|
579
|
+
...tx,
|
580
|
+
to: tx.to ? checksumAddress(tx.to) : undefined,
|
581
|
+
}).toEqual({
|
582
|
+
...baseEip7702,
|
583
|
+
nonce: BigInt(baseEip7702.nonce),
|
584
|
+
type: "eip7702",
|
585
|
+
});
|
586
|
+
});
|
587
|
+
|
588
|
+
test("signature", () => {
|
589
|
+
expect(
|
590
|
+
serializeTransaction({
|
591
|
+
transaction: {
|
592
|
+
...baseEip7702,
|
593
|
+
r: "0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe",
|
594
|
+
s: "0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe",
|
595
|
+
yParity: 1,
|
596
|
+
},
|
597
|
+
}),
|
598
|
+
).toMatchInlineSnapshot(
|
599
|
+
`"0x04f90126018203118080809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0f8baf85c0194fba3912ca04dd458c843e2ee08967fc04f3579c28201a480a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fef85a0a9400000000000000000000000000000000000000004501a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe01a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe"`,
|
600
|
+
);
|
601
|
+
expect(
|
602
|
+
serializeTransaction({
|
603
|
+
transaction: {
|
604
|
+
...baseEip7702,
|
605
|
+
r: "0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe",
|
606
|
+
s: "0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe",
|
607
|
+
yParity: 0,
|
608
|
+
},
|
609
|
+
}),
|
610
|
+
).toMatchInlineSnapshot(
|
611
|
+
`"0x04f90126018203118080809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0f8baf85c0194fba3912ca04dd458c843e2ee08967fc04f3579c28201a480a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fef85a0a9400000000000000000000000000000000000000004501a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe80a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe"`,
|
612
|
+
);
|
613
|
+
expect(
|
614
|
+
serializeTransaction({
|
615
|
+
transaction: {
|
616
|
+
...baseEip7702,
|
617
|
+
r: "0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe",
|
618
|
+
s: "0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe",
|
619
|
+
v: 0n,
|
620
|
+
},
|
621
|
+
}),
|
622
|
+
).toMatchInlineSnapshot(
|
623
|
+
`"0x04f90126018203118080809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0f8baf85c0194fba3912ca04dd458c843e2ee08967fc04f3579c28201a480a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fef85a0a9400000000000000000000000000000000000000004501a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe80a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe"`,
|
624
|
+
);
|
625
|
+
expect(
|
626
|
+
serializeTransaction({
|
627
|
+
transaction: {
|
628
|
+
...baseEip7702,
|
629
|
+
r: "0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe",
|
630
|
+
s: "0x60fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe",
|
631
|
+
v: 1n,
|
632
|
+
},
|
633
|
+
}),
|
634
|
+
).toMatchInlineSnapshot(
|
635
|
+
`"0x04f90126018203118080809470997970c51812dc3a010c7d01b50e0d17dc79c8880de0b6b3a764000080c0f8baf85c0194fba3912ca04dd458c843e2ee08967fc04f3579c28201a480a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fef85a0a9400000000000000000000000000000000000000004501a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe01a060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fea060fdd29ff912ce880cd3edaf9f932dc61d3dae823ea77e0323f94adb9f6a72fe"`,
|
636
|
+
);
|
637
|
+
});
|
638
|
+
});
|
639
|
+
|
533
640
|
describe("legacy", () => {
|
534
641
|
const BASE_LEGACY_TRANSACTION = {
|
535
642
|
...BASE_TRANSACTION,
|
@@ -2,6 +2,7 @@ import * as ox__Hex from "ox/Hex";
|
|
2
2
|
import * as ox__Signature from "ox/Signature";
|
3
3
|
import * as ox__TransactionEnvelopeEip1559 from "ox/TransactionEnvelopeEip1559";
|
4
4
|
import * as ox__TransactionEnvelopeEip2930 from "ox/TransactionEnvelopeEip2930";
|
5
|
+
import * as ox__TransactionEnvelopeEip7702 from "ox/TransactionEnvelopeEip7702";
|
5
6
|
import * as ox__TransactionEnvelopeLegacy from "ox/TransactionEnvelopeLegacy";
|
6
7
|
import type { Hex } from "../utils/encoding/hex.js";
|
7
8
|
|
@@ -24,6 +25,9 @@ export type SerializableTransaction = {
|
|
24
25
|
value?: bigint | undefined;
|
25
26
|
gas?: bigint | undefined;
|
26
27
|
gasLimit?: bigint | undefined;
|
28
|
+
authorizationList?:
|
29
|
+
| ox__TransactionEnvelopeEip7702.TransactionEnvelopeEip7702["authorizationList"]
|
30
|
+
| undefined;
|
27
31
|
};
|
28
32
|
|
29
33
|
export type SerializeTransactionOptions = {
|
@@ -141,6 +145,16 @@ export function serializeTransaction(
|
|
141
145
|
});
|
142
146
|
}
|
143
147
|
|
148
|
+
if (type === "eip7702") {
|
149
|
+
const typedTransaction =
|
150
|
+
transaction as ox__TransactionEnvelopeEip7702.TransactionEnvelopeEip7702;
|
151
|
+
ox__TransactionEnvelopeEip7702.assert(typedTransaction);
|
152
|
+
|
153
|
+
return ox__TransactionEnvelopeEip7702.serialize(typedTransaction, {
|
154
|
+
signature,
|
155
|
+
});
|
156
|
+
}
|
157
|
+
|
144
158
|
throw new Error("Invalid transaction type");
|
145
159
|
}
|
146
160
|
|
@@ -154,6 +168,10 @@ function getTransactionEnvelopeType(
|
|
154
168
|
return transactionEnvelope.type;
|
155
169
|
}
|
156
170
|
|
171
|
+
if (typeof transactionEnvelope.authorizationList !== "undefined") {
|
172
|
+
return "eip7702";
|
173
|
+
}
|
174
|
+
|
157
175
|
if (
|
158
176
|
typeof transactionEnvelope.maxFeePerGas !== "undefined" ||
|
159
177
|
typeof transactionEnvelope.maxPriorityFeePerGas !== "undefined"
|
@@ -1,4 +1,5 @@
|
|
1
|
-
import
|
1
|
+
import type * as ox__Abi from "ox/Abi";
|
2
|
+
import * as ox__AbiError from "ox/AbiError";
|
2
3
|
import { resolveContractAbi } from "../../contract/actions/resolve-abi.js";
|
3
4
|
import type { ThirdwebContract } from "../../contract/contract.js";
|
4
5
|
import type { Hex } from "../encoding/hex.js";
|
@@ -17,7 +18,7 @@ import type { Hex } from "../encoding/hex.js";
|
|
17
18
|
*
|
18
19
|
* @utils
|
19
20
|
*/
|
20
|
-
export async function decodeError<abi extends
|
21
|
+
export async function decodeError<abi extends ox__Abi.Abi>(options: {
|
21
22
|
contract: ThirdwebContract<abi>;
|
22
23
|
data: Hex;
|
23
24
|
}) {
|
@@ -31,6 +32,6 @@ export async function decodeError<abi extends Abi.Abi>(options: {
|
|
31
32
|
`No ABI found for contract ${contract.address} on chain ${contract.chain.id}`,
|
32
33
|
);
|
33
34
|
}
|
34
|
-
const abiError =
|
35
|
-
return
|
35
|
+
const abiError = ox__AbiError.fromAbi(abi, data) as ox__AbiError.AbiError;
|
36
|
+
return ox__AbiError.decode(abiError, data);
|
36
37
|
}
|
@@ -1,4 +1,6 @@
|
|
1
|
-
import
|
1
|
+
import type * as ox__Abi from "ox/Abi";
|
2
|
+
import * as ox__AbiFunction from "ox/AbiFunction";
|
3
|
+
import type * as ox__Hex from "ox/Hex";
|
2
4
|
import { resolveContractAbi } from "../../contract/actions/resolve-abi.js";
|
3
5
|
import type { ThirdwebContract } from "../../contract/contract.js";
|
4
6
|
|
@@ -16,9 +18,9 @@ import type { ThirdwebContract } from "../../contract/contract.js";
|
|
16
18
|
*
|
17
19
|
* @utils
|
18
20
|
*/
|
19
|
-
export async function decodeFunctionData<abi extends
|
21
|
+
export async function decodeFunctionData<abi extends ox__Abi.Abi>(options: {
|
20
22
|
contract: ThirdwebContract<abi>;
|
21
|
-
data:
|
23
|
+
data: ox__Hex.Hex;
|
22
24
|
}) {
|
23
25
|
const { contract, data } = options;
|
24
26
|
let abi = contract?.abi;
|
@@ -30,6 +32,6 @@ export async function decodeFunctionData<abi extends Abi.Abi>(options: {
|
|
30
32
|
`No ABI found for contract ${contract.address} on chain ${contract.chain.id}`,
|
31
33
|
);
|
32
34
|
}
|
33
|
-
const abiFunction =
|
34
|
-
return
|
35
|
+
const abiFunction = ox__AbiFunction.fromAbi(abi, data);
|
36
|
+
return ox__AbiFunction.decodeData(abiFunction, data);
|
35
37
|
}
|
@@ -1,4 +1,6 @@
|
|
1
|
-
import
|
1
|
+
import type * as ox__Abi from "ox/Abi";
|
2
|
+
import * as ox__AbiFunction from "ox/AbiFunction";
|
3
|
+
import type * as ox__Hex from "ox/Hex";
|
2
4
|
import { resolveContractAbi } from "../../contract/actions/resolve-abi.js";
|
3
5
|
import type { ThirdwebContract } from "../../contract/contract.js";
|
4
6
|
|
@@ -16,9 +18,9 @@ import type { ThirdwebContract } from "../../contract/contract.js";
|
|
16
18
|
*
|
17
19
|
* @utils
|
18
20
|
*/
|
19
|
-
export async function decodeFunctionResult<abi extends
|
21
|
+
export async function decodeFunctionResult<abi extends ox__Abi.Abi>(options: {
|
20
22
|
contract: ThirdwebContract<abi>;
|
21
|
-
data:
|
23
|
+
data: ox__Hex.Hex;
|
22
24
|
}) {
|
23
25
|
const { contract, ...rest } = options;
|
24
26
|
let abi = contract?.abi;
|
@@ -30,6 +32,6 @@ export async function decodeFunctionResult<abi extends Abi.Abi>(options: {
|
|
30
32
|
`No ABI found for contract ${contract.address} on chain ${contract.chain.id}`,
|
31
33
|
);
|
32
34
|
}
|
33
|
-
const abiFunction =
|
34
|
-
return
|
35
|
+
const abiFunction = ox__AbiFunction.fromAbi(abi, rest.data);
|
36
|
+
return ox__AbiFunction.decodeResult(abiFunction, rest.data);
|
35
37
|
}
|
@@ -40,7 +40,7 @@ describe("signMessage", async () => {
|
|
40
40
|
privateKey: ANVIL_PKEY_A,
|
41
41
|
}),
|
42
42
|
).toMatchInlineSnapshot(
|
43
|
-
|
43
|
+
`"0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b"`,
|
44
44
|
);
|
45
45
|
|
46
46
|
expect(
|
@@ -53,7 +53,7 @@ describe("signMessage", async () => {
|
|
53
53
|
privateKey: ANVIL_PKEY_A,
|
54
54
|
}),
|
55
55
|
).toMatchInlineSnapshot(
|
56
|
-
|
56
|
+
`"0xa461f509887bd19e312c0c58467ce8ff8e300d3c1a90b608a760c5b80318eaf15fe57c96f9175d6cd4daad4663763baa7e78836e067d0163e9a2ccf2ff753f5b1b"`,
|
57
57
|
);
|
58
58
|
});
|
59
59
|
|
package/src/version.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export const version = "5.
|
1
|
+
export const version = "5.82.0";
|
@@ -116,6 +116,22 @@ import { createWalletEmitter } from "./wallet-emitter.js";
|
|
116
116
|
*
|
117
117
|
* [View Coinbase wallet creation options](https://portal.thirdweb.com/references/typescript/v5/CoinbaseWalletCreationOptions)
|
118
118
|
*
|
119
|
+
* ## Connecting with a smart wallet
|
120
|
+
*
|
121
|
+
* ```ts
|
122
|
+
* import { createWallet } from "thirdweb/wallets";
|
123
|
+
*
|
124
|
+
* const wallet = createWallet("smart", {
|
125
|
+
* chain: sepolia,
|
126
|
+
* sponsorGas: true,
|
127
|
+
* });
|
128
|
+
*
|
129
|
+
* const account = await wallet.connect({
|
130
|
+
* client,
|
131
|
+
* personalAccount, // pass the admin account
|
132
|
+
* });
|
133
|
+
* ```
|
134
|
+
*
|
119
135
|
* @wallet
|
120
136
|
*/
|
121
137
|
export function createWallet<const ID extends WalletId>(
|
@@ -2,6 +2,10 @@ import type { Address } from "abitype";
|
|
2
2
|
import type * as ox__TypedData from "ox/TypedData";
|
3
3
|
import type { Hex, SignableMessage } from "viem";
|
4
4
|
import type { Chain } from "../../chains/types.js";
|
5
|
+
import type {
|
6
|
+
AuthorizationRequest,
|
7
|
+
SignedAuthorization,
|
8
|
+
} from "../../transaction/actions/eip7702/authorization.js";
|
5
9
|
import type {
|
6
10
|
EIP712TransactionOptions,
|
7
11
|
PreparedTransaction,
|
@@ -195,6 +199,17 @@ export type Account = {
|
|
195
199
|
|
196
200
|
// OPTIONAL
|
197
201
|
|
202
|
+
/**
|
203
|
+
* Sign the given EIP-7702 authorization object.
|
204
|
+
* @example
|
205
|
+
* ```ts
|
206
|
+
* const signedAuthorization = await account.signAuthorization({ address: "0x...", chainId: 1, nonce: 1n });
|
207
|
+
* ```
|
208
|
+
*/
|
209
|
+
signAuthorization?: (
|
210
|
+
authorization: AuthorizationRequest,
|
211
|
+
) => Promise<SignedAuthorization>;
|
212
|
+
|
198
213
|
/**
|
199
214
|
* Estimate the gas required to execute the given transaction.
|
200
215
|
*
|
@@ -1,10 +1,13 @@
|
|
1
1
|
import { secp256k1 } from "@noble/curves/secp256k1";
|
2
|
+
import * as ox__Authorization from "ox/Authorization";
|
3
|
+
import * as ox__Secp256k1 from "ox/Secp256k1";
|
2
4
|
import type * as ox__TypedData from "ox/TypedData";
|
3
5
|
import { publicKeyToAddress } from "viem/utils";
|
4
6
|
import { getCachedChain } from "../chains/utils.js";
|
5
7
|
import type { ThirdwebClient } from "../client/client.js";
|
6
8
|
import { eth_sendRawTransaction } from "../rpc/actions/eth_sendRawTransaction.js";
|
7
9
|
import { getRpcClient } from "../rpc/rpc.js";
|
10
|
+
import type { AuthorizationRequest } from "../transaction/actions/eip7702/authorization.js";
|
8
11
|
import { signTransaction } from "../transaction/actions/sign-transaction.js";
|
9
12
|
import type { SerializableTransaction } from "../transaction/serialize-transaction.js";
|
10
13
|
import { type Hex, toHex } from "../utils/encoding/hex.js";
|
@@ -119,6 +122,13 @@ export function privateKeyToAccount(
|
|
119
122
|
privateKey,
|
120
123
|
});
|
121
124
|
},
|
125
|
+
signAuthorization: async (authorization: AuthorizationRequest) => {
|
126
|
+
const signature = ox__Secp256k1.sign({
|
127
|
+
payload: ox__Authorization.getSignPayload(authorization),
|
128
|
+
privateKey: privateKey,
|
129
|
+
});
|
130
|
+
return ox__Authorization.from(authorization, { signature });
|
131
|
+
},
|
122
132
|
};
|
123
133
|
|
124
134
|
return account satisfies Account;
|
@@ -210,7 +210,7 @@ async function createSmartAccount(
|
|
210
210
|
}
|
211
211
|
}
|
212
212
|
|
213
|
-
|
213
|
+
let accountContract = options.accountContract;
|
214
214
|
const account: Account = {
|
215
215
|
address: getAddress(accountContract.address),
|
216
216
|
async sendTransaction(transaction: SendTransactionOption) {
|
@@ -237,21 +237,17 @@ async function createSmartAccount(
|
|
237
237
|
paymasterOverride = options.overrides?.paymaster;
|
238
238
|
}
|
239
239
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
}
|
249
|
-
// Default to the existing account contract
|
250
|
-
return accountContract;
|
251
|
-
})();
|
240
|
+
// If this transaction is for a different chain than the initial one, get the account contract for that chain
|
241
|
+
if (transaction.chainId !== accountContract.chain.id) {
|
242
|
+
accountContract = getContract({
|
243
|
+
address: account.address,
|
244
|
+
chain: getCachedChain(transaction.chainId),
|
245
|
+
client: options.client,
|
246
|
+
});
|
247
|
+
}
|
252
248
|
|
253
249
|
const executeTx = prepareExecute({
|
254
|
-
accountContract:
|
250
|
+
accountContract: accountContract,
|
255
251
|
transaction,
|
256
252
|
executeOverride: options.overrides?.execute,
|
257
253
|
});
|
@@ -260,6 +256,7 @@ async function createSmartAccount(
|
|
260
256
|
options: {
|
261
257
|
...options,
|
262
258
|
chain: getCachedChain(transaction.chainId),
|
259
|
+
accountContract,
|
263
260
|
overrides: {
|
264
261
|
...options.overrides,
|
265
262
|
paymaster: paymasterOverride,
|
@@ -275,7 +272,11 @@ async function createSmartAccount(
|
|
275
272
|
});
|
276
273
|
return _sendUserOp({
|
277
274
|
executeTx,
|
278
|
-
options
|
275
|
+
options: {
|
276
|
+
...options,
|
277
|
+
chain: getCachedChain(transactions[0]?.chainId ?? options.chain.id),
|
278
|
+
accountContract,
|
279
|
+
},
|
279
280
|
});
|
280
281
|
},
|
281
282
|
async signMessage({ message }: { message: SignableMessage }) {
|
@@ -288,8 +289,8 @@ async function createSmartAccount(
|
|
288
289
|
});
|
289
290
|
}
|
290
291
|
|
291
|
-
const {
|
292
|
-
return
|
292
|
+
const { smartAccountSignMessage } = await import("./lib/signing.js");
|
293
|
+
return smartAccountSignMessage({
|
293
294
|
accountContract,
|
294
295
|
factoryContract: options.factoryContract,
|
295
296
|
options,
|
@@ -309,8 +310,8 @@ async function createSmartAccount(
|
|
309
310
|
});
|
310
311
|
}
|
311
312
|
|
312
|
-
const {
|
313
|
-
return
|
313
|
+
const { smartAccountSignTypedData } = await import("./lib/signing.js");
|
314
|
+
return smartAccountSignTypedData({
|
314
315
|
accountContract,
|
315
316
|
factoryContract: options.factoryContract,
|
316
317
|
options,
|