@provable-games/metagame-sdk 0.1.2 → 0.1.4
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/abis.cjs +2794 -0
- package/dist/abis.cjs.map +1 -0
- package/dist/abis.d.cts +2012 -0
- package/dist/abis.d.ts +2012 -0
- package/dist/abis.js +2786 -0
- package/dist/abis.js.map +1 -0
- package/dist/{prizeAggregation-CHwIJzXr.d.cts → client-CD-q6Alx.d.ts} +36 -2
- package/dist/{prizeAggregation-CHwIJzXr.d.ts → client-CcoKJS8i.d.cts} +36 -2
- package/dist/index.cjs +309 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +123 -3
- package/dist/index.d.ts +123 -3
- package/dist/index.js +302 -7
- package/dist/index.js.map +1 -1
- package/dist/merkle.cjs +209 -0
- package/dist/merkle.cjs.map +1 -0
- package/dist/merkle.d.cts +151 -0
- package/dist/merkle.d.ts +151 -0
- package/dist/merkle.js +200 -0
- package/dist/merkle.js.map +1 -0
- package/dist/react.cjs +243 -22
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +53 -18
- package/dist/react.d.ts +53 -18
- package/dist/react.js +242 -25
- package/dist/react.js.map +1 -1
- package/dist/rpc.cjs.map +1 -1
- package/dist/rpc.js.map +1 -1
- package/package.json +31 -11
package/dist/merkle.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { StandardMerkleTree } from '@ericnordelo/strk-merkle-tree';
|
|
2
|
+
import { hash } from 'starknet';
|
|
3
|
+
|
|
4
|
+
// src/merkle/merkleTree.ts
|
|
5
|
+
function computeLeafValue(address, count) {
|
|
6
|
+
const intermediate = hash.computePedersenHash("0x0", address);
|
|
7
|
+
return hash.computePedersenHash(intermediate, "0x" + count.toString(16));
|
|
8
|
+
}
|
|
9
|
+
function buildMerkleTree(entries) {
|
|
10
|
+
if (entries.length === 0) {
|
|
11
|
+
throw new Error("Cannot build merkle tree with no entries");
|
|
12
|
+
}
|
|
13
|
+
const leaves = entries.map((e) => [computeLeafValue(e.address, e.count)]);
|
|
14
|
+
const tree = StandardMerkleTree.of(leaves, ["felt252"], {
|
|
15
|
+
sortLeaves: true
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
version: 2,
|
|
19
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20
|
+
entries,
|
|
21
|
+
root: tree.root,
|
|
22
|
+
tree: tree.dump()
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function getProof(treeData, address, count) {
|
|
26
|
+
const tree = StandardMerkleTree.load(treeData.tree);
|
|
27
|
+
const leafValue = computeLeafValue(address, count);
|
|
28
|
+
for (const [index, leaf] of tree.entries()) {
|
|
29
|
+
if (BigInt(leaf[0]) === BigInt(leafValue)) {
|
|
30
|
+
return tree.getProof(index);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
function verifyProof(treeData, address, count, proof) {
|
|
36
|
+
const leafValue = computeLeafValue(address, count);
|
|
37
|
+
return StandardMerkleTree.verify(
|
|
38
|
+
treeData.root,
|
|
39
|
+
["felt252"],
|
|
40
|
+
[leafValue],
|
|
41
|
+
proof
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
function buildQualification(count, proof) {
|
|
45
|
+
return ["0x" + count.toString(16), ...proof];
|
|
46
|
+
}
|
|
47
|
+
function findEntry(treeData, address) {
|
|
48
|
+
return treeData.entries.find(
|
|
49
|
+
(e) => e.address.toLowerCase() === address.toLowerCase() || BigInt(e.address) === BigInt(address)
|
|
50
|
+
) || null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/merkle/client.ts
|
|
54
|
+
var DEFAULT_MERKLE_API_URLS = {
|
|
55
|
+
SN_SEPOLIA: "https://merkle-api-sepolia.up.railway.app",
|
|
56
|
+
SN_MAIN: "https://merkle-api.up.railway.app"
|
|
57
|
+
};
|
|
58
|
+
var MerkleClient = class {
|
|
59
|
+
apiUrl;
|
|
60
|
+
constructor(config) {
|
|
61
|
+
this.apiUrl = config.apiUrl ?? DEFAULT_MERKLE_API_URLS[config.chainId] ?? DEFAULT_MERKLE_API_URLS.SN_MAIN;
|
|
62
|
+
}
|
|
63
|
+
/** Fetch paginated list of merkle trees. */
|
|
64
|
+
async getTrees(options) {
|
|
65
|
+
const empty = {
|
|
66
|
+
data: [],
|
|
67
|
+
total: 0,
|
|
68
|
+
page: 1,
|
|
69
|
+
limit: 20,
|
|
70
|
+
totalPages: 0
|
|
71
|
+
};
|
|
72
|
+
try {
|
|
73
|
+
const params = new URLSearchParams();
|
|
74
|
+
if (options?.page) params.set("page", String(options.page));
|
|
75
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
76
|
+
const qs = params.toString();
|
|
77
|
+
const res = await fetch(`${this.apiUrl}/trees${qs ? `?${qs}` : ""}`);
|
|
78
|
+
if (!res.ok) return empty;
|
|
79
|
+
const json = await res.json();
|
|
80
|
+
return {
|
|
81
|
+
data: json.data ?? [],
|
|
82
|
+
total: json.total ?? 0,
|
|
83
|
+
page: json.page ?? 1,
|
|
84
|
+
limit: json.limit ?? 20,
|
|
85
|
+
totalPages: json.totalPages ?? 0
|
|
86
|
+
};
|
|
87
|
+
} catch {
|
|
88
|
+
return empty;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Fetch entries for a specific merkle tree. */
|
|
92
|
+
async getTreeEntries(treeId, options) {
|
|
93
|
+
const empty = {
|
|
94
|
+
data: [],
|
|
95
|
+
total: 0,
|
|
96
|
+
page: 1,
|
|
97
|
+
limit: 50,
|
|
98
|
+
totalPages: 0
|
|
99
|
+
};
|
|
100
|
+
try {
|
|
101
|
+
const params = new URLSearchParams();
|
|
102
|
+
if (options?.page) params.set("page", String(options.page));
|
|
103
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
104
|
+
const qs = params.toString();
|
|
105
|
+
const res = await fetch(
|
|
106
|
+
`${this.apiUrl}/trees/${treeId}/entries${qs ? `?${qs}` : ""}`
|
|
107
|
+
);
|
|
108
|
+
if (!res.ok) return empty;
|
|
109
|
+
const json = await res.json();
|
|
110
|
+
return {
|
|
111
|
+
data: json.data ?? [],
|
|
112
|
+
total: json.total ?? 0,
|
|
113
|
+
page: json.page ?? 1,
|
|
114
|
+
limit: json.limit ?? 50,
|
|
115
|
+
totalPages: json.totalPages ?? 0
|
|
116
|
+
};
|
|
117
|
+
} catch {
|
|
118
|
+
return empty;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** Fetch a merkle proof for a player address. */
|
|
122
|
+
async getProof(treeId, playerAddress) {
|
|
123
|
+
try {
|
|
124
|
+
const res = await fetch(
|
|
125
|
+
`${this.apiUrl}/trees/${treeId}/proof/${playerAddress.toLowerCase()}`
|
|
126
|
+
);
|
|
127
|
+
if (!res.ok) return null;
|
|
128
|
+
return await res.json();
|
|
129
|
+
} catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** Store a merkle tree in the API (after on-chain registration). */
|
|
134
|
+
async storeTree(request) {
|
|
135
|
+
const res = await fetch(`${this.apiUrl}/trees`, {
|
|
136
|
+
method: "POST",
|
|
137
|
+
headers: { "Content-Type": "application/json" },
|
|
138
|
+
body: JSON.stringify(request)
|
|
139
|
+
});
|
|
140
|
+
if (!res.ok) {
|
|
141
|
+
const text = await res.text();
|
|
142
|
+
throw new Error(`Failed to create merkle tree: ${text}`);
|
|
143
|
+
}
|
|
144
|
+
return await res.json();
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Build a merkle tree locally and return the calldata needed
|
|
148
|
+
* to register it on-chain via the validator contract.
|
|
149
|
+
*
|
|
150
|
+
* The consumer is responsible for executing the call with their
|
|
151
|
+
* own account/signer.
|
|
152
|
+
*/
|
|
153
|
+
buildTreeCalldata(entries, validatorAddress) {
|
|
154
|
+
const tree = buildMerkleTree(entries);
|
|
155
|
+
return {
|
|
156
|
+
tree,
|
|
157
|
+
call: {
|
|
158
|
+
contractAddress: validatorAddress,
|
|
159
|
+
entrypoint: "create_tree",
|
|
160
|
+
calldata: [tree.root]
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Parse the tree ID from transaction receipt events.
|
|
166
|
+
* Returns null if the event cannot be found.
|
|
167
|
+
*/
|
|
168
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
169
|
+
parseTreeIdFromEvents(events, validatorAddress) {
|
|
170
|
+
const validatorBigInt = BigInt(validatorAddress);
|
|
171
|
+
const treeEvent = events.find((e) => {
|
|
172
|
+
try {
|
|
173
|
+
return BigInt(e.from_address) === validatorBigInt;
|
|
174
|
+
} catch {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
if (!treeEvent?.keys?.[1]) return null;
|
|
179
|
+
return Number(BigInt(treeEvent.keys[1]));
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Store the tree in the API after on-chain registration.
|
|
183
|
+
* Pass the tree ID from the on-chain event along with the original entries.
|
|
184
|
+
*/
|
|
185
|
+
async createTree(params) {
|
|
186
|
+
return this.storeTree({
|
|
187
|
+
id: params.treeId,
|
|
188
|
+
name: params.name,
|
|
189
|
+
description: params.description,
|
|
190
|
+
entries: params.entries
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
function createMerkleClient(config) {
|
|
195
|
+
return new MerkleClient(config);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export { MerkleClient, buildMerkleTree, buildQualification, computeLeafValue, createMerkleClient, findEntry, getProof, verifyProof };
|
|
199
|
+
//# sourceMappingURL=merkle.js.map
|
|
200
|
+
//# sourceMappingURL=merkle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/merkle/merkleTree.ts","../src/merkle/client.ts"],"names":[],"mappings":"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","file":"merkle.js","sourcesContent":["import { StandardMerkleTree } from \"@ericnordelo/strk-merkle-tree\";\nimport { hash } from \"starknet\";\n\nexport interface MerkleEntry {\n address: string;\n count: number;\n}\n\nexport interface MerkleTreeData {\n version: 2;\n createdAt: string;\n entries: MerkleEntry[];\n root: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n tree: any; // StandardMerkleTree dump format\n}\n\n/**\n * Compute the leaf value that gets passed to StandardMerkleTree.\n * This matches the Cairo contract's leaf computation:\n * PedersenTrait::new(0).update(address).update(count).finalize()\n *\n * The StandardMerkleTree then applies its own leaf hashing on top:\n * H(0, value, 1) using PedersenCHasher\n */\nexport function computeLeafValue(address: string, count: number): string {\n const intermediate = hash.computePedersenHash(\"0x0\", address);\n return hash.computePedersenHash(intermediate, \"0x\" + count.toString(16));\n}\n\n/**\n * Build a StandardMerkleTree from entries.\n * Each leaf is a single felt252 value (the pre-hashed leaf value).\n */\nexport function buildMerkleTree(entries: MerkleEntry[]): MerkleTreeData {\n if (entries.length === 0) {\n throw new Error(\"Cannot build merkle tree with no entries\");\n }\n\n const leaves = entries.map((e) => [computeLeafValue(e.address, e.count)]);\n\n const tree = StandardMerkleTree.of(leaves, [\"felt252\"], {\n sortLeaves: true,\n });\n\n return {\n version: 2,\n createdAt: new Date().toISOString(),\n entries,\n root: tree.root,\n tree: tree.dump(),\n };\n}\n\n/**\n * Load a tree from saved data and get the proof for an address.\n */\nexport function getProof(\n treeData: MerkleTreeData,\n address: string,\n count: number,\n): string[] | null {\n const tree = StandardMerkleTree.load(treeData.tree);\n const leafValue = computeLeafValue(address, count);\n\n for (const [index, leaf] of tree.entries()) {\n if (BigInt(leaf[0] as string) === BigInt(leafValue)) {\n return tree.getProof(index);\n }\n }\n\n return null;\n}\n\n/**\n * Verify a proof against a root (client-side).\n */\nexport function verifyProof(\n treeData: MerkleTreeData,\n address: string,\n count: number,\n proof: string[],\n): boolean {\n const leafValue = computeLeafValue(address, count);\n return StandardMerkleTree.verify(\n treeData.root,\n [\"felt252\"],\n [leafValue],\n proof,\n );\n}\n\n/**\n * Build qualification array for contract calls: [count, ...proof]\n */\nexport function buildQualification(count: number, proof: string[]): string[] {\n return [\"0x\" + count.toString(16), ...proof];\n}\n\n/**\n * Find an entry in the tree by address.\n */\nexport function findEntry(\n treeData: MerkleTreeData,\n address: string,\n): MerkleEntry | null {\n return (\n treeData.entries.find(\n (e) =>\n e.address.toLowerCase() === address.toLowerCase() ||\n BigInt(e.address) === BigInt(address),\n ) || null\n );\n}\n","/**\n * MerkleClient — chainId-aware client for the merkle API service.\n *\n * Resolves the API URL once at construction time so callers never\n * need to pass chainId on every request.\n */\n\nimport { buildMerkleTree } from \"./merkleTree\";\nimport type { MerkleEntry } from \"./merkleTree\";\n\n// ── Default API URLs per chain ──────────────────────────────────────────────\n\nconst DEFAULT_MERKLE_API_URLS: Record<string, string> = {\n SN_SEPOLIA: \"https://merkle-api-sepolia.up.railway.app\",\n SN_MAIN: \"https://merkle-api.up.railway.app\",\n};\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\nexport interface MerkleClientConfig {\n /** Starknet chain ID, e.g. \"SN_MAIN\" or \"SN_SEPOLIA\" */\n chainId: string;\n /** Override the default API URL for this chain */\n apiUrl?: string;\n}\n\nexport interface MerkleTree {\n id: number;\n name: string;\n description: string;\n root: string;\n entryCount: number;\n createdAt: string;\n}\n\nexport interface MerkleTreesResponse {\n data: MerkleTree[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface MerkleProofResponse {\n address: string;\n count: number;\n proof: string[];\n qualification: string[];\n}\n\nexport interface MerkleTreeEntry {\n address: string;\n count: number;\n}\n\nexport interface MerkleTreeEntriesResponse {\n data: MerkleTreeEntry[];\n total: number;\n page: number;\n limit: number;\n totalPages: number;\n}\n\nexport interface CreateMerkleTreeRequest {\n id: number;\n name: string;\n description: string;\n entries: MerkleEntry[];\n}\n\nexport interface CreateMerkleTreeResponse {\n id: number;\n root: string;\n entryCount: number;\n}\n\nexport interface TreeCalldata {\n tree: ReturnType<typeof buildMerkleTree>;\n call: {\n contractAddress: string;\n entrypoint: string;\n calldata: string[];\n };\n}\n\n// ── Client ──────────────────────────────────────────────────────────────────\n\nexport class MerkleClient {\n readonly apiUrl: string;\n\n constructor(config: MerkleClientConfig) {\n this.apiUrl =\n config.apiUrl ??\n DEFAULT_MERKLE_API_URLS[config.chainId] ??\n DEFAULT_MERKLE_API_URLS.SN_MAIN;\n }\n\n /** Fetch paginated list of merkle trees. */\n async getTrees(options?: {\n page?: number;\n limit?: number;\n }): Promise<MerkleTreesResponse> {\n const empty: MerkleTreesResponse = {\n data: [],\n total: 0,\n page: 1,\n limit: 20,\n totalPages: 0,\n };\n try {\n const params = new URLSearchParams();\n if (options?.page) params.set(\"page\", String(options.page));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n const qs = params.toString();\n const res = await fetch(`${this.apiUrl}/trees${qs ? `?${qs}` : \"\"}`);\n if (!res.ok) return empty;\n const json = await res.json();\n return {\n data: json.data ?? [],\n total: json.total ?? 0,\n page: json.page ?? 1,\n limit: json.limit ?? 20,\n totalPages: json.totalPages ?? 0,\n };\n } catch {\n return empty;\n }\n }\n\n /** Fetch entries for a specific merkle tree. */\n async getTreeEntries(\n treeId: string | number,\n options?: { page?: number; limit?: number },\n ): Promise<MerkleTreeEntriesResponse> {\n const empty: MerkleTreeEntriesResponse = {\n data: [],\n total: 0,\n page: 1,\n limit: 50,\n totalPages: 0,\n };\n try {\n const params = new URLSearchParams();\n if (options?.page) params.set(\"page\", String(options.page));\n if (options?.limit) params.set(\"limit\", String(options.limit));\n const qs = params.toString();\n const res = await fetch(\n `${this.apiUrl}/trees/${treeId}/entries${qs ? `?${qs}` : \"\"}`,\n );\n if (!res.ok) return empty;\n const json = await res.json();\n return {\n data: json.data ?? [],\n total: json.total ?? 0,\n page: json.page ?? 1,\n limit: json.limit ?? 50,\n totalPages: json.totalPages ?? 0,\n };\n } catch {\n return empty;\n }\n }\n\n /** Fetch a merkle proof for a player address. */\n async getProof(\n treeId: string | number,\n playerAddress: string,\n ): Promise<MerkleProofResponse | null> {\n try {\n const res = await fetch(\n `${this.apiUrl}/trees/${treeId}/proof/${playerAddress.toLowerCase()}`,\n );\n if (!res.ok) return null;\n return await res.json();\n } catch {\n return null;\n }\n }\n\n /** Store a merkle tree in the API (after on-chain registration). */\n async storeTree(\n request: CreateMerkleTreeRequest,\n ): Promise<CreateMerkleTreeResponse> {\n const res = await fetch(`${this.apiUrl}/trees`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(request),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Failed to create merkle tree: ${text}`);\n }\n return await res.json();\n }\n\n /**\n * Build a merkle tree locally and return the calldata needed\n * to register it on-chain via the validator contract.\n *\n * The consumer is responsible for executing the call with their\n * own account/signer.\n */\n buildTreeCalldata(\n entries: MerkleEntry[],\n validatorAddress: string,\n ): TreeCalldata {\n const tree = buildMerkleTree(entries);\n return {\n tree,\n call: {\n contractAddress: validatorAddress,\n entrypoint: \"create_tree\",\n calldata: [tree.root],\n },\n };\n }\n\n /**\n * Parse the tree ID from transaction receipt events.\n * Returns null if the event cannot be found.\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n parseTreeIdFromEvents(events: any[], validatorAddress: string): number | null {\n const validatorBigInt = BigInt(validatorAddress);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const treeEvent = events.find((e: any) => {\n try {\n return BigInt(e.from_address) === validatorBigInt;\n } catch {\n return false;\n }\n });\n if (!treeEvent?.keys?.[1]) return null;\n return Number(BigInt(treeEvent.keys[1]));\n }\n\n /**\n * Store the tree in the API after on-chain registration.\n * Pass the tree ID from the on-chain event along with the original entries.\n */\n async createTree(params: {\n treeId: number;\n name: string;\n description: string;\n entries: MerkleEntry[];\n }): Promise<CreateMerkleTreeResponse> {\n return this.storeTree({\n id: params.treeId,\n name: params.name,\n description: params.description,\n entries: params.entries,\n });\n }\n}\n\n/** Factory function for creating a MerkleClient. */\nexport function createMerkleClient(config: MerkleClientConfig): MerkleClient {\n return new MerkleClient(config);\n}\n"]}
|
package/dist/react.cjs
CHANGED
|
@@ -1,9 +1,240 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var react = require('react');
|
|
4
|
+
var strkMerkleTree = require('@ericnordelo/strk-merkle-tree');
|
|
4
5
|
var starknet = require('starknet');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
7
|
|
|
6
|
-
// src/react/
|
|
8
|
+
// src/react/MetagameProvider.tsx
|
|
9
|
+
function computeLeafValue(address, count) {
|
|
10
|
+
const intermediate = starknet.hash.computePedersenHash("0x0", address);
|
|
11
|
+
return starknet.hash.computePedersenHash(intermediate, "0x" + count.toString(16));
|
|
12
|
+
}
|
|
13
|
+
function buildMerkleTree(entries) {
|
|
14
|
+
if (entries.length === 0) {
|
|
15
|
+
throw new Error("Cannot build merkle tree with no entries");
|
|
16
|
+
}
|
|
17
|
+
const leaves = entries.map((e) => [computeLeafValue(e.address, e.count)]);
|
|
18
|
+
const tree = strkMerkleTree.StandardMerkleTree.of(leaves, ["felt252"], {
|
|
19
|
+
sortLeaves: true
|
|
20
|
+
});
|
|
21
|
+
return {
|
|
22
|
+
version: 2,
|
|
23
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24
|
+
entries,
|
|
25
|
+
root: tree.root,
|
|
26
|
+
tree: tree.dump()
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/merkle/client.ts
|
|
31
|
+
var DEFAULT_MERKLE_API_URLS = {
|
|
32
|
+
SN_SEPOLIA: "https://merkle-api-sepolia.up.railway.app",
|
|
33
|
+
SN_MAIN: "https://merkle-api.up.railway.app"
|
|
34
|
+
};
|
|
35
|
+
var MerkleClient = class {
|
|
36
|
+
apiUrl;
|
|
37
|
+
constructor(config) {
|
|
38
|
+
this.apiUrl = config.apiUrl ?? DEFAULT_MERKLE_API_URLS[config.chainId] ?? DEFAULT_MERKLE_API_URLS.SN_MAIN;
|
|
39
|
+
}
|
|
40
|
+
/** Fetch paginated list of merkle trees. */
|
|
41
|
+
async getTrees(options) {
|
|
42
|
+
const empty2 = {
|
|
43
|
+
data: [],
|
|
44
|
+
total: 0,
|
|
45
|
+
page: 1,
|
|
46
|
+
limit: 20,
|
|
47
|
+
totalPages: 0
|
|
48
|
+
};
|
|
49
|
+
try {
|
|
50
|
+
const params = new URLSearchParams();
|
|
51
|
+
if (options?.page) params.set("page", String(options.page));
|
|
52
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
53
|
+
const qs = params.toString();
|
|
54
|
+
const res = await fetch(`${this.apiUrl}/trees${qs ? `?${qs}` : ""}`);
|
|
55
|
+
if (!res.ok) return empty2;
|
|
56
|
+
const json = await res.json();
|
|
57
|
+
return {
|
|
58
|
+
data: json.data ?? [],
|
|
59
|
+
total: json.total ?? 0,
|
|
60
|
+
page: json.page ?? 1,
|
|
61
|
+
limit: json.limit ?? 20,
|
|
62
|
+
totalPages: json.totalPages ?? 0
|
|
63
|
+
};
|
|
64
|
+
} catch {
|
|
65
|
+
return empty2;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** Fetch entries for a specific merkle tree. */
|
|
69
|
+
async getTreeEntries(treeId, options) {
|
|
70
|
+
const empty2 = {
|
|
71
|
+
data: [],
|
|
72
|
+
total: 0,
|
|
73
|
+
page: 1,
|
|
74
|
+
limit: 50,
|
|
75
|
+
totalPages: 0
|
|
76
|
+
};
|
|
77
|
+
try {
|
|
78
|
+
const params = new URLSearchParams();
|
|
79
|
+
if (options?.page) params.set("page", String(options.page));
|
|
80
|
+
if (options?.limit) params.set("limit", String(options.limit));
|
|
81
|
+
const qs = params.toString();
|
|
82
|
+
const res = await fetch(
|
|
83
|
+
`${this.apiUrl}/trees/${treeId}/entries${qs ? `?${qs}` : ""}`
|
|
84
|
+
);
|
|
85
|
+
if (!res.ok) return empty2;
|
|
86
|
+
const json = await res.json();
|
|
87
|
+
return {
|
|
88
|
+
data: json.data ?? [],
|
|
89
|
+
total: json.total ?? 0,
|
|
90
|
+
page: json.page ?? 1,
|
|
91
|
+
limit: json.limit ?? 50,
|
|
92
|
+
totalPages: json.totalPages ?? 0
|
|
93
|
+
};
|
|
94
|
+
} catch {
|
|
95
|
+
return empty2;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** Fetch a merkle proof for a player address. */
|
|
99
|
+
async getProof(treeId, playerAddress) {
|
|
100
|
+
try {
|
|
101
|
+
const res = await fetch(
|
|
102
|
+
`${this.apiUrl}/trees/${treeId}/proof/${playerAddress.toLowerCase()}`
|
|
103
|
+
);
|
|
104
|
+
if (!res.ok) return null;
|
|
105
|
+
return await res.json();
|
|
106
|
+
} catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** Store a merkle tree in the API (after on-chain registration). */
|
|
111
|
+
async storeTree(request) {
|
|
112
|
+
const res = await fetch(`${this.apiUrl}/trees`, {
|
|
113
|
+
method: "POST",
|
|
114
|
+
headers: { "Content-Type": "application/json" },
|
|
115
|
+
body: JSON.stringify(request)
|
|
116
|
+
});
|
|
117
|
+
if (!res.ok) {
|
|
118
|
+
const text = await res.text();
|
|
119
|
+
throw new Error(`Failed to create merkle tree: ${text}`);
|
|
120
|
+
}
|
|
121
|
+
return await res.json();
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Build a merkle tree locally and return the calldata needed
|
|
125
|
+
* to register it on-chain via the validator contract.
|
|
126
|
+
*
|
|
127
|
+
* The consumer is responsible for executing the call with their
|
|
128
|
+
* own account/signer.
|
|
129
|
+
*/
|
|
130
|
+
buildTreeCalldata(entries, validatorAddress) {
|
|
131
|
+
const tree = buildMerkleTree(entries);
|
|
132
|
+
return {
|
|
133
|
+
tree,
|
|
134
|
+
call: {
|
|
135
|
+
contractAddress: validatorAddress,
|
|
136
|
+
entrypoint: "create_tree",
|
|
137
|
+
calldata: [tree.root]
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Parse the tree ID from transaction receipt events.
|
|
143
|
+
* Returns null if the event cannot be found.
|
|
144
|
+
*/
|
|
145
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
146
|
+
parseTreeIdFromEvents(events, validatorAddress) {
|
|
147
|
+
const validatorBigInt = BigInt(validatorAddress);
|
|
148
|
+
const treeEvent = events.find((e) => {
|
|
149
|
+
try {
|
|
150
|
+
return BigInt(e.from_address) === validatorBigInt;
|
|
151
|
+
} catch {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
if (!treeEvent?.keys?.[1]) return null;
|
|
156
|
+
return Number(BigInt(treeEvent.keys[1]));
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Store the tree in the API after on-chain registration.
|
|
160
|
+
* Pass the tree ID from the on-chain event along with the original entries.
|
|
161
|
+
*/
|
|
162
|
+
async createTree(params) {
|
|
163
|
+
return this.storeTree({
|
|
164
|
+
id: params.treeId,
|
|
165
|
+
name: params.name,
|
|
166
|
+
description: params.description,
|
|
167
|
+
entries: params.entries
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// src/client.ts
|
|
173
|
+
var MetagameClient = class {
|
|
174
|
+
chainId;
|
|
175
|
+
merkle;
|
|
176
|
+
constructor(config) {
|
|
177
|
+
this.chainId = config.chainId;
|
|
178
|
+
const merkleConfig = {
|
|
179
|
+
chainId: config.chainId,
|
|
180
|
+
apiUrl: config.merkleApiUrl
|
|
181
|
+
};
|
|
182
|
+
this.merkle = new MerkleClient(merkleConfig);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
function createMetagameClient(config) {
|
|
186
|
+
return new MetagameClient(config);
|
|
187
|
+
}
|
|
188
|
+
var MetagameContext = react.createContext(null);
|
|
189
|
+
function MetagameProvider({
|
|
190
|
+
children,
|
|
191
|
+
...config
|
|
192
|
+
}) {
|
|
193
|
+
const client = react.useMemo(
|
|
194
|
+
() => createMetagameClient(config),
|
|
195
|
+
[config.chainId, config.merkleApiUrl]
|
|
196
|
+
);
|
|
197
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MetagameContext.Provider, { value: client, children });
|
|
198
|
+
}
|
|
199
|
+
function useMetagameClient() {
|
|
200
|
+
const client = react.useContext(MetagameContext);
|
|
201
|
+
if (!client) {
|
|
202
|
+
throw new Error(
|
|
203
|
+
"useMetagameClient must be used within a MetagameProvider"
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
return client;
|
|
207
|
+
}
|
|
208
|
+
function useMerkleTrees(options) {
|
|
209
|
+
const client = useMetagameClient();
|
|
210
|
+
const [data, setData] = react.useState(null);
|
|
211
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
212
|
+
react.useEffect(() => {
|
|
213
|
+
setIsLoading(true);
|
|
214
|
+
client.merkle.getTrees({ page: options?.page, limit: options?.limit }).then(setData).finally(() => setIsLoading(false));
|
|
215
|
+
}, [client, options?.page, options?.limit]);
|
|
216
|
+
return {
|
|
217
|
+
trees: data?.data ?? [],
|
|
218
|
+
total: data?.total ?? 0,
|
|
219
|
+
totalPages: data?.totalPages ?? 0,
|
|
220
|
+
page: data?.page ?? 1,
|
|
221
|
+
isLoading
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function useMerkleProof(treeId, playerAddress) {
|
|
225
|
+
const client = useMetagameClient();
|
|
226
|
+
const [proof, setProof] = react.useState(null);
|
|
227
|
+
const [isLoading, setIsLoading] = react.useState(false);
|
|
228
|
+
react.useEffect(() => {
|
|
229
|
+
if (!treeId || !playerAddress) {
|
|
230
|
+
setProof(null);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
setIsLoading(true);
|
|
234
|
+
client.merkle.getProof(treeId, playerAddress).then(setProof).finally(() => setIsLoading(false));
|
|
235
|
+
}, [client, treeId, playerAddress]);
|
|
236
|
+
return { proof, isLoading };
|
|
237
|
+
}
|
|
7
238
|
function useDebounce(value, delay) {
|
|
8
239
|
const [debouncedValue, setDebouncedValue] = react.useState(value);
|
|
9
240
|
react.useEffect(() => {
|
|
@@ -702,11 +933,7 @@ var useExtensionQualification = (provider, extensionAddress, contextId, playerAd
|
|
|
702
933
|
extensionAddress,
|
|
703
934
|
contextId,
|
|
704
935
|
playerAddress,
|
|
705
|
-
inputs: qualificationInputs.map((i) => ({
|
|
706
|
-
tid: i.tournamentId,
|
|
707
|
-
token: i.tokenId,
|
|
708
|
-
pos: i.position
|
|
709
|
-
}))
|
|
936
|
+
inputs: qualificationInputs.map((i) => ({ id: i.id, proof: i.proof }))
|
|
710
937
|
});
|
|
711
938
|
}, [enabled, provider, extensionAddress, contextId, playerAddress, qualificationInputs]);
|
|
712
939
|
const lastFetchedKey = react.useRef("");
|
|
@@ -729,36 +956,26 @@ var useExtensionQualification = (provider, extensionAddress, contextId, playerAd
|
|
|
729
956
|
const results = await Promise.all(
|
|
730
957
|
qualificationInputs.map(async (input) => {
|
|
731
958
|
try {
|
|
732
|
-
const proof = [
|
|
733
|
-
input.tournamentId,
|
|
734
|
-
input.tokenId,
|
|
735
|
-
input.position.toString()
|
|
736
|
-
];
|
|
737
959
|
const entriesLeft = await getExtensionEntriesLeft(
|
|
738
960
|
provider,
|
|
739
961
|
extensionAddress,
|
|
740
962
|
contextId,
|
|
741
963
|
playerAddress,
|
|
742
|
-
proof
|
|
964
|
+
input.proof
|
|
743
965
|
);
|
|
744
966
|
if (entriesLeft !== null && entriesLeft > 0) {
|
|
745
967
|
return {
|
|
746
|
-
id:
|
|
747
|
-
proof,
|
|
968
|
+
id: input.id,
|
|
969
|
+
proof: input.proof,
|
|
748
970
|
entriesLeft,
|
|
749
|
-
label: input.
|
|
750
|
-
metadata:
|
|
751
|
-
tournamentId: input.tournamentId,
|
|
752
|
-
tournamentName: input.tournamentName,
|
|
753
|
-
tokenId: input.tokenId,
|
|
754
|
-
position: input.position
|
|
755
|
-
}
|
|
971
|
+
label: input.label,
|
|
972
|
+
metadata: input.metadata
|
|
756
973
|
};
|
|
757
974
|
}
|
|
758
975
|
return null;
|
|
759
976
|
} catch (err) {
|
|
760
977
|
console.error(
|
|
761
|
-
`Error checking qualification
|
|
978
|
+
`Error checking qualification ${input.id}:`,
|
|
762
979
|
err
|
|
763
980
|
);
|
|
764
981
|
return null;
|
|
@@ -903,10 +1120,14 @@ var useOpusTrovesBannableEntries = (provider, games, config, enabled) => {
|
|
|
903
1120
|
};
|
|
904
1121
|
};
|
|
905
1122
|
|
|
1123
|
+
exports.MetagameProvider = MetagameProvider;
|
|
906
1124
|
exports.useDebounce = useDebounce;
|
|
907
1125
|
exports.useEntryFeePreview = useEntryFeePreview;
|
|
908
1126
|
exports.useEntryQualification = useEntryQualification;
|
|
909
1127
|
exports.useExtensionQualification = useExtensionQualification;
|
|
1128
|
+
exports.useMerkleProof = useMerkleProof;
|
|
1129
|
+
exports.useMerkleTrees = useMerkleTrees;
|
|
1130
|
+
exports.useMetagameClient = useMetagameClient;
|
|
910
1131
|
exports.useOpusTrovesBannableEntries = useOpusTrovesBannableEntries;
|
|
911
1132
|
exports.usePagination = usePagination;
|
|
912
1133
|
exports.usePrizeTable = usePrizeTable;
|