Skip to content

Commit 7cce978

Browse files
authored
Merge branch 'main' into neb-docs
2 parents b7fa3c2 + c86e13b commit 7cce978

File tree

75 files changed

+1870
-727
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+1870
-727
lines changed

.changeset/breezy-balloons-ring.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@thirdweb-dev/service-utils": patch
3+
---
4+
5+
[service-utils] Helper to call client usageV2 reporting endpoint

.changeset/dull-lamps-share.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Batch approvals and swaps if using smart wallets

.changeset/fresh-weeks-deliver.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@thirdweb-dev/service-utils": patch
3+
---
4+
5+
[service-utils] Omit team_id for client usageV2 events

.changeset/metal-crabs-beg.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@thirdweb-dev/service-utils": patch
3+
---
4+
5+
[service-utils] Allow client-side usageV2 reporting

apps/dashboard/src/@/components/blocks/FormFieldSetup.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { Label } from "@/components/ui/label";
22
import { ToolTipLabel } from "@/components/ui/tooltip";
33
import { AsteriskIcon, InfoIcon } from "lucide-react";
4+
import type React from "react";
45

56
export function FormFieldSetup(props: {
67
htmlFor?: string;
7-
label: string;
8+
label: React.ReactNode;
89
errorMessage: React.ReactNode | undefined;
910
children: React.ReactNode;
1011
tooltip?: React.ReactNode;

apps/dashboard/src/@3rdweb-sdk/react/cache-keys.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,6 @@ export const engineKeys = {
125125
[...engineKeys.all, engineId, "alerts"] as const,
126126
notificationChannels: (engineId: string) =>
127127
[...engineKeys.all, engineId, "notificationChannels"] as const,
128+
walletCredentials: (instance: string) =>
129+
[...engineKeys.all, instance, "walletCredentials"] as const,
128130
};

apps/dashboard/src/@3rdweb-sdk/react/hooks/useEngine.ts

Lines changed: 135 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ type EngineFeature =
9393
| "CONTRACT_SUBSCRIPTIONS"
9494
| "IP_ALLOWLIST"
9595
| "HETEROGENEOUS_WALLET_TYPES"
96-
| "SMART_BACKEND_WALLETS";
96+
| "SMART_BACKEND_WALLETS"
97+
| "WALLET_CREDENTIALS";
9798

9899
interface EngineSystemHealth {
99100
status: string;
@@ -860,6 +861,10 @@ export type SetWalletConfigInput =
860861
gcpKmsKeyRingId: string;
861862
gcpApplicationCredentialEmail: string;
862863
gcpApplicationCredentialPrivateKey: string;
864+
}
865+
| {
866+
type: "circle";
867+
circleApiKey: string;
863868
};
864869

865870
export function useEngineSetWalletConfig(params: {
@@ -869,8 +874,8 @@ export function useEngineSetWalletConfig(params: {
869874
const { instanceUrl, authToken } = params;
870875
const queryClient = useQueryClient();
871876

872-
return useMutation<WalletConfigResponse, void, SetWalletConfigInput>({
873-
mutationFn: async (input) => {
877+
return useMutation({
878+
mutationFn: async (input: SetWalletConfigInput) => {
874879
invariant(instanceUrl, "instance is required");
875880

876881
const res = await fetch(`${instanceUrl}configuration/wallets`, {
@@ -884,7 +889,7 @@ export function useEngineSetWalletConfig(params: {
884889
throw new Error(json.error.message);
885890
}
886891

887-
return json.result;
892+
return json.result as WalletConfigResponse;
888893
},
889894
onSuccess: () => {
890895
return queryClient.invalidateQueries({
@@ -894,10 +899,17 @@ export function useEngineSetWalletConfig(params: {
894899
});
895900
}
896901

897-
export type CreateBackendWalletInput = {
898-
type: EngineBackendWalletType;
899-
label?: string;
900-
};
902+
export type CreateBackendWalletInput =
903+
| {
904+
type: Exclude<EngineBackendWalletType, "circle" | "smart:circle">;
905+
label?: string;
906+
}
907+
| {
908+
type: "circle" | "smart:circle";
909+
label?: string;
910+
credentialId: string;
911+
isTestnet: boolean;
912+
};
901913

902914
export function useEngineCreateBackendWallet(params: {
903915
instanceUrl: string;
@@ -1851,3 +1863,118 @@ export function useEngineDeleteNotificationChannel(engineId: string) {
18511863
},
18521864
});
18531865
}
1866+
1867+
export interface WalletCredential {
1868+
id: string;
1869+
type: string;
1870+
label: string;
1871+
isDefault: boolean | null;
1872+
createdAt: string;
1873+
updatedAt: string;
1874+
}
1875+
1876+
interface CreateWalletCredentialInput {
1877+
type: "circle";
1878+
label: string;
1879+
entitySecret?: string;
1880+
isDefault?: boolean;
1881+
}
1882+
1883+
export function useEngineWalletCredentials(params: {
1884+
instanceUrl: string;
1885+
authToken: string;
1886+
page?: number;
1887+
limit?: number;
1888+
}) {
1889+
const { instanceUrl, authToken, page = 1, limit = 100 } = params;
1890+
1891+
return useQuery({
1892+
queryKey: [...engineKeys.walletCredentials(instanceUrl), page, limit],
1893+
queryFn: async () => {
1894+
const res = await fetch(
1895+
`${instanceUrl}wallet-credentials?page=${page}&limit=${limit}`,
1896+
{
1897+
method: "GET",
1898+
headers: getEngineRequestHeaders(authToken),
1899+
},
1900+
);
1901+
1902+
const json = await res.json();
1903+
return (json.result as WalletCredential[]) || [];
1904+
},
1905+
enabled: !!instanceUrl,
1906+
});
1907+
}
1908+
1909+
export function useEngineCreateWalletCredential(params: {
1910+
instanceUrl: string;
1911+
authToken: string;
1912+
}) {
1913+
const { instanceUrl, authToken } = params;
1914+
const queryClient = useQueryClient();
1915+
1916+
return useMutation({
1917+
mutationFn: async (input: CreateWalletCredentialInput) => {
1918+
invariant(instanceUrl, "instance is required");
1919+
1920+
const res = await fetch(`${instanceUrl}wallet-credentials`, {
1921+
method: "POST",
1922+
headers: getEngineRequestHeaders(authToken),
1923+
body: JSON.stringify(input),
1924+
});
1925+
const json = await res.json();
1926+
1927+
if (json.error) {
1928+
throw new Error(json.error.message);
1929+
}
1930+
1931+
return json.result as WalletCredential;
1932+
},
1933+
onSuccess: () => {
1934+
return queryClient.invalidateQueries({
1935+
queryKey: engineKeys.walletCredentials(instanceUrl),
1936+
});
1937+
},
1938+
});
1939+
}
1940+
1941+
interface UpdateWalletCredentialInput {
1942+
label?: string;
1943+
isDefault?: boolean;
1944+
entitySecret?: string;
1945+
}
1946+
1947+
export function useEngineUpdateWalletCredential(params: {
1948+
instanceUrl: string;
1949+
authToken: string;
1950+
}) {
1951+
const { instanceUrl, authToken } = params;
1952+
const queryClient = useQueryClient();
1953+
1954+
return useMutation({
1955+
mutationFn: async ({
1956+
id,
1957+
...input
1958+
}: UpdateWalletCredentialInput & { id: string }) => {
1959+
invariant(instanceUrl, "instance is required");
1960+
1961+
const res = await fetch(`${instanceUrl}wallet-credentials/${id}`, {
1962+
method: "PUT",
1963+
headers: getEngineRequestHeaders(authToken),
1964+
body: JSON.stringify(input),
1965+
});
1966+
const json = await res.json();
1967+
1968+
if (json.error) {
1969+
throw new Error(json.error.message);
1970+
}
1971+
1972+
return json.result as WalletCredential;
1973+
},
1974+
onSuccess: () => {
1975+
return queryClient.invalidateQueries({
1976+
queryKey: engineKeys.walletCredentials(instanceUrl),
1977+
});
1978+
},
1979+
});
1980+
}

apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/modules/components/getModuleInstalledParams.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { getThirdwebClient } from "@/constants/thirdweb.server";
2-
import { fetchPublishedContractVersions } from "components/contract-components/fetch-contracts-with-versions";
2+
import {
3+
fetchLatestPublishedContractVersion,
4+
fetchPublishedContractVersions,
5+
} from "components/contract-components/fetch-contracts-with-versions";
36
import { isAddress } from "thirdweb";
7+
import type { FetchDeployMetadataResult } from "thirdweb/contract";
48
import { resolveAddress } from "thirdweb/extensions/ens";
59
import invariant from "tiny-invariant";
610
import type { ModuleMeta } from "./install-module-params";
@@ -14,16 +18,24 @@ export async function getModuleInstalledParams(ext: ModuleMeta) {
1418
client: getThirdwebClient(),
1519
name: ext.publisherAddress,
1620
});
17-
const allPublishedModules = await fetchPublishedContractVersions(
18-
publisherAddress,
19-
ext.moduleName,
20-
);
2121

22-
// find the version we want
23-
const publishedModule =
24-
ext.moduleVersion === "latest"
25-
? allPublishedModules[0]
26-
: allPublishedModules.find((v) => v.version === ext.moduleVersion);
22+
let publishedModule: FetchDeployMetadataResult | undefined = undefined;
23+
24+
if (ext.moduleVersion === "latest") {
25+
publishedModule = await fetchLatestPublishedContractVersion(
26+
publisherAddress,
27+
ext.moduleName,
28+
);
29+
} else {
30+
const allPublishedModules = await fetchPublishedContractVersions(
31+
publisherAddress,
32+
ext.moduleName,
33+
);
34+
35+
publishedModule = allPublishedModules.find(
36+
(v) => v.version === ext.moduleVersion,
37+
);
38+
}
2739

2840
invariant(
2941
publishedModule,

apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/components/platform-fees.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,8 @@ export const SettingsPlatformFees = ({
132132
<SolidityInput
133133
solidityType="address"
134134
formContext={form}
135-
variant="filled"
136135
{...form.register("platform_fee_recipient")}
137-
isDisabled={!address || sendAndConfirmTx.isPending}
136+
disabled={!address || sendAndConfirmTx.isPending}
138137
/>
139138
<FormErrorMessage>
140139
{
@@ -155,15 +154,14 @@ export const SettingsPlatformFees = ({
155154
>
156155
<FormLabel>Percentage</FormLabel>
157156
<BasisPointsInput
158-
variant="filled"
159157
value={form.watch("platform_fee_basis_points")}
160158
onChange={(value) =>
161159
form.setValue("platform_fee_basis_points", value, {
162160
shouldDirty: true,
163161
shouldTouch: true,
164162
})
165163
}
166-
isDisabled={sendAndConfirmTx.isPending}
164+
disabled={sendAndConfirmTx.isPending}
167165
/>
168166
<FormErrorMessage>
169167
{

apps/dashboard/src/app/(dashboard)/(chain)/[chain_id]/[contractAddress]/settings/components/primary-sale.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,9 @@ export const SettingsPrimarySale = ({
128128
>
129129
<FormLabel>Recipient Address</FormLabel>
130130
<SolidityInput
131-
isDisabled={mutation.isPending || !address}
131+
disabled={mutation.isPending || !address}
132132
solidityType="address"
133133
formContext={form}
134-
variant="filled"
135134
{...form.register("primary_sale_recipient")}
136135
/>
137136
<FormErrorMessage>

0 commit comments

Comments
 (0)