@wiimdy/openfunderse-sdk 0.1.2 → 0.1.3
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/constants.d.ts +6 -0
- package/dist/constants.js +6 -0
- package/dist/hash.d.ts +15 -2
- package/dist/hash.js +77 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/relayer-utils.js +10 -2
- package/package.json +1 -1
package/dist/hash.d.ts
CHANGED
|
@@ -4,8 +4,21 @@ export declare function intentHash(intent: TradeIntent): Hex;
|
|
|
4
4
|
export declare function snapshotHash(epochId: bigint, orderedClaimHashes: Hex[]): Hex;
|
|
5
5
|
export declare function canonicalOrderedClaimHashes(claimHashes: Hex[]): Hex[];
|
|
6
6
|
export declare function snapshotHashFromUnordered(epochId: bigint, claimHashes: Hex[]): Hex;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Deterministic Merkle root for strictly-sorted bytes32 leaves using commutative keccak256.
|
|
9
|
+
* - Leaves must be strictly sorted ascending with no duplicates.
|
|
10
|
+
* - If a layer has an odd number of nodes, the last node is duplicated.
|
|
11
|
+
*/
|
|
12
|
+
export declare function merkleRoot(orderedLeaves: Hex[]): Hex;
|
|
13
|
+
export declare function merkleRootFromUnorderedLeaves(leaves: Hex[]): Hex;
|
|
14
|
+
/**
|
|
15
|
+
* Epoch state hash used as the onchain/offchain snapshot root.
|
|
16
|
+
* Compatible with {SnapshotBook} + {IntentBook} snapshot gating.
|
|
17
|
+
*/
|
|
18
|
+
export declare function epochStateHash(epochId: bigint, orderedClaimHashes: Hex[]): Hex;
|
|
19
|
+
export declare function epochStateHashFromUnordered(epochId: bigint, claimHashes: Hex[]): Hex;
|
|
20
|
+
export declare function merkleProof(orderedLeaves: Hex[], leaf: Hex): Hex[];
|
|
21
|
+
export declare function merkleProofFromUnorderedLeaves(leaves: Hex[], leaf: Hex): Hex[];
|
|
9
22
|
export declare function reasonHash(reason: string): Hex;
|
|
10
23
|
/**
|
|
11
24
|
* Canonical allowlist hash for intent execution route.
|
package/dist/hash.js
CHANGED
|
@@ -59,8 +59,83 @@ export function snapshotHashFromUnordered(epochId, claimHashes) {
|
|
|
59
59
|
const orderedClaimHashes = canonicalOrderedClaimHashes(claimHashes);
|
|
60
60
|
return snapshotHash(epochId, orderedClaimHashes);
|
|
61
61
|
}
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
const MERKLE_NODE_PAIR = parseAbiParameters("bytes32 a, bytes32 b");
|
|
63
|
+
function merkleHashPair(a, b) {
|
|
64
|
+
const left = a.toLowerCase() < b.toLowerCase() ? a : b;
|
|
65
|
+
const right = left === a ? b : a;
|
|
66
|
+
return keccak256(encodeAbiParameters(MERKLE_NODE_PAIR, [left, right]));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Deterministic Merkle root for strictly-sorted bytes32 leaves using commutative keccak256.
|
|
70
|
+
* - Leaves must be strictly sorted ascending with no duplicates.
|
|
71
|
+
* - If a layer has an odd number of nodes, the last node is duplicated.
|
|
72
|
+
*/
|
|
73
|
+
export function merkleRoot(orderedLeaves) {
|
|
74
|
+
if (orderedLeaves.length === 0) {
|
|
75
|
+
throw new Error("leaves must not be empty");
|
|
76
|
+
}
|
|
77
|
+
assertStrictlySortedHex(orderedLeaves, "orderedLeaves");
|
|
78
|
+
let layer = [...orderedLeaves];
|
|
79
|
+
while (layer.length > 1) {
|
|
80
|
+
const next = [];
|
|
81
|
+
for (let i = 0; i < layer.length; i += 2) {
|
|
82
|
+
const left = layer[i];
|
|
83
|
+
const right = i + 1 < layer.length ? layer[i + 1] : layer[i];
|
|
84
|
+
next.push(merkleHashPair(left, right));
|
|
85
|
+
}
|
|
86
|
+
layer = next;
|
|
87
|
+
}
|
|
88
|
+
return layer[0];
|
|
89
|
+
}
|
|
90
|
+
export function merkleRootFromUnorderedLeaves(leaves) {
|
|
91
|
+
const ordered = uniqueSortedBytes32Hex(leaves);
|
|
92
|
+
return merkleRoot(ordered);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Epoch state hash used as the onchain/offchain snapshot root.
|
|
96
|
+
* Compatible with {SnapshotBook} + {IntentBook} snapshot gating.
|
|
97
|
+
*/
|
|
98
|
+
export function epochStateHash(epochId, orderedClaimHashes) {
|
|
99
|
+
assertUint64(epochId, "epochId");
|
|
100
|
+
return merkleRoot(orderedClaimHashes);
|
|
101
|
+
}
|
|
102
|
+
export function epochStateHashFromUnordered(epochId, claimHashes) {
|
|
103
|
+
assertUint64(epochId, "epochId");
|
|
104
|
+
const ordered = canonicalOrderedClaimHashes(claimHashes);
|
|
105
|
+
return merkleRoot(ordered);
|
|
106
|
+
}
|
|
107
|
+
export function merkleProof(orderedLeaves, leaf) {
|
|
108
|
+
assertStrictlySortedHex(orderedLeaves, "orderedLeaves");
|
|
109
|
+
if (orderedLeaves.length === 0) {
|
|
110
|
+
throw new Error("orderedLeaves must not be empty");
|
|
111
|
+
}
|
|
112
|
+
const normalizedLeaf = leaf.toLowerCase();
|
|
113
|
+
const index0 = orderedLeaves.findIndex((entry) => entry.toLowerCase() === normalizedLeaf);
|
|
114
|
+
if (index0 < 0) {
|
|
115
|
+
throw new Error("leaf not found in orderedLeaves");
|
|
116
|
+
}
|
|
117
|
+
const proof = [];
|
|
118
|
+
let index = index0;
|
|
119
|
+
let layer = [...orderedLeaves];
|
|
120
|
+
while (layer.length > 1) {
|
|
121
|
+
const siblingIndex = index ^ 1; // toggle last bit
|
|
122
|
+
const sibling = siblingIndex < layer.length ? layer[siblingIndex] : layer[index];
|
|
123
|
+
proof.push(sibling);
|
|
124
|
+
const next = [];
|
|
125
|
+
for (let i = 0; i < layer.length; i += 2) {
|
|
126
|
+
const left = layer[i];
|
|
127
|
+
const right = i + 1 < layer.length ? layer[i + 1] : layer[i];
|
|
128
|
+
next.push(merkleHashPair(left, right));
|
|
129
|
+
}
|
|
130
|
+
layer = next;
|
|
131
|
+
index = Math.floor(index / 2);
|
|
132
|
+
}
|
|
133
|
+
return proof;
|
|
134
|
+
}
|
|
135
|
+
export function merkleProofFromUnorderedLeaves(leaves, leaf) {
|
|
136
|
+
const ordered = uniqueSortedBytes32Hex(leaves);
|
|
137
|
+
return merkleProof(ordered, leaf);
|
|
138
|
+
}
|
|
64
139
|
export function reasonHash(reason) {
|
|
65
140
|
return keccak256(toHex(reason.normalize("NFC").trim()));
|
|
66
141
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/relayer-utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { keccak256 } from "viem";
|
|
2
2
|
import { canonicalAllocationClaim, canonicalIntent } from "./canonical.js";
|
|
3
|
-
import {
|
|
3
|
+
import { CLAIM_WEIGHT_SCALE } from "./constants.js";
|
|
4
|
+
import { allocationClaimHash, intentExecutionAllowlistHash, intentHash, epochStateHashFromUnordered } from "./hash.js";
|
|
4
5
|
import { assertUint16, assertUint64 } from "./validate.js";
|
|
5
6
|
function assertPositive(value, label) {
|
|
6
7
|
if (value <= 0n) {
|
|
@@ -18,6 +19,12 @@ function assertWeightsSumPositive(weights) {
|
|
|
18
19
|
throw new Error("targetWeights sum must be positive");
|
|
19
20
|
}
|
|
20
21
|
}
|
|
22
|
+
function assertWeightsSumEqualsScale(weights) {
|
|
23
|
+
const sum = weights.reduce((acc, w) => acc + w, 0n);
|
|
24
|
+
if (sum !== CLAIM_WEIGHT_SCALE) {
|
|
25
|
+
throw new Error(`targetWeights sum must equal CLAIM_WEIGHT_SCALE (${CLAIM_WEIGHT_SCALE}), got ${sum}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
21
28
|
export function buildCanonicalAllocationClaimRecord(input) {
|
|
22
29
|
assertUint64(input.claim.epochId, "epochId");
|
|
23
30
|
assertUint64(input.claim.horizonSec, "horizonSec");
|
|
@@ -35,6 +42,7 @@ export function buildCanonicalAllocationClaimRecord(input) {
|
|
|
35
42
|
}
|
|
36
43
|
});
|
|
37
44
|
assertWeightsSumPositive(claim.targetWeights);
|
|
45
|
+
assertWeightsSumEqualsScale(claim.targetWeights);
|
|
38
46
|
return {
|
|
39
47
|
claim,
|
|
40
48
|
claimHash: allocationClaimHash(claim)
|
|
@@ -78,7 +86,7 @@ export function buildEpochStateRecord(input) {
|
|
|
78
86
|
if (input.claimHashes.length === 0) {
|
|
79
87
|
throw new Error("claimHashes must not be empty");
|
|
80
88
|
}
|
|
81
|
-
const hash =
|
|
89
|
+
const hash = epochStateHashFromUnordered(input.epochId, input.claimHashes);
|
|
82
90
|
return {
|
|
83
91
|
epochId: input.epochId,
|
|
84
92
|
epochStateHash: hash
|