@openzeppelin/ui-renderer 1.2.0 → 2.0.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/README.md +69 -28
- package/dist/index.cjs +125 -103
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -23
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +16 -23
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +125 -103
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -178,8 +178,8 @@ const ExecutionConfigCard = ({ config }) => {
|
|
|
178
178
|
//#region src/components/ExecutionConfigDisplay/components/RelayerConfigDetails.tsx
|
|
179
179
|
const RelayerConfigDetails = ({ config, enhancedDetails, loading = false }) => {
|
|
180
180
|
const { relayer } = config;
|
|
181
|
-
const {
|
|
182
|
-
const labels =
|
|
181
|
+
const { activeRuntime } = useWalletState();
|
|
182
|
+
const labels = activeRuntime?.uiLabels.getUiLabels();
|
|
183
183
|
return /* @__PURE__ */ jsxs("div", {
|
|
184
184
|
className: "space-y-4",
|
|
185
185
|
children: [
|
|
@@ -216,18 +216,18 @@ const RelayerConfigDetails = ({ config, enhancedDetails, loading = false }) => {
|
|
|
216
216
|
|
|
217
217
|
//#endregion
|
|
218
218
|
//#region src/components/ExecutionConfigDisplay/hooks/useExecutionValidation.ts
|
|
219
|
-
const useExecutionValidation = ({ executionConfig,
|
|
219
|
+
const useExecutionValidation = ({ executionConfig, execution, runtimeApiKey }) => {
|
|
220
220
|
const [validationResult, setValidationResult] = useState({ isValid: true });
|
|
221
221
|
const validateConfig = useCallback(async () => {
|
|
222
|
-
if (!
|
|
222
|
+
if (!execution) {
|
|
223
223
|
setValidationResult({
|
|
224
224
|
isValid: false,
|
|
225
|
-
error: "No
|
|
225
|
+
error: "No execution capability available for validation"
|
|
226
226
|
});
|
|
227
227
|
return;
|
|
228
228
|
}
|
|
229
229
|
try {
|
|
230
|
-
const result = await
|
|
230
|
+
const result = await execution.validateExecutionConfig(executionConfig);
|
|
231
231
|
if (result === true) {
|
|
232
232
|
let runtimeError;
|
|
233
233
|
if (executionConfig.method === "relayer" && (!runtimeApiKey || runtimeApiKey.trim() === "")) runtimeError = "Relayer API key is required for transaction execution";
|
|
@@ -246,8 +246,8 @@ const useExecutionValidation = ({ executionConfig, adapter, runtimeApiKey }) =>
|
|
|
246
246
|
});
|
|
247
247
|
}
|
|
248
248
|
}, [
|
|
249
|
+
execution,
|
|
249
250
|
executionConfig,
|
|
250
|
-
adapter,
|
|
251
251
|
runtimeApiKey
|
|
252
252
|
]);
|
|
253
253
|
useEffect(() => {
|
|
@@ -258,7 +258,7 @@ const useExecutionValidation = ({ executionConfig, adapter, runtimeApiKey }) =>
|
|
|
258
258
|
|
|
259
259
|
//#endregion
|
|
260
260
|
//#region src/components/ExecutionConfigDisplay/ExecutionConfigDisplay.tsx
|
|
261
|
-
const ExecutionConfigDisplay = ({ executionConfig,
|
|
261
|
+
const ExecutionConfigDisplay = ({ executionConfig, execution, relayer, error, onRuntimeApiKeyChange }) => {
|
|
262
262
|
const { control, watch } = useForm({ defaultValues: { runtimeApiKey: "" } });
|
|
263
263
|
const runtimeApiKey = watch("runtimeApiKey");
|
|
264
264
|
const [isOpen, setIsOpen] = useState(false);
|
|
@@ -266,17 +266,17 @@ const ExecutionConfigDisplay = ({ executionConfig, adapter, error, onRuntimeApiK
|
|
|
266
266
|
const [relayerDetailsLoading, setRelayerDetailsLoading] = useState(false);
|
|
267
267
|
const { isValid, error: validationError } = useExecutionValidation({
|
|
268
268
|
executionConfig,
|
|
269
|
-
|
|
269
|
+
execution,
|
|
270
270
|
runtimeApiKey
|
|
271
271
|
});
|
|
272
272
|
useEffect(() => {
|
|
273
273
|
onRuntimeApiKeyChange?.(runtimeApiKey);
|
|
274
274
|
}, [runtimeApiKey, onRuntimeApiKeyChange]);
|
|
275
275
|
useEffect(() => {
|
|
276
|
-
if (isOpen && executionConfig.method === "relayer" && runtimeApiKey &&
|
|
276
|
+
if (isOpen && executionConfig.method === "relayer" && runtimeApiKey && relayer?.getRelayer) {
|
|
277
277
|
const relayerConfig = executionConfig;
|
|
278
278
|
setRelayerDetailsLoading(true);
|
|
279
|
-
|
|
279
|
+
relayer.getRelayer(relayerConfig.serviceUrl, runtimeApiKey, relayerConfig.relayer.relayerId).then((details) => {
|
|
280
280
|
setEnhancedRelayerDetails(details);
|
|
281
281
|
}).catch((err) => {
|
|
282
282
|
logger.error("ExecutionConfigDisplay", "Failed to fetch enhanced relayer details:", err);
|
|
@@ -286,10 +286,10 @@ const ExecutionConfigDisplay = ({ executionConfig, adapter, error, onRuntimeApiK
|
|
|
286
286
|
});
|
|
287
287
|
}
|
|
288
288
|
}, [
|
|
289
|
-
isOpen,
|
|
290
289
|
executionConfig,
|
|
291
|
-
|
|
292
|
-
|
|
290
|
+
isOpen,
|
|
291
|
+
relayer,
|
|
292
|
+
runtimeApiKey
|
|
293
293
|
]);
|
|
294
294
|
const getExecutionContent = () => {
|
|
295
295
|
switch (executionConfig.method) {
|
|
@@ -410,10 +410,10 @@ function validateField(value, validation) {
|
|
|
410
410
|
/**
|
|
411
411
|
* Creates a transform for address fields
|
|
412
412
|
*
|
|
413
|
-
* @param
|
|
413
|
+
* @param addressing The addressing capability to use for validation
|
|
414
414
|
* @returns Transform functions for address fields
|
|
415
415
|
*/
|
|
416
|
-
function createAddressTransform(
|
|
416
|
+
function createAddressTransform(addressing) {
|
|
417
417
|
return {
|
|
418
418
|
input: (value) => {
|
|
419
419
|
if (value === null || value === void 0) return "";
|
|
@@ -421,7 +421,7 @@ function createAddressTransform(adapter) {
|
|
|
421
421
|
},
|
|
422
422
|
output: (value) => {
|
|
423
423
|
const address = String(value || "");
|
|
424
|
-
if (
|
|
424
|
+
if (addressing.isValidAddress(address)) return address;
|
|
425
425
|
return "";
|
|
426
426
|
}
|
|
427
427
|
};
|
|
@@ -525,14 +525,14 @@ function createTextTransform() {
|
|
|
525
525
|
* Creates a transform function based on field type
|
|
526
526
|
*
|
|
527
527
|
* @param fieldType The type of field to create transforms for
|
|
528
|
-
* @param
|
|
528
|
+
* @param addressing Optional addressing capability for address validation
|
|
529
529
|
* @returns Transform functions for the field type
|
|
530
530
|
*/
|
|
531
|
-
function createTransformForFieldType(fieldType,
|
|
531
|
+
function createTransformForFieldType(fieldType, addressing) {
|
|
532
532
|
switch (fieldType) {
|
|
533
533
|
case "blockchain-address":
|
|
534
|
-
if (!
|
|
535
|
-
return createAddressTransform(
|
|
534
|
+
if (!addressing) throw new Error(`createTransformForFieldType: Addressing capability is required for 'blockchain-address' field type but was not provided.`);
|
|
535
|
+
return createAddressTransform(addressing);
|
|
536
536
|
case "number":
|
|
537
537
|
case "amount": return createNumberTransform();
|
|
538
538
|
case "bigint": return createBigIntTransform();
|
|
@@ -843,11 +843,15 @@ function useShouldRenderField(field, control) {
|
|
|
843
843
|
*
|
|
844
844
|
* @returns The rendered form field component or null if the field should not be visible
|
|
845
845
|
*/
|
|
846
|
-
function DynamicFormField({ field, control,
|
|
846
|
+
function DynamicFormField({ field, control, addressing, typeMapping, contractSchema }) {
|
|
847
|
+
const requireTypeMapping = useCallback((fieldName, fieldType) => {
|
|
848
|
+
if (!typeMapping) throw new Error(`DynamicFormField: Missing typeMapping capability for field "${fieldName}" (${fieldType}).`);
|
|
849
|
+
return typeMapping;
|
|
850
|
+
}, [typeMapping]);
|
|
847
851
|
const renderPayloadField = useCallback((payloadField, payloadIndex) => {
|
|
848
852
|
let enhancedPayloadField;
|
|
849
853
|
if (payloadField.originalParameterType) {
|
|
850
|
-
const generatedField =
|
|
854
|
+
const generatedField = requireTypeMapping(payloadField.name, payloadField.type).generateDefaultField({
|
|
851
855
|
name: payloadField.name || `payload_${payloadIndex}`,
|
|
852
856
|
type: payloadField.originalParameterType
|
|
853
857
|
}, contractSchema);
|
|
@@ -866,17 +870,20 @@ function DynamicFormField({ field, control, adapter, contractSchema }) {
|
|
|
866
870
|
return /* @__PURE__ */ jsx(DynamicFormField, {
|
|
867
871
|
field: enhancedPayloadField,
|
|
868
872
|
control,
|
|
869
|
-
|
|
873
|
+
addressing,
|
|
874
|
+
typeMapping,
|
|
870
875
|
contractSchema
|
|
871
876
|
}, `${field.id}-payload-${payloadIndex}`);
|
|
872
877
|
}, [
|
|
873
878
|
field.id,
|
|
874
879
|
control,
|
|
875
|
-
|
|
876
|
-
|
|
880
|
+
contractSchema,
|
|
881
|
+
addressing,
|
|
882
|
+
requireTypeMapping,
|
|
883
|
+
typeMapping
|
|
877
884
|
]);
|
|
878
885
|
const renderKeyField = useCallback((keyField, entryIndex) => {
|
|
879
|
-
const mappedKeyType = keyField.originalParameterType ?
|
|
886
|
+
const mappedKeyType = keyField.originalParameterType ? requireTypeMapping(keyField.name, keyField.type).mapParameterTypeToFieldType(keyField.originalParameterType) : keyField.type;
|
|
880
887
|
return /* @__PURE__ */ jsx(DynamicFormField, {
|
|
881
888
|
field: {
|
|
882
889
|
...keyField,
|
|
@@ -884,18 +891,21 @@ function DynamicFormField({ field, control, adapter, contractSchema }) {
|
|
|
884
891
|
readOnly: keyField.readOnly ?? field.readOnly
|
|
885
892
|
},
|
|
886
893
|
control,
|
|
887
|
-
|
|
894
|
+
addressing,
|
|
895
|
+
typeMapping,
|
|
888
896
|
contractSchema
|
|
889
897
|
}, `${field.id}-key-${entryIndex}`);
|
|
890
898
|
}, [
|
|
891
899
|
field.id,
|
|
892
900
|
field.readOnly,
|
|
893
901
|
control,
|
|
894
|
-
|
|
895
|
-
|
|
902
|
+
contractSchema,
|
|
903
|
+
addressing,
|
|
904
|
+
requireTypeMapping,
|
|
905
|
+
typeMapping
|
|
896
906
|
]);
|
|
897
907
|
const renderValueField = useCallback((valueField, entryIndex) => {
|
|
898
|
-
const mappedValueType = valueField.originalParameterType ?
|
|
908
|
+
const mappedValueType = valueField.originalParameterType ? requireTypeMapping(valueField.name, valueField.type).mapParameterTypeToFieldType(valueField.originalParameterType) : valueField.type;
|
|
899
909
|
return /* @__PURE__ */ jsx(DynamicFormField, {
|
|
900
910
|
field: {
|
|
901
911
|
...valueField,
|
|
@@ -903,15 +913,18 @@ function DynamicFormField({ field, control, adapter, contractSchema }) {
|
|
|
903
913
|
readOnly: valueField.readOnly ?? field.readOnly
|
|
904
914
|
},
|
|
905
915
|
control,
|
|
906
|
-
|
|
916
|
+
addressing,
|
|
917
|
+
typeMapping,
|
|
907
918
|
contractSchema
|
|
908
919
|
}, `${field.id}-value-${entryIndex}`);
|
|
909
920
|
}, [
|
|
910
921
|
field.id,
|
|
911
922
|
field.readOnly,
|
|
912
923
|
control,
|
|
913
|
-
|
|
914
|
-
|
|
924
|
+
contractSchema,
|
|
925
|
+
addressing,
|
|
926
|
+
requireTypeMapping,
|
|
927
|
+
typeMapping
|
|
915
928
|
]);
|
|
916
929
|
if (!useShouldRenderField(field, control)) return null;
|
|
917
930
|
const FieldComponent = fieldComponents[field.type];
|
|
@@ -931,7 +944,8 @@ function DynamicFormField({ field, control, adapter, contractSchema }) {
|
|
|
931
944
|
readOnly: elementField.readOnly ?? field.readOnly
|
|
932
945
|
},
|
|
933
946
|
control,
|
|
934
|
-
|
|
947
|
+
addressing,
|
|
948
|
+
typeMapping,
|
|
935
949
|
contractSchema
|
|
936
950
|
}, `${field.id}-element-${index}`) },
|
|
937
951
|
...field.type === "object" && { renderProperty: (propertyField, propertyName) => /* @__PURE__ */ jsx(DynamicFormField, {
|
|
@@ -940,7 +954,8 @@ function DynamicFormField({ field, control, adapter, contractSchema }) {
|
|
|
940
954
|
readOnly: propertyField.readOnly ?? field.readOnly
|
|
941
955
|
},
|
|
942
956
|
control,
|
|
943
|
-
|
|
957
|
+
addressing,
|
|
958
|
+
typeMapping,
|
|
944
959
|
contractSchema
|
|
945
960
|
}, `${field.id}-property-${propertyName}`) },
|
|
946
961
|
...field.type === "array-object" && { renderProperty: (propertyField, itemIndex, propertyName) => /* @__PURE__ */ jsx(DynamicFormField, {
|
|
@@ -949,7 +964,8 @@ function DynamicFormField({ field, control, adapter, contractSchema }) {
|
|
|
949
964
|
readOnly: propertyField.readOnly ?? field.readOnly
|
|
950
965
|
},
|
|
951
966
|
control,
|
|
952
|
-
|
|
967
|
+
addressing,
|
|
968
|
+
typeMapping,
|
|
953
969
|
contractSchema
|
|
954
970
|
}, `${field.id}-item-${itemIndex}-property-${propertyName}`) }
|
|
955
971
|
};
|
|
@@ -962,7 +978,8 @@ function DynamicFormField({ field, control, adapter, contractSchema }) {
|
|
|
962
978
|
validation: field.validation,
|
|
963
979
|
control,
|
|
964
980
|
name: field.name,
|
|
965
|
-
|
|
981
|
+
addressing,
|
|
982
|
+
typeMapping,
|
|
966
983
|
readOnly: field.readOnly,
|
|
967
984
|
contractSchema,
|
|
968
985
|
...enhancedProps
|
|
@@ -1095,7 +1112,7 @@ function formatErrorWithHash(errorMsg) {
|
|
|
1095
1112
|
});
|
|
1096
1113
|
}
|
|
1097
1114
|
/** Displays the current status of a transaction with appropriate icons and messages. */
|
|
1098
|
-
function TransactionStatusDisplay({ status, txHash, error, explorerUrl, className, customTitle, customMessage, result, functionDetails,
|
|
1115
|
+
function TransactionStatusDisplay({ status, txHash, error, explorerUrl, className, customTitle, customMessage, result, functionDetails, query, explorer }) {
|
|
1099
1116
|
if (status === "idle") return null;
|
|
1100
1117
|
let variant = "default";
|
|
1101
1118
|
let defaultTitle = "";
|
|
@@ -1128,12 +1145,14 @@ function TransactionStatusDisplay({ status, txHash, error, explorerUrl, classNam
|
|
|
1128
1145
|
}
|
|
1129
1146
|
const title = customTitle || defaultTitle;
|
|
1130
1147
|
let formattedResult = null;
|
|
1131
|
-
if (result !== void 0 && result !== null &&
|
|
1132
|
-
|
|
1148
|
+
if (result !== void 0 && result !== null && query && functionDetails) try {
|
|
1149
|
+
const nextFormattedResult = query.formatFunctionResult(result, functionDetails);
|
|
1150
|
+
formattedResult = typeof nextFormattedResult === "string" ? nextFormattedResult : JSON.stringify(nextFormattedResult, null, 2);
|
|
1133
1151
|
} catch {
|
|
1134
1152
|
formattedResult = JSON.stringify(result, null, 2);
|
|
1135
1153
|
}
|
|
1136
1154
|
else if (result !== void 0 && result !== null) formattedResult = JSON.stringify(result, null, 2);
|
|
1155
|
+
const resolvedExplorerUrl = explorerUrl ?? (txHash ? explorer?.getExplorerTxUrl?.(txHash) ?? explorer?.getExplorerUrl(txHash) ?? null : null);
|
|
1137
1156
|
let content = null;
|
|
1138
1157
|
if (status === "error") content = /* @__PURE__ */ jsxs("div", { children: [error ? formatErrorWithHash(error) : customMessage ? /* @__PURE__ */ jsx("span", {
|
|
1139
1158
|
className: "break-word",
|
|
@@ -1143,7 +1162,7 @@ function TransactionStatusDisplay({ status, txHash, error, explorerUrl, classNam
|
|
|
1143
1162
|
children: "An unknown error occurred."
|
|
1144
1163
|
}), txHash && /* @__PURE__ */ jsx(TransactionHashDisplay, {
|
|
1145
1164
|
txHash,
|
|
1146
|
-
explorerUrl:
|
|
1165
|
+
explorerUrl: resolvedExplorerUrl
|
|
1147
1166
|
})] });
|
|
1148
1167
|
else {
|
|
1149
1168
|
const messageText = customMessage || defaultMessage || "";
|
|
@@ -1153,7 +1172,7 @@ function TransactionStatusDisplay({ status, txHash, error, explorerUrl, classNam
|
|
|
1153
1172
|
messageText && /* @__PURE__ */ jsx("p", { children: messageText }),
|
|
1154
1173
|
txHash && /* @__PURE__ */ jsx(TransactionHashDisplay, {
|
|
1155
1174
|
txHash,
|
|
1156
|
-
explorerUrl:
|
|
1175
|
+
explorerUrl: resolvedExplorerUrl
|
|
1157
1176
|
}),
|
|
1158
1177
|
formattedResult && /* @__PURE__ */ jsxs("div", {
|
|
1159
1178
|
className: "mt-3 pt-3 border-t border-border",
|
|
@@ -1358,7 +1377,8 @@ function TransactionForm({ schema, contractSchema, adapter, isWalletConnected =
|
|
|
1358
1377
|
field,
|
|
1359
1378
|
control: methods.control,
|
|
1360
1379
|
error: errors[field.name]?.message,
|
|
1361
|
-
adapter,
|
|
1380
|
+
addressing: adapter,
|
|
1381
|
+
typeMapping: adapter,
|
|
1362
1382
|
contractSchema
|
|
1363
1383
|
}, field.id))
|
|
1364
1384
|
});
|
|
@@ -1417,7 +1437,8 @@ function TransactionForm({ schema, contractSchema, adapter, isWalletConnected =
|
|
|
1417
1437
|
customMessage: txStatusDetails?.message,
|
|
1418
1438
|
result: txResult,
|
|
1419
1439
|
functionDetails: currentFunction,
|
|
1420
|
-
adapter
|
|
1440
|
+
query: adapter,
|
|
1441
|
+
explorer: adapter
|
|
1421
1442
|
})
|
|
1422
1443
|
}),
|
|
1423
1444
|
/* @__PURE__ */ jsxs("form", {
|
|
@@ -1437,7 +1458,8 @@ function TransactionForm({ schema, contractSchema, adapter, isWalletConnected =
|
|
|
1437
1458
|
className: "w-full",
|
|
1438
1459
|
children: /* @__PURE__ */ jsx(ExecutionConfigDisplay, {
|
|
1439
1460
|
executionConfig,
|
|
1440
|
-
adapter,
|
|
1461
|
+
execution: adapter,
|
|
1462
|
+
relayer: adapter,
|
|
1441
1463
|
error: executionConfigError,
|
|
1442
1464
|
onRuntimeApiKeyChange: setRuntimeApiKey
|
|
1443
1465
|
})
|
|
@@ -1467,22 +1489,22 @@ function TransactionForm({ schema, contractSchema, adapter, isWalletConnected =
|
|
|
1467
1489
|
//#endregion
|
|
1468
1490
|
//#region src/components/AddressBookWidget/AddAliasDialog.tsx
|
|
1469
1491
|
/** Dialog for creating a new address alias entry. */
|
|
1470
|
-
function AddAliasDialog({ open, onOpenChange, onSave, currentNetworkId,
|
|
1492
|
+
function AddAliasDialog({ open, onOpenChange, onSave, currentNetworkId, addressing: defaultAddressing, resolveAddressing, addressPlaceholder: defaultPlaceholder, resolveAddressPlaceholder, resolveNetwork, networks }) {
|
|
1471
1493
|
const [saving, setSaving] = useState(false);
|
|
1472
1494
|
const initialNetwork = useMemo(() => currentNetworkId && resolveNetwork ? resolveNetwork(currentNetworkId) : void 0, [currentNetworkId, resolveNetwork]);
|
|
1473
1495
|
const [selectedNetwork, setSelectedNetwork] = useState(initialNetwork ?? null);
|
|
1474
|
-
const [
|
|
1496
|
+
const [activeAddressing, setActiveAddressing] = useState(defaultAddressing);
|
|
1475
1497
|
const [activePlaceholder, setActivePlaceholder] = useState(defaultPlaceholder);
|
|
1476
1498
|
useEffect(() => {
|
|
1477
1499
|
if (open) {
|
|
1478
1500
|
setSelectedNetwork(initialNetwork ?? null);
|
|
1479
|
-
|
|
1501
|
+
setActiveAddressing(defaultAddressing);
|
|
1480
1502
|
setActivePlaceholder(defaultPlaceholder);
|
|
1481
1503
|
}
|
|
1482
1504
|
}, [
|
|
1483
1505
|
open,
|
|
1484
1506
|
initialNetwork,
|
|
1485
|
-
|
|
1507
|
+
defaultAddressing,
|
|
1486
1508
|
defaultPlaceholder
|
|
1487
1509
|
]);
|
|
1488
1510
|
const { control, handleSubmit, reset, trigger, formState } = useForm({
|
|
@@ -1495,12 +1517,12 @@ function AddAliasDialog({ open, onOpenChange, onSave, currentNetworkId, adapter:
|
|
|
1495
1517
|
const handleNetworkChange = useCallback(async (network) => {
|
|
1496
1518
|
setSelectedNetwork(network);
|
|
1497
1519
|
if (resolveAddressPlaceholder) setActivePlaceholder(resolveAddressPlaceholder(network));
|
|
1498
|
-
if (
|
|
1499
|
-
|
|
1520
|
+
if (resolveAddressing) {
|
|
1521
|
+
setActiveAddressing(await resolveAddressing(network));
|
|
1500
1522
|
trigger("address");
|
|
1501
1523
|
}
|
|
1502
1524
|
}, [
|
|
1503
|
-
|
|
1525
|
+
resolveAddressing,
|
|
1504
1526
|
resolveAddressPlaceholder,
|
|
1505
1527
|
trigger
|
|
1506
1528
|
]);
|
|
@@ -1529,12 +1551,12 @@ function AddAliasDialog({ open, onOpenChange, onSave, currentNetworkId, adapter:
|
|
|
1529
1551
|
if (!nextOpen) {
|
|
1530
1552
|
reset();
|
|
1531
1553
|
setSelectedNetwork(initialNetwork ?? null);
|
|
1532
|
-
|
|
1554
|
+
setActiveAddressing(defaultAddressing);
|
|
1533
1555
|
setActivePlaceholder(defaultPlaceholder);
|
|
1534
1556
|
}
|
|
1535
1557
|
onOpenChange(nextOpen);
|
|
1536
1558
|
}, [
|
|
1537
|
-
|
|
1559
|
+
defaultAddressing,
|
|
1538
1560
|
defaultPlaceholder,
|
|
1539
1561
|
initialNetwork,
|
|
1540
1562
|
onOpenChange,
|
|
@@ -1578,7 +1600,7 @@ function AddAliasDialog({ open, onOpenChange, onSave, currentNetworkId, adapter:
|
|
|
1578
1600
|
placeholder: activePlaceholder,
|
|
1579
1601
|
control,
|
|
1580
1602
|
validation: { required: true },
|
|
1581
|
-
|
|
1603
|
+
addressing: activeAddressing
|
|
1582
1604
|
}),
|
|
1583
1605
|
/* @__PURE__ */ jsx(TextField, {
|
|
1584
1606
|
id: "new-alias-name",
|
|
@@ -1783,7 +1805,7 @@ function ImportExportBar({ onExport, onImport, exportDisabled }) {
|
|
|
1783
1805
|
//#endregion
|
|
1784
1806
|
//#region src/components/AddressBookWidget/AddressBookWidget.tsx
|
|
1785
1807
|
/** Widget for managing a personal address book with aliases, search, and network filtering. */
|
|
1786
|
-
function AddressBookWidget({ aliases, isLoading, onSave, onRemove, onClear, onExport, onImport, currentNetworkId, resolveNetwork, resolveExplorerUrl,
|
|
1808
|
+
function AddressBookWidget({ aliases, isLoading, onSave, onRemove, onClear, onExport, onImport, currentNetworkId, resolveNetwork, resolveExplorerUrl, addressing, resolveAddressing, addressPlaceholder, resolveAddressPlaceholder, networks, filterNetworkIds, onFilterNetworkIdsChange, title = "Address Book", className }) {
|
|
1787
1809
|
const [search, setSearch] = useState("");
|
|
1788
1810
|
const [addDialogOpen, setAddDialogOpen] = useState(false);
|
|
1789
1811
|
const [confirmClear, setConfirmClear] = useState(false);
|
|
@@ -1856,8 +1878,8 @@ function AddressBookWidget({ aliases, isLoading, onSave, onRemove, onClear, onEx
|
|
|
1856
1878
|
onOpenChange: setAddDialogOpen,
|
|
1857
1879
|
onSave,
|
|
1858
1880
|
currentNetworkId,
|
|
1859
|
-
|
|
1860
|
-
|
|
1881
|
+
addressing,
|
|
1882
|
+
resolveAddressing,
|
|
1861
1883
|
addressPlaceholder,
|
|
1862
1884
|
resolveAddressPlaceholder,
|
|
1863
1885
|
resolveNetwork,
|
|
@@ -2225,8 +2247,8 @@ function FunctionResult({ functionDetails, result, loading }) {
|
|
|
2225
2247
|
/**
|
|
2226
2248
|
* Panel for displaying and querying simple view functions (functions without parameters)
|
|
2227
2249
|
*/
|
|
2228
|
-
function ViewFunctionsPanel({ functions, contractAddress,
|
|
2229
|
-
const safeFunctions =
|
|
2250
|
+
function ViewFunctionsPanel({ functions, contractAddress, query, schema, contractSchema, className }) {
|
|
2251
|
+
const safeFunctions = schema.filterAutoQueryableFunctions ? schema.filterAutoQueryableFunctions(functions) : functions;
|
|
2230
2252
|
const [results, setResults] = useState({});
|
|
2231
2253
|
const [loadingStates, setLoadingStates] = useState({});
|
|
2232
2254
|
const [hasQueried, setHasQueried] = useState(false);
|
|
@@ -2246,10 +2268,11 @@ function ViewFunctionsPanel({ functions, contractAddress, adapter, contractSchem
|
|
|
2246
2268
|
try {
|
|
2247
2269
|
await rateLimitedBatch(safeFunctions.map((func) => async () => {
|
|
2248
2270
|
try {
|
|
2249
|
-
const result = await
|
|
2271
|
+
const result = await query.queryViewFunction(contractAddress, func.id, [], contractSchema);
|
|
2250
2272
|
let formattedResult;
|
|
2251
2273
|
try {
|
|
2252
|
-
|
|
2274
|
+
const nextResult = query.formatFunctionResult(result, func);
|
|
2275
|
+
formattedResult = typeof nextResult === "string" ? nextResult : JSON.stringify(nextResult, null, 2);
|
|
2253
2276
|
} catch (formatError) {
|
|
2254
2277
|
logger.error("ViewFunctionsPanel", `Error formatting result for ${func.name}:`, formatError);
|
|
2255
2278
|
formattedResult = `Error formatting result: ${formatError instanceof Error ? formatError.message : "Unknown error"}`;
|
|
@@ -2291,11 +2314,11 @@ function ViewFunctionsPanel({ functions, contractAddress, adapter, contractSchem
|
|
|
2291
2314
|
setIsQueryInProgress(false);
|
|
2292
2315
|
}
|
|
2293
2316
|
}, [
|
|
2294
|
-
safeFunctions,
|
|
2295
2317
|
contractAddress,
|
|
2296
|
-
adapter,
|
|
2297
2318
|
contractSchema,
|
|
2298
|
-
isQueryInProgress
|
|
2319
|
+
isQueryInProgress,
|
|
2320
|
+
query,
|
|
2321
|
+
safeFunctions
|
|
2299
2322
|
]);
|
|
2300
2323
|
useEffect(() => {
|
|
2301
2324
|
let mounted = true;
|
|
@@ -2317,13 +2340,13 @@ function ViewFunctionsPanel({ functions, contractAddress, adapter, contractSchem
|
|
|
2317
2340
|
handleQueryAll
|
|
2318
2341
|
]);
|
|
2319
2342
|
useEffect(() => {
|
|
2320
|
-
const networkId =
|
|
2343
|
+
const networkId = query.networkConfig?.id;
|
|
2321
2344
|
if (!networkId) return;
|
|
2322
2345
|
return userRpcConfigService.subscribe(networkId, (event) => {
|
|
2323
2346
|
logger.info("ViewFunctionsPanel", "RPC configuration changed:", event);
|
|
2324
2347
|
handleQueryAll();
|
|
2325
2348
|
});
|
|
2326
|
-
}, [
|
|
2349
|
+
}, [handleQueryAll, query.networkConfig?.id]);
|
|
2327
2350
|
if (safeFunctions.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
2328
2351
|
className: "text-xs text-muted-foreground",
|
|
2329
2352
|
children: "No simple view functions found in this contract."
|
|
@@ -2370,19 +2393,19 @@ function ViewFunctionsPanel({ functions, contractAddress, adapter, contractSchem
|
|
|
2370
2393
|
* ContractStateWidget - Compact widget for displaying contract state
|
|
2371
2394
|
* Shows contract state by allowing users to query simple view functions (no parameters)
|
|
2372
2395
|
*/
|
|
2373
|
-
function ContractStateWidget({ contractSchema, contractAddress,
|
|
2396
|
+
function ContractStateWidget({ contractSchema, contractAddress, query, schema, isVisible = true, onToggle, className, error }) {
|
|
2374
2397
|
const [viewFunctions, setViewFunctions] = useState([]);
|
|
2375
2398
|
const [animationState, setAnimationState] = useState(isVisible ? "entered" : "exited");
|
|
2376
|
-
const networkConfig =
|
|
2399
|
+
const networkConfig = query?.networkConfig;
|
|
2377
2400
|
const [lastSchema, setLastSchema] = useState(contractSchema ?? null);
|
|
2378
2401
|
useEffect(() => {
|
|
2379
2402
|
if (contractSchema) setLastSchema(contractSchema);
|
|
2380
2403
|
}, [contractSchema]);
|
|
2381
2404
|
const effectiveSchema = useMemo(() => contractSchema ?? lastSchema, [contractSchema, lastSchema]);
|
|
2382
2405
|
useEffect(() => {
|
|
2383
|
-
if (!effectiveSchema
|
|
2384
|
-
setViewFunctions(effectiveSchema.functions.filter((fn) =>
|
|
2385
|
-
}, [effectiveSchema,
|
|
2406
|
+
if (!effectiveSchema) return;
|
|
2407
|
+
setViewFunctions(effectiveSchema.functions.filter((fn) => schema.isViewFunction(fn)).filter((fn) => fn.inputs.length === 0));
|
|
2408
|
+
}, [effectiveSchema, schema]);
|
|
2386
2409
|
useEffect(() => {
|
|
2387
2410
|
if (isVisible) {
|
|
2388
2411
|
setAnimationState("entering");
|
|
@@ -2401,7 +2424,7 @@ function ContractStateWidget({ contractSchema, contractAddress, adapter, isVisib
|
|
|
2401
2424
|
const handleToggle = () => {
|
|
2402
2425
|
if (onToggle) onToggle();
|
|
2403
2426
|
};
|
|
2404
|
-
if (!contractAddress || !
|
|
2427
|
+
if (!contractAddress || !networkConfig) return null;
|
|
2405
2428
|
return /* @__PURE__ */ jsxs(Fragment, { children: [(animationState === "entering" || animationState === "entered" || animationState === "exiting") && /* @__PURE__ */ jsx("div", {
|
|
2406
2429
|
className: cn("fixed inset-0 z-[9998] md:hidden bg-background/60 backdrop-blur-sm transition-opacity duration-500 ease-in-out", animationState === "entering" || animationState === "entered" ? "opacity-100" : "opacity-0"),
|
|
2407
2430
|
"aria-hidden": "true",
|
|
@@ -2436,7 +2459,7 @@ function ContractStateWidget({ contractSchema, contractAddress, adapter, isVisib
|
|
|
2436
2459
|
className: "mt-1 text-xs text-center",
|
|
2437
2460
|
children: error.message
|
|
2438
2461
|
})]
|
|
2439
|
-
}) : !effectiveSchema && !lastSchema
|
|
2462
|
+
}) : !effectiveSchema && !lastSchema ? /* @__PURE__ */ jsxs("div", {
|
|
2440
2463
|
className: "flex flex-col items-center justify-center h-full space-y-3 py-6",
|
|
2441
2464
|
children: [/* @__PURE__ */ jsx(Loader2, { className: "h-8 w-8 text-primary animate-spin opacity-70" }), /* @__PURE__ */ jsxs("div", {
|
|
2442
2465
|
className: "text-center space-y-1",
|
|
@@ -2451,7 +2474,8 @@ function ContractStateWidget({ contractSchema, contractAddress, adapter, isVisib
|
|
|
2451
2474
|
}) : viewFunctions.length > 0 && effectiveSchema ? /* @__PURE__ */ jsx(ViewFunctionsPanel, {
|
|
2452
2475
|
functions: viewFunctions,
|
|
2453
2476
|
contractAddress,
|
|
2454
|
-
|
|
2477
|
+
query,
|
|
2478
|
+
schema,
|
|
2455
2479
|
contractSchema: effectiveSchema,
|
|
2456
2480
|
className: "flex-grow flex flex-col min-h-0"
|
|
2457
2481
|
}) : /* @__PURE__ */ jsxs("div", {
|
|
@@ -2502,7 +2526,7 @@ function ContractActionBar({ networkConfig, contractAddress = null, onToggleCont
|
|
|
2502
2526
|
//#endregion
|
|
2503
2527
|
//#region src/components/network/NetworkServiceSettingsPanel.tsx
|
|
2504
2528
|
/** Panel for configuring network service settings like RPC endpoints. */
|
|
2505
|
-
function NetworkServiceSettingsPanel({
|
|
2529
|
+
function NetworkServiceSettingsPanel({ relayer, networkId, service, onSettingsChanged }) {
|
|
2506
2530
|
const [isTesting, setIsTesting] = useState(false);
|
|
2507
2531
|
const [result, setResult] = useState(null);
|
|
2508
2532
|
const { control, handleSubmit, setValue, getValues, watch, formState: { isDirty } } = useForm({ defaultValues: {} });
|
|
@@ -2547,12 +2571,12 @@ function NetworkServiceSettingsPanel({ adapter, networkId, service, onSettingsCh
|
|
|
2547
2571
|
getValues
|
|
2548
2572
|
]);
|
|
2549
2573
|
const testConnection = useCallback(async () => {
|
|
2550
|
-
if (!
|
|
2574
|
+
if (!relayer.testNetworkServiceConnection) return;
|
|
2551
2575
|
setIsTesting(true);
|
|
2552
2576
|
setResult(null);
|
|
2553
2577
|
try {
|
|
2554
2578
|
const data = getValues();
|
|
2555
|
-
const r = await
|
|
2579
|
+
const r = await relayer.testNetworkServiceConnection(service.id, data);
|
|
2556
2580
|
setResult({
|
|
2557
2581
|
success: r.success,
|
|
2558
2582
|
message: r.error || (r.success ? "Connection successful" : "Connection failed"),
|
|
@@ -2567,15 +2591,15 @@ function NetworkServiceSettingsPanel({ adapter, networkId, service, onSettingsCh
|
|
|
2567
2591
|
setIsTesting(false);
|
|
2568
2592
|
}
|
|
2569
2593
|
}, [
|
|
2570
|
-
|
|
2594
|
+
relayer,
|
|
2571
2595
|
service.id,
|
|
2572
2596
|
getValues
|
|
2573
2597
|
]);
|
|
2574
2598
|
return /* @__PURE__ */ jsxs("form", {
|
|
2575
2599
|
onSubmit: handleSubmit(useCallback(async (formData) => {
|
|
2576
2600
|
const data = formData;
|
|
2577
|
-
if (
|
|
2578
|
-
if (!await
|
|
2601
|
+
if (relayer.validateNetworkServiceConfig) {
|
|
2602
|
+
if (!await relayer.validateNetworkServiceConfig(service.id, data)) {
|
|
2579
2603
|
setResult({
|
|
2580
2604
|
success: false,
|
|
2581
2605
|
message: "Invalid configuration"
|
|
@@ -2591,7 +2615,7 @@ function NetworkServiceSettingsPanel({ adapter, networkId, service, onSettingsCh
|
|
|
2591
2615
|
message: "Settings saved successfully"
|
|
2592
2616
|
});
|
|
2593
2617
|
}, [
|
|
2594
|
-
|
|
2618
|
+
relayer,
|
|
2595
2619
|
networkId,
|
|
2596
2620
|
service.id,
|
|
2597
2621
|
onSettingsChanged
|
|
@@ -2633,8 +2657,7 @@ function NetworkServiceSettingsPanel({ adapter, networkId, service, onSettingsCh
|
|
|
2633
2657
|
className: "space-y-4",
|
|
2634
2658
|
children: primaryFields.map((field) => /* @__PURE__ */ jsx(DynamicFormField, {
|
|
2635
2659
|
field,
|
|
2636
|
-
control
|
|
2637
|
-
adapter
|
|
2660
|
+
control
|
|
2638
2661
|
}, field.id))
|
|
2639
2662
|
}),
|
|
2640
2663
|
Object.keys(sectionGroups).length > 0 && /* @__PURE__ */ jsx(Accordion, {
|
|
@@ -2680,8 +2703,7 @@ function NetworkServiceSettingsPanel({ adapter, networkId, service, onSettingsCh
|
|
|
2680
2703
|
className: indentUnder ? "ml-6" : "",
|
|
2681
2704
|
children: /* @__PURE__ */ jsx(DynamicFormField, {
|
|
2682
2705
|
field: wrappedField,
|
|
2683
|
-
control
|
|
2684
|
-
adapter
|
|
2706
|
+
control
|
|
2685
2707
|
})
|
|
2686
2708
|
}, field.id);
|
|
2687
2709
|
})
|
|
@@ -2724,7 +2746,7 @@ function NetworkServiceSettingsPanel({ adapter, networkId, service, onSettingsCh
|
|
|
2724
2746
|
const hideTest = fields.some((f) => {
|
|
2725
2747
|
return f.metadata?.hideTestConnection === true;
|
|
2726
2748
|
});
|
|
2727
|
-
return Boolean(
|
|
2749
|
+
return Boolean(relayer.testNetworkServiceConnection) && !hideTest;
|
|
2728
2750
|
})() ? /* @__PURE__ */ jsx(Button, {
|
|
2729
2751
|
type: "button",
|
|
2730
2752
|
variant: "outline",
|
|
@@ -2745,14 +2767,14 @@ function NetworkServiceSettingsPanel({ adapter, networkId, service, onSettingsCh
|
|
|
2745
2767
|
|
|
2746
2768
|
//#endregion
|
|
2747
2769
|
//#region src/components/network/NetworkSettingsDialog.tsx
|
|
2748
|
-
const NetworkSettingsDialog = ({ isOpen, onOpenChange, networkConfig,
|
|
2749
|
-
const services = filterEnabledServiceForms(
|
|
2770
|
+
const NetworkSettingsDialog = ({ isOpen, onOpenChange, networkConfig, relayer, onSettingsChanged }) => {
|
|
2771
|
+
const services = filterEnabledServiceForms(relayer?.getNetworkServiceForms() ?? []);
|
|
2750
2772
|
return /* @__PURE__ */ jsx(Dialog, {
|
|
2751
2773
|
open: isOpen,
|
|
2752
2774
|
onOpenChange,
|
|
2753
2775
|
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
2754
2776
|
className: "max-w-2xl sm:max-w-3xl",
|
|
2755
|
-
children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: "Network Settings" }), /* @__PURE__ */ jsxs(DialogDescription, { children: ["Configure settings for ", networkConfig?.name] })] }), networkConfig &&
|
|
2777
|
+
children: [/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: "Network Settings" }), /* @__PURE__ */ jsxs(DialogDescription, { children: ["Configure settings for ", networkConfig?.name] })] }), networkConfig && relayer && services.length > 0 ? /* @__PURE__ */ jsxs(Tabs, {
|
|
2756
2778
|
defaultValue: services[0]?.id,
|
|
2757
2779
|
className: "w-full",
|
|
2758
2780
|
children: [/* @__PURE__ */ jsx(TabsList, {
|
|
@@ -2765,16 +2787,10 @@ const NetworkSettingsDialog = ({ isOpen, onOpenChange, networkConfig, adapter })
|
|
|
2765
2787
|
value: svc.id,
|
|
2766
2788
|
className: "px-2",
|
|
2767
2789
|
children: /* @__PURE__ */ jsx(NetworkServiceSettingsPanel, {
|
|
2768
|
-
|
|
2790
|
+
relayer,
|
|
2769
2791
|
networkId: networkConfig.id,
|
|
2770
2792
|
service: svc,
|
|
2771
|
-
onSettingsChanged
|
|
2772
|
-
const cfg = appConfigService.getTypedNestedConfig("walletui", "config");
|
|
2773
|
-
adapter.configureUiKit?.(cfg ?? {
|
|
2774
|
-
kitName: "custom",
|
|
2775
|
-
kitConfig: {}
|
|
2776
|
-
});
|
|
2777
|
-
}
|
|
2793
|
+
onSettingsChanged
|
|
2778
2794
|
})
|
|
2779
2795
|
}, svc.id))]
|
|
2780
2796
|
}) : /* @__PURE__ */ jsx("div", {
|
|
@@ -2801,7 +2817,7 @@ const NetworkSettingsDialog = ({ isOpen, onOpenChange, networkConfig, adapter })
|
|
|
2801
2817
|
* Used in exported apps to provide access to RPC and Explorer configuration.
|
|
2802
2818
|
*/
|
|
2803
2819
|
const WalletConnectionWithSettings = () => {
|
|
2804
|
-
const {
|
|
2820
|
+
const { isRuntimeLoading, activeRuntime, activeNetworkConfig, reconfigureActiveUiKit } = useWalletState();
|
|
2805
2821
|
const { setOpenNetworkSettingsHandler } = useNetworkErrors();
|
|
2806
2822
|
const [showNetworkSettings, setShowNetworkSettings] = useState(false);
|
|
2807
2823
|
const openNetworkSettings = useCallback((networkId) => {
|
|
@@ -2810,10 +2826,10 @@ const WalletConnectionWithSettings = () => {
|
|
|
2810
2826
|
useEffect(() => {
|
|
2811
2827
|
setOpenNetworkSettingsHandler(openNetworkSettings);
|
|
2812
2828
|
}, [openNetworkSettings, setOpenNetworkSettingsHandler]);
|
|
2813
|
-
if (
|
|
2829
|
+
if (isRuntimeLoading) return /* @__PURE__ */ jsx("div", { className: "h-9 w-28 animate-pulse rounded bg-muted" });
|
|
2814
2830
|
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
|
|
2815
2831
|
className: "flex items-center gap-2",
|
|
2816
|
-
children: [/* @__PURE__ */ jsx(WalletConnectionUI, {}),
|
|
2832
|
+
children: [/* @__PURE__ */ jsx(WalletConnectionUI, {}), activeRuntime?.relayer && activeNetworkConfig && /* @__PURE__ */ jsx(Button, {
|
|
2817
2833
|
variant: "ghost",
|
|
2818
2834
|
size: "icon",
|
|
2819
2835
|
className: "h-9 w-9",
|
|
@@ -2825,7 +2841,13 @@ const WalletConnectionWithSettings = () => {
|
|
|
2825
2841
|
isOpen: showNetworkSettings,
|
|
2826
2842
|
onOpenChange: setShowNetworkSettings,
|
|
2827
2843
|
networkConfig: activeNetworkConfig,
|
|
2828
|
-
|
|
2844
|
+
relayer: activeRuntime?.relayer ?? null,
|
|
2845
|
+
onSettingsChanged: () => {
|
|
2846
|
+
reconfigureActiveUiKit(appConfigService.getTypedNestedConfig("walletui", "config") ?? {
|
|
2847
|
+
kitName: "custom",
|
|
2848
|
+
kitConfig: {}
|
|
2849
|
+
});
|
|
2850
|
+
}
|
|
2829
2851
|
})] });
|
|
2830
2852
|
};
|
|
2831
2853
|
|