@epoch-protocol/epoch-commons-sdk 0.1.18 → 0.1.19
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/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/miden-intent.d.ts +29 -0
- package/dist/utils/miden-intent.js +79 -0
- package/dist/utils/witness-typestring-constants.d.ts +18 -0
- package/dist/utils/witness-typestring-constants.js +31 -0
- package/dist/utils/witness-typestring-parse.d.ts +5 -0
- package/dist/utils/witness-typestring-parse.js +18 -0
- package/dist/utils/witness-typestring.d.ts +30 -12
- package/dist/utils/witness-typestring.js +125 -54
- package/package.json +1 -1
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { EVM_TO_MIDEN_EXTRA_TYPESTRING, EVM_TO_MIDEN_FIELD_NAMES, MIDEN_MARKER_FIELD_NAMES, MIDEN_TO_EVM_EXTRA_TYPESTRING, MIDEN_TO_EVM_FIELD_NAMES } from "./witness-typestring.js";
|
|
2
|
+
export type MidenBridgeDirection = "miden-to-evm" | "evm-to-miden";
|
|
3
|
+
export interface MidenExtraData {
|
|
4
|
+
midenSourceAccount?: string;
|
|
5
|
+
midenRecipientAccount?: string;
|
|
6
|
+
midenFaucetId?: string;
|
|
7
|
+
midenNoteType?: string;
|
|
8
|
+
midenNoteId?: string;
|
|
9
|
+
}
|
|
10
|
+
/** True when mandate/extra data carries any Miden bridge marker field. */
|
|
11
|
+
export declare function hasMidenMarkersInData(data?: Record<string, unknown>): boolean;
|
|
12
|
+
/** True when a witness/extra typestring declares any Miden bridge marker field. */
|
|
13
|
+
export declare function hasMidenMarkersInTypestring(typestring: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* True iff the intent is a Miden bridge intent (markers in typestring and/or data).
|
|
16
|
+
* At least one of `typestring` or `data` must be provided.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isMidenIntent(typestring?: string, data?: Record<string, unknown>): boolean;
|
|
19
|
+
/** EVM→Miden: recipient set, source account absent. */
|
|
20
|
+
export declare function isEVMToMidenIntent(data?: Record<string, unknown>): boolean;
|
|
21
|
+
/** Miden→EVM: source account set. */
|
|
22
|
+
export declare function isMidenToEvmIntent(data?: Record<string, unknown>): boolean;
|
|
23
|
+
export declare function hasMidenToEvmTypestringMarker(typestring: string): boolean;
|
|
24
|
+
export declare function hasEvmToMidenTypestringMarker(typestring: string): boolean;
|
|
25
|
+
export declare function resolveMidenBridgeDirection(typestring: string, data?: Record<string, unknown>): MidenBridgeDirection | "conflict" | null;
|
|
26
|
+
export declare function getMidenMetadata(data?: Record<string, unknown>, typestring?: string): MidenExtraData | null;
|
|
27
|
+
/** @deprecated Use {@link isEVMToMidenIntent}. */
|
|
28
|
+
export declare function isEVMToMidenMandate(mandate?: Record<string, unknown>): boolean;
|
|
29
|
+
export { EVM_TO_MIDEN_EXTRA_TYPESTRING, EVM_TO_MIDEN_FIELD_NAMES, MIDEN_TO_EVM_EXTRA_TYPESTRING, MIDEN_TO_EVM_FIELD_NAMES, MIDEN_MARKER_FIELD_NAMES, };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { EVM_TO_MIDEN_EXTRA_TYPESTRING, EVM_TO_MIDEN_FIELD_NAMES, MIDEN_MARKER_FIELD_NAMES, MIDEN_RECIPIENT_ACCOUNT_FIELD_NAME, MIDEN_SOURCE_ACCOUNT_FIELD_NAME, MIDEN_TO_EVM_EXTRA_TYPESTRING, MIDEN_TO_EVM_FIELD_NAMES, } from "./witness-typestring.js";
|
|
2
|
+
function hasTruthyField(data, fieldName) {
|
|
3
|
+
return data[fieldName] != null && data[fieldName] !== "";
|
|
4
|
+
}
|
|
5
|
+
/** True when mandate/extra data carries any Miden bridge marker field. */
|
|
6
|
+
export function hasMidenMarkersInData(data) {
|
|
7
|
+
if (!data)
|
|
8
|
+
return false;
|
|
9
|
+
return MIDEN_MARKER_FIELD_NAMES.some((name) => hasTruthyField(data, name));
|
|
10
|
+
}
|
|
11
|
+
/** True when a witness/extra typestring declares any Miden bridge marker field. */
|
|
12
|
+
export function hasMidenMarkersInTypestring(typestring) {
|
|
13
|
+
if (!typestring.trim())
|
|
14
|
+
return false;
|
|
15
|
+
return MIDEN_MARKER_FIELD_NAMES.some((name) => typestring.includes(name));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* True iff the intent is a Miden bridge intent (markers in typestring and/or data).
|
|
19
|
+
* At least one of `typestring` or `data` must be provided.
|
|
20
|
+
*/
|
|
21
|
+
export function isMidenIntent(typestring, data) {
|
|
22
|
+
const hasTypestring = typestring !== undefined && typestring.trim() !== "";
|
|
23
|
+
const hasData = data !== undefined;
|
|
24
|
+
if (!hasTypestring && !hasData) {
|
|
25
|
+
throw new Error("isMidenIntent requires typestring and/or data");
|
|
26
|
+
}
|
|
27
|
+
return ((hasTypestring && hasMidenMarkersInTypestring(typestring)) ||
|
|
28
|
+
hasMidenMarkersInData(data));
|
|
29
|
+
}
|
|
30
|
+
/** EVM→Miden: recipient set, source account absent. */
|
|
31
|
+
export function isEVMToMidenIntent(data) {
|
|
32
|
+
if (!data)
|
|
33
|
+
return false;
|
|
34
|
+
return (hasTruthyField(data, MIDEN_RECIPIENT_ACCOUNT_FIELD_NAME) &&
|
|
35
|
+
!hasTruthyField(data, MIDEN_SOURCE_ACCOUNT_FIELD_NAME));
|
|
36
|
+
}
|
|
37
|
+
/** Miden→EVM: source account set. */
|
|
38
|
+
export function isMidenToEvmIntent(data) {
|
|
39
|
+
if (!data)
|
|
40
|
+
return false;
|
|
41
|
+
return hasTruthyField(data, MIDEN_SOURCE_ACCOUNT_FIELD_NAME);
|
|
42
|
+
}
|
|
43
|
+
export function hasMidenToEvmTypestringMarker(typestring) {
|
|
44
|
+
return typestring.includes(MIDEN_SOURCE_ACCOUNT_FIELD_NAME);
|
|
45
|
+
}
|
|
46
|
+
export function hasEvmToMidenTypestringMarker(typestring) {
|
|
47
|
+
return typestring.includes(MIDEN_RECIPIENT_ACCOUNT_FIELD_NAME);
|
|
48
|
+
}
|
|
49
|
+
export function resolveMidenBridgeDirection(typestring, data) {
|
|
50
|
+
const toEvm = isMidenToEvmIntent(data) || hasMidenToEvmTypestringMarker(typestring);
|
|
51
|
+
const fromEvm = isEVMToMidenIntent(data) || hasEvmToMidenTypestringMarker(typestring);
|
|
52
|
+
if (toEvm && fromEvm)
|
|
53
|
+
return "conflict";
|
|
54
|
+
if (toEvm)
|
|
55
|
+
return "miden-to-evm";
|
|
56
|
+
if (fromEvm)
|
|
57
|
+
return "evm-to-miden";
|
|
58
|
+
// Match server routing: other Miden markers without a recipient use collateral path.
|
|
59
|
+
if (isMidenIntent(typestring, data))
|
|
60
|
+
return "miden-to-evm";
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
export function getMidenMetadata(data, typestring) {
|
|
64
|
+
if (!data || !isMidenIntent(typestring, data))
|
|
65
|
+
return null;
|
|
66
|
+
return {
|
|
67
|
+
midenSourceAccount: data?.midenSourceAccount,
|
|
68
|
+
midenRecipientAccount: data?.midenRecipientAccount,
|
|
69
|
+
midenFaucetId: data?.midenFaucetId,
|
|
70
|
+
midenNoteType: data?.midenNoteType,
|
|
71
|
+
midenNoteId: data?.midenNoteId,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/** @deprecated Use {@link isEVMToMidenIntent}. */
|
|
75
|
+
export function isEVMToMidenMandate(mandate) {
|
|
76
|
+
return isEVMToMidenIntent(mandate);
|
|
77
|
+
}
|
|
78
|
+
// Re-export canonical typestrings for callers that import direction helpers here.
|
|
79
|
+
export { EVM_TO_MIDEN_EXTRA_TYPESTRING, EVM_TO_MIDEN_FIELD_NAMES, MIDEN_TO_EVM_EXTRA_TYPESTRING, MIDEN_TO_EVM_FIELD_NAMES, MIDEN_MARKER_FIELD_NAMES, };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Base Mandate fields shared by all Epoch intents (matches `getTaskData`). */
|
|
2
|
+
export declare const BASE_MANDATE_TYPESTRING = "address tokenIn,uint256 tokenInAmount,address tokenOut,uint256 minTokenOut,uint256 destinationChainId,bytes4 taskType,bytes32 protocolHashIdentifier,address recipient";
|
|
3
|
+
/** Miden → EVM cross-chain bridge witness suffix (canonical). */
|
|
4
|
+
export declare const MIDEN_TO_EVM_EXTRA_TYPESTRING = "string midenSourceAccount,string midenFaucetId,string midenNoteType,string midenNoteId";
|
|
5
|
+
/** EVM → Miden cross-chain bridge witness suffix (canonical). */
|
|
6
|
+
export declare const EVM_TO_MIDEN_EXTRA_TYPESTRING = "string midenRecipientAccount,string midenFaucetId";
|
|
7
|
+
export declare const MIDEN_TO_EVM_WITNESS_TYPESTRING = "address tokenIn,uint256 tokenInAmount,address tokenOut,uint256 minTokenOut,uint256 destinationChainId,bytes4 taskType,bytes32 protocolHashIdentifier,address recipient,string midenSourceAccount,string midenFaucetId,string midenNoteType,string midenNoteId";
|
|
8
|
+
export declare const EVM_TO_MIDEN_WITNESS_TYPESTRING = "address tokenIn,uint256 tokenInAmount,address tokenOut,uint256 minTokenOut,uint256 destinationChainId,bytes4 taskType,bytes32 protocolHashIdentifier,address recipient,string midenRecipientAccount,string midenFaucetId";
|
|
9
|
+
export declare const MIDEN_TO_EVM_FIELD_NAMES: string[];
|
|
10
|
+
export declare const EVM_TO_MIDEN_FIELD_NAMES: string[];
|
|
11
|
+
/** Union of all Miden bridge field names from the canonical extra typestrings. */
|
|
12
|
+
export declare const MIDEN_MARKER_FIELD_NAMES: string[];
|
|
13
|
+
/** Fields declared only on the Miden→EVM extra typestring. */
|
|
14
|
+
export declare const MIDEN_TO_EVM_ONLY_FIELD_NAMES: string[];
|
|
15
|
+
/** Fields declared only on the EVM→Miden extra typestring. */
|
|
16
|
+
export declare const EVM_TO_MIDEN_ONLY_FIELD_NAMES: string[];
|
|
17
|
+
export declare const MIDEN_SOURCE_ACCOUNT_FIELD_NAME: "midenSourceAccount";
|
|
18
|
+
export declare const MIDEN_RECIPIENT_ACCOUNT_FIELD_NAME: "midenRecipientAccount";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { fieldNamesFromExtraTypestring } from "./witness-typestring-parse.js";
|
|
2
|
+
function uniqueFieldNames(typestrings) {
|
|
3
|
+
return [
|
|
4
|
+
...new Set(typestrings.flatMap((typestring) => fieldNamesFromExtraTypestring(typestring))),
|
|
5
|
+
];
|
|
6
|
+
}
|
|
7
|
+
function onlyInLeft(left, right) {
|
|
8
|
+
const rightSet = new Set(right);
|
|
9
|
+
return left.filter((name) => !rightSet.has(name));
|
|
10
|
+
}
|
|
11
|
+
/** Base Mandate fields shared by all Epoch intents (matches `getTaskData`). */
|
|
12
|
+
export const BASE_MANDATE_TYPESTRING = "address tokenIn,uint256 tokenInAmount,address tokenOut,uint256 minTokenOut,uint256 destinationChainId,bytes4 taskType,bytes32 protocolHashIdentifier,address recipient";
|
|
13
|
+
/** Miden → EVM cross-chain bridge witness suffix (canonical). */
|
|
14
|
+
export const MIDEN_TO_EVM_EXTRA_TYPESTRING = "string midenSourceAccount,string midenFaucetId,string midenNoteType,string midenNoteId";
|
|
15
|
+
/** EVM → Miden cross-chain bridge witness suffix (canonical). */
|
|
16
|
+
export const EVM_TO_MIDEN_EXTRA_TYPESTRING = "string midenRecipientAccount,string midenFaucetId";
|
|
17
|
+
export const MIDEN_TO_EVM_WITNESS_TYPESTRING = `${BASE_MANDATE_TYPESTRING},${MIDEN_TO_EVM_EXTRA_TYPESTRING}`;
|
|
18
|
+
export const EVM_TO_MIDEN_WITNESS_TYPESTRING = `${BASE_MANDATE_TYPESTRING},${EVM_TO_MIDEN_EXTRA_TYPESTRING}`;
|
|
19
|
+
export const MIDEN_TO_EVM_FIELD_NAMES = fieldNamesFromExtraTypestring(MIDEN_TO_EVM_EXTRA_TYPESTRING);
|
|
20
|
+
export const EVM_TO_MIDEN_FIELD_NAMES = fieldNamesFromExtraTypestring(EVM_TO_MIDEN_EXTRA_TYPESTRING);
|
|
21
|
+
/** Union of all Miden bridge field names from the canonical extra typestrings. */
|
|
22
|
+
export const MIDEN_MARKER_FIELD_NAMES = uniqueFieldNames([
|
|
23
|
+
MIDEN_TO_EVM_EXTRA_TYPESTRING,
|
|
24
|
+
EVM_TO_MIDEN_EXTRA_TYPESTRING,
|
|
25
|
+
]);
|
|
26
|
+
/** Fields declared only on the Miden→EVM extra typestring. */
|
|
27
|
+
export const MIDEN_TO_EVM_ONLY_FIELD_NAMES = onlyInLeft(MIDEN_TO_EVM_FIELD_NAMES, EVM_TO_MIDEN_FIELD_NAMES);
|
|
28
|
+
/** Fields declared only on the EVM→Miden extra typestring. */
|
|
29
|
+
export const EVM_TO_MIDEN_ONLY_FIELD_NAMES = onlyInLeft(EVM_TO_MIDEN_FIELD_NAMES, MIDEN_TO_EVM_FIELD_NAMES);
|
|
30
|
+
export const MIDEN_SOURCE_ACCOUNT_FIELD_NAME = MIDEN_TO_EVM_ONLY_FIELD_NAMES.find((name) => name === "midenSourceAccount");
|
|
31
|
+
export const MIDEN_RECIPIENT_ACCOUNT_FIELD_NAME = EVM_TO_MIDEN_ONLY_FIELD_NAMES.find((name) => name === "midenRecipientAccount");
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function parseWitnessTypestringFields(witnessTypeString) {
|
|
2
|
+
return witnessTypeString
|
|
3
|
+
.split(",")
|
|
4
|
+
.map((field) => field.trim())
|
|
5
|
+
.filter(Boolean)
|
|
6
|
+
.map((field) => {
|
|
7
|
+
const tokens = field.split(/\s+/).filter(Boolean);
|
|
8
|
+
if (tokens.length < 2) {
|
|
9
|
+
throw new Error(`Invalid witness field "${field}" (expected "type name" in witnessTypeString)`);
|
|
10
|
+
}
|
|
11
|
+
const name = tokens[tokens.length - 1];
|
|
12
|
+
const type = tokens.slice(0, -1).join(" ");
|
|
13
|
+
return { type, name };
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export function fieldNamesFromExtraTypestring(typestring) {
|
|
17
|
+
return parseWitnessTypestringFields(typestring).map((field) => field.name);
|
|
18
|
+
}
|
|
@@ -1,35 +1,53 @@
|
|
|
1
|
+
export declare function parseWitnessTypestringFields(witnessTypeString: string): Array<{
|
|
2
|
+
type: string;
|
|
3
|
+
name: string;
|
|
4
|
+
}>;
|
|
5
|
+
export declare function fieldNamesFromExtraTypestring(typestring: string): string[];
|
|
1
6
|
/** Base Mandate fields shared by all Epoch intents (matches `getTaskData`). */
|
|
2
7
|
export declare const BASE_MANDATE_TYPESTRING = "address tokenIn,uint256 tokenInAmount,address tokenOut,uint256 minTokenOut,uint256 destinationChainId,bytes4 taskType,bytes32 protocolHashIdentifier,address recipient";
|
|
3
8
|
/** Miden → EVM cross-chain bridge witness suffix (canonical). */
|
|
4
9
|
export declare const MIDEN_TO_EVM_EXTRA_TYPESTRING = "string midenSourceAccount,string midenFaucetId,string midenNoteType,string midenNoteId";
|
|
5
10
|
/** EVM → Miden cross-chain bridge witness suffix (canonical). */
|
|
6
11
|
export declare const EVM_TO_MIDEN_EXTRA_TYPESTRING = "string midenRecipientAccount,string midenFaucetId";
|
|
7
|
-
|
|
8
|
-
export declare const
|
|
12
|
+
/** Lending DEPOSIT extraData suffix (canonical). */
|
|
13
|
+
export declare const DEPOSIT_EXTRADATA_TYPESTRING = "string marketUid,string action,string payAsset,bool isAll";
|
|
14
|
+
/** Lending WITHDRAW extraData suffix (canonical). */
|
|
15
|
+
export declare const WITHDRAW_EXTRADATA_TYPESTRING = "string marketUid,string action,string payAsset,bool isAll";
|
|
16
|
+
export declare const MIDEN_TO_EVM_FIELD_NAMES: string[];
|
|
17
|
+
export declare const EVM_TO_MIDEN_FIELD_NAMES: string[];
|
|
18
|
+
/** Union of all Miden bridge field names from the canonical extra typestrings. */
|
|
19
|
+
export declare const MIDEN_MARKER_FIELD_NAMES: string[];
|
|
20
|
+
/** Fields declared only on the Miden→EVM extra typestring. */
|
|
21
|
+
export declare const MIDEN_TO_EVM_ONLY_FIELD_NAMES: string[];
|
|
22
|
+
/** Fields declared only on the EVM→Miden extra typestring. */
|
|
23
|
+
export declare const EVM_TO_MIDEN_ONLY_FIELD_NAMES: string[];
|
|
24
|
+
export declare const MIDEN_SOURCE_ACCOUNT_FIELD_NAME: "midenSourceAccount";
|
|
25
|
+
export declare const MIDEN_RECIPIENT_ACCOUNT_FIELD_NAME: "midenRecipientAccount";
|
|
9
26
|
export type WitnessTypestringValidationResult = {
|
|
10
27
|
valid: true;
|
|
11
28
|
} | {
|
|
12
29
|
valid: false;
|
|
13
30
|
error: string;
|
|
14
31
|
};
|
|
15
|
-
export declare function parseWitnessTypestringFields(witnessTypeString: string): Array<{
|
|
16
|
-
type: string;
|
|
17
|
-
name: string;
|
|
18
|
-
}>;
|
|
19
32
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
33
|
+
* Validate Miden `extraDataTypestring` / `extraData` for task assembly.
|
|
34
|
+
* Required Miden fields must be declared and present; additional protocol fields
|
|
35
|
+
* are allowed when declared in the typestring.
|
|
36
|
+
*/
|
|
37
|
+
export declare function validateMidenExtraFields(extraDataTypestring: string, extraData?: Record<string, unknown>): WitnessTypestringValidationResult;
|
|
38
|
+
/**
|
|
39
|
+
* When a mandate includes Miden bridge metadata, the witness typestring must
|
|
40
|
+
* declare every required Miden field for the detected direction. Additional
|
|
41
|
+
* non-Miden fields may appear before or after the Miden fields.
|
|
23
42
|
*
|
|
24
43
|
* No-op for pure EVM intents — Miden checks run only when {@link isMidenIntent}.
|
|
25
44
|
*/
|
|
26
|
-
export declare function
|
|
27
|
-
export declare function isEVMToMidenMandate(mandate?: Record<string, unknown>): boolean;
|
|
45
|
+
export declare function assertMidenWitnessFields(witnessTypeString: string, mandate?: Record<string, unknown>): WitnessTypestringValidationResult;
|
|
28
46
|
/**
|
|
29
47
|
* Validates a witness typestring against its data. Handles both the full witness
|
|
30
48
|
* (base mandate + extra suffix) and a bare extra suffix — the same rules apply to
|
|
31
49
|
* either: comma spacing, "type name" format, key alignment with the data object,
|
|
32
|
-
* and
|
|
50
|
+
* and required Miden bridge fields when applicable. Pass the assembled typestring and the
|
|
33
51
|
* merged data; there is no separate extra-suffix validator.
|
|
34
52
|
*/
|
|
35
53
|
export declare function validateWitnessTypeString(witnessTypeString: string, mandate?: Record<string, unknown>): WitnessTypestringValidationResult;
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export const BASE_MANDATE_TYPESTRING = "address tokenIn,uint256 tokenInAmount,address tokenOut,uint256 minTokenOut,uint256 destinationChainId,bytes4 taskType,bytes32 protocolHashIdentifier,address recipient";
|
|
3
|
-
/** Miden → EVM cross-chain bridge witness suffix (canonical). */
|
|
4
|
-
export const MIDEN_TO_EVM_EXTRA_TYPESTRING = "string midenSourceAccount,string midenFaucetId,string midenNoteType,string midenNoteId";
|
|
5
|
-
/** EVM → Miden cross-chain bridge witness suffix (canonical). */
|
|
6
|
-
export const EVM_TO_MIDEN_EXTRA_TYPESTRING = "string midenRecipientAccount,string midenFaucetId";
|
|
7
|
-
export const MIDEN_TO_EVM_WITNESS_TYPESTRING = `${BASE_MANDATE_TYPESTRING},${MIDEN_TO_EVM_EXTRA_TYPESTRING}`;
|
|
8
|
-
export const EVM_TO_MIDEN_WITNESS_TYPESTRING = `${BASE_MANDATE_TYPESTRING},${EVM_TO_MIDEN_EXTRA_TYPESTRING}`;
|
|
1
|
+
import { isMidenIntent, resolveMidenBridgeDirection } from "./miden-intent.js";
|
|
9
2
|
export function parseWitnessTypestringFields(witnessTypeString) {
|
|
10
3
|
return witnessTypeString
|
|
11
4
|
.split(",")
|
|
@@ -21,6 +14,41 @@ export function parseWitnessTypestringFields(witnessTypeString) {
|
|
|
21
14
|
return { type, name };
|
|
22
15
|
});
|
|
23
16
|
}
|
|
17
|
+
export function fieldNamesFromExtraTypestring(typestring) {
|
|
18
|
+
return parseWitnessTypestringFields(typestring).map((field) => field.name);
|
|
19
|
+
}
|
|
20
|
+
function uniqueFieldNames(typestrings) {
|
|
21
|
+
return [
|
|
22
|
+
...new Set(typestrings.flatMap((typestring) => fieldNamesFromExtraTypestring(typestring))),
|
|
23
|
+
];
|
|
24
|
+
}
|
|
25
|
+
function onlyInLeft(left, right) {
|
|
26
|
+
const rightSet = new Set(right);
|
|
27
|
+
return left.filter((name) => !rightSet.has(name));
|
|
28
|
+
}
|
|
29
|
+
/** Base Mandate fields shared by all Epoch intents (matches `getTaskData`). */
|
|
30
|
+
export const BASE_MANDATE_TYPESTRING = "address tokenIn,uint256 tokenInAmount,address tokenOut,uint256 minTokenOut,uint256 destinationChainId,bytes4 taskType,bytes32 protocolHashIdentifier,address recipient";
|
|
31
|
+
/** Miden → EVM cross-chain bridge witness suffix (canonical). */
|
|
32
|
+
export const MIDEN_TO_EVM_EXTRA_TYPESTRING = "string midenSourceAccount,string midenFaucetId,string midenNoteType,string midenNoteId";
|
|
33
|
+
/** EVM → Miden cross-chain bridge witness suffix (canonical). */
|
|
34
|
+
export const EVM_TO_MIDEN_EXTRA_TYPESTRING = "string midenRecipientAccount,string midenFaucetId";
|
|
35
|
+
/** Lending DEPOSIT extraData suffix (canonical). */
|
|
36
|
+
export const DEPOSIT_EXTRADATA_TYPESTRING = "string marketUid,string action,string payAsset,bool isAll";
|
|
37
|
+
/** Lending WITHDRAW extraData suffix (canonical). */
|
|
38
|
+
export const WITHDRAW_EXTRADATA_TYPESTRING = "string marketUid,string action,string payAsset,bool isAll";
|
|
39
|
+
export const MIDEN_TO_EVM_FIELD_NAMES = fieldNamesFromExtraTypestring(MIDEN_TO_EVM_EXTRA_TYPESTRING);
|
|
40
|
+
export const EVM_TO_MIDEN_FIELD_NAMES = fieldNamesFromExtraTypestring(EVM_TO_MIDEN_EXTRA_TYPESTRING);
|
|
41
|
+
/** Union of all Miden bridge field names from the canonical extra typestrings. */
|
|
42
|
+
export const MIDEN_MARKER_FIELD_NAMES = uniqueFieldNames([
|
|
43
|
+
MIDEN_TO_EVM_EXTRA_TYPESTRING,
|
|
44
|
+
EVM_TO_MIDEN_EXTRA_TYPESTRING,
|
|
45
|
+
]);
|
|
46
|
+
/** Fields declared only on the Miden→EVM extra typestring. */
|
|
47
|
+
export const MIDEN_TO_EVM_ONLY_FIELD_NAMES = onlyInLeft(MIDEN_TO_EVM_FIELD_NAMES, EVM_TO_MIDEN_FIELD_NAMES);
|
|
48
|
+
/** Fields declared only on the EVM→Miden extra typestring. */
|
|
49
|
+
export const EVM_TO_MIDEN_ONLY_FIELD_NAMES = onlyInLeft(EVM_TO_MIDEN_FIELD_NAMES, MIDEN_TO_EVM_FIELD_NAMES);
|
|
50
|
+
export const MIDEN_SOURCE_ACCOUNT_FIELD_NAME = MIDEN_TO_EVM_ONLY_FIELD_NAMES.find((name) => name === "midenSourceAccount");
|
|
51
|
+
export const MIDEN_RECIPIENT_ACCOUNT_FIELD_NAME = EVM_TO_MIDEN_ONLY_FIELD_NAMES.find((name) => name === "midenRecipientAccount");
|
|
24
52
|
function assertNoSpacesAroundCommas(typestring) {
|
|
25
53
|
if (/,(\s)|(\s),/.test(typestring)) {
|
|
26
54
|
return {
|
|
@@ -63,70 +91,113 @@ function assertKeysMatchTypestring(typestring, data, dataLabel = "extraData", ty
|
|
|
63
91
|
}
|
|
64
92
|
return { valid: true };
|
|
65
93
|
}
|
|
66
|
-
function
|
|
67
|
-
return
|
|
68
|
-
|
|
94
|
+
function requiredMidenExtraTypestring(direction) {
|
|
95
|
+
return direction === "miden-to-evm"
|
|
96
|
+
? MIDEN_TO_EVM_EXTRA_TYPESTRING
|
|
97
|
+
: EVM_TO_MIDEN_EXTRA_TYPESTRING;
|
|
69
98
|
}
|
|
70
|
-
function
|
|
71
|
-
|
|
99
|
+
function assertMidenFieldsDeclared(typestring, requiredExtraTypestring, typestringLabel) {
|
|
100
|
+
const requiredFields = parseWitnessTypestringFields(requiredExtraTypestring);
|
|
101
|
+
let declaredFields;
|
|
102
|
+
try {
|
|
103
|
+
declaredFields = parseWitnessTypestringFields(typestring);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
return {
|
|
107
|
+
valid: false,
|
|
108
|
+
error: error instanceof Error
|
|
109
|
+
? error.message
|
|
110
|
+
: "Invalid witnessTypeString format",
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const declaredByName = new Map(declaredFields.map((field) => [field.name, field.type]));
|
|
114
|
+
for (const field of requiredFields) {
|
|
115
|
+
const declaredType = declaredByName.get(field.name);
|
|
116
|
+
if (declaredType === undefined) {
|
|
117
|
+
return {
|
|
118
|
+
valid: false,
|
|
119
|
+
error: `${typestringLabel} is missing required Miden field "${field.type} ${field.name}"`,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (declaredType !== field.type) {
|
|
123
|
+
return {
|
|
124
|
+
valid: false,
|
|
125
|
+
error: `${typestringLabel} field "${field.name}" must be type "${field.type}", got "${declaredType}"`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return { valid: true };
|
|
72
130
|
}
|
|
73
|
-
function
|
|
74
|
-
|
|
131
|
+
function assertMidenFieldsPresentInData(data, requiredExtraTypestring, dataLabel) {
|
|
132
|
+
const requiredNames = parseWitnessTypestringFields(requiredExtraTypestring).map((field) => field.name);
|
|
133
|
+
for (const name of requiredNames) {
|
|
134
|
+
if (!Object.prototype.hasOwnProperty.call(data, name)) {
|
|
135
|
+
return {
|
|
136
|
+
valid: false,
|
|
137
|
+
error: `${dataLabel} is missing required Miden field "${name}"`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return { valid: true };
|
|
75
142
|
}
|
|
76
|
-
function
|
|
77
|
-
|
|
78
|
-
|
|
143
|
+
function validateRequiredMidenFields(typestring, data, typestringLabel, dataLabel) {
|
|
144
|
+
const direction = resolveMidenBridgeDirection(typestring, data);
|
|
145
|
+
if (direction === "conflict") {
|
|
146
|
+
return {
|
|
147
|
+
valid: false,
|
|
148
|
+
error: "Miden witness cannot include both midenSourceAccount and midenRecipientAccount",
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
if (!direction) {
|
|
152
|
+
return {
|
|
153
|
+
valid: false,
|
|
154
|
+
error: "Unable to determine Miden bridge direction",
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const requiredExtraTypestring = requiredMidenExtraTypestring(direction);
|
|
158
|
+
const declarationCheck = assertMidenFieldsDeclared(typestring, requiredExtraTypestring, typestringLabel);
|
|
159
|
+
if (!declarationCheck.valid)
|
|
160
|
+
return declarationCheck;
|
|
161
|
+
if (!data) {
|
|
162
|
+
return {
|
|
163
|
+
valid: false,
|
|
164
|
+
error: `${dataLabel} is required for Miden intents`,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
return assertMidenFieldsPresentInData(data, requiredExtraTypestring, dataLabel);
|
|
79
168
|
}
|
|
80
169
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* validation is skipped for them.
|
|
170
|
+
* Validate Miden `extraDataTypestring` / `extraData` for task assembly.
|
|
171
|
+
* Required Miden fields must be declared and present; additional protocol fields
|
|
172
|
+
* are allowed when declared in the typestring.
|
|
85
173
|
*/
|
|
86
|
-
function
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
174
|
+
export function validateMidenExtraFields(extraDataTypestring, extraData) {
|
|
175
|
+
if (!extraDataTypestring.trim() && extraData === undefined) {
|
|
176
|
+
return { valid: true };
|
|
177
|
+
}
|
|
178
|
+
if (!isMidenIntent(extraDataTypestring, extraData)) {
|
|
179
|
+
return { valid: true };
|
|
180
|
+
}
|
|
181
|
+
return validateRequiredMidenFields(extraDataTypestring, extraData, "extraDataTypestring", "extraData");
|
|
91
182
|
}
|
|
92
183
|
/**
|
|
93
|
-
* When a mandate includes Miden bridge metadata, the witness typestring must
|
|
94
|
-
*
|
|
95
|
-
*
|
|
184
|
+
* When a mandate includes Miden bridge metadata, the witness typestring must
|
|
185
|
+
* declare every required Miden field for the detected direction. Additional
|
|
186
|
+
* non-Miden fields may appear before or after the Miden fields.
|
|
96
187
|
*
|
|
97
188
|
* No-op for pure EVM intents — Miden checks run only when {@link isMidenIntent}.
|
|
98
189
|
*/
|
|
99
|
-
export function
|
|
190
|
+
export function assertMidenWitnessFields(witnessTypeString, mandate) {
|
|
100
191
|
if (!isMidenIntent(witnessTypeString, mandate)) {
|
|
101
192
|
return { valid: true };
|
|
102
193
|
}
|
|
103
|
-
|
|
104
|
-
const fromEvm = isEvmToMidenMandate(mandate) || hasEvmToMidenSuffix(witnessTypeString);
|
|
105
|
-
if (toEvm && fromEvm) {
|
|
106
|
-
return {
|
|
107
|
-
valid: false,
|
|
108
|
-
error: "Miden witness cannot include both midenSourceAccount and midenRecipientAccount",
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
const expectedSuffix = toEvm
|
|
112
|
-
? MIDEN_TO_EVM_EXTRA_TYPESTRING
|
|
113
|
-
: EVM_TO_MIDEN_EXTRA_TYPESTRING;
|
|
114
|
-
if (!witnessTypeString.endsWith(expectedSuffix)) {
|
|
115
|
-
return {
|
|
116
|
-
valid: false,
|
|
117
|
-
error: `Invalid Miden witness suffix. Expected typestring to end with "${expectedSuffix}".`,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
return { valid: true };
|
|
121
|
-
}
|
|
122
|
-
export function isEVMToMidenMandate(mandate) {
|
|
123
|
-
return isEvmToMidenMandate(mandate);
|
|
194
|
+
return validateRequiredMidenFields(witnessTypeString, mandate, "witnessTypeString", "mandate");
|
|
124
195
|
}
|
|
125
196
|
/**
|
|
126
197
|
* Validates a witness typestring against its data. Handles both the full witness
|
|
127
198
|
* (base mandate + extra suffix) and a bare extra suffix — the same rules apply to
|
|
128
199
|
* either: comma spacing, "type name" format, key alignment with the data object,
|
|
129
|
-
* and
|
|
200
|
+
* and required Miden bridge fields when applicable. Pass the assembled typestring and the
|
|
130
201
|
* merged data; there is no separate extra-suffix validator.
|
|
131
202
|
*/
|
|
132
203
|
export function validateWitnessTypeString(witnessTypeString, mandate) {
|
|
@@ -159,7 +230,7 @@ export function validateWitnessTypeString(witnessTypeString, mandate) {
|
|
|
159
230
|
if (!keyCheck.valid)
|
|
160
231
|
return keyCheck;
|
|
161
232
|
}
|
|
162
|
-
const midenCheck =
|
|
233
|
+
const midenCheck = assertMidenWitnessFields(witnessTypeString, mandate);
|
|
163
234
|
if (!midenCheck.valid)
|
|
164
235
|
return midenCheck;
|
|
165
236
|
return { valid: true };
|