@medialane/sdk 0.1.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 +380 -0
- package/dist/index.cjs +1154 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +922 -0
- package/dist/index.d.ts +922 -0
- package/dist/index.js +1130 -0
- package/dist/index.js.map +1 -0
- package/package.json +37 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1130 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { TypedDataRevision, shortString, cairo, Contract, constants, RpcProvider, byteArray, num } from 'starknet';
|
|
3
|
+
|
|
4
|
+
// src/config.ts
|
|
5
|
+
|
|
6
|
+
// src/constants.ts
|
|
7
|
+
var MARKETPLACE_CONTRACT_MAINNET = "0x059deafbbafbf7051c315cf75a94b03c5547892bc0c6dfa36d7ac7290d4cc33a";
|
|
8
|
+
var COLLECTION_CONTRACT_MAINNET = "0x05e73b7be06d82beeb390a0e0d655f2c9e7cf519658e04f05d9c690ccc41da03";
|
|
9
|
+
var SUPPORTED_TOKENS = [
|
|
10
|
+
{
|
|
11
|
+
// Circle-native USDC on Starknet (canonical)
|
|
12
|
+
symbol: "USDC",
|
|
13
|
+
address: "0x033068f6539f8e6e6b131e6b2b814e6c34a5224bc66947c47dab9dfee93b35fb",
|
|
14
|
+
decimals: 6
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
symbol: "USDT",
|
|
18
|
+
address: "0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8",
|
|
19
|
+
decimals: 6
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
symbol: "ETH",
|
|
23
|
+
address: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
|
|
24
|
+
decimals: 18
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
symbol: "STRK",
|
|
28
|
+
address: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
|
|
29
|
+
decimals: 18
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
var DEFAULT_CURRENCY = "USDC";
|
|
33
|
+
var SUPPORTED_NETWORKS = ["mainnet", "sepolia"];
|
|
34
|
+
var DEFAULT_RPC_URLS = {
|
|
35
|
+
mainnet: "https://starknet-mainnet.public.blastapi.io",
|
|
36
|
+
sepolia: "https://starknet-sepolia.public.blastapi.io"
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// src/config.ts
|
|
40
|
+
var MedialaneConfigSchema = z.object({
|
|
41
|
+
network: z.enum(SUPPORTED_NETWORKS).default("mainnet"),
|
|
42
|
+
rpcUrl: z.string().url().optional(),
|
|
43
|
+
backendUrl: z.string().url().optional(),
|
|
44
|
+
/** API key for authenticated /v1/* backend endpoints */
|
|
45
|
+
apiKey: z.string().optional(),
|
|
46
|
+
marketplaceContract: z.string().optional(),
|
|
47
|
+
collectionContract: z.string().optional()
|
|
48
|
+
});
|
|
49
|
+
function resolveConfig(raw) {
|
|
50
|
+
const parsed = MedialaneConfigSchema.parse(raw);
|
|
51
|
+
return {
|
|
52
|
+
network: parsed.network,
|
|
53
|
+
rpcUrl: parsed.rpcUrl ?? DEFAULT_RPC_URLS[parsed.network],
|
|
54
|
+
backendUrl: parsed.backendUrl,
|
|
55
|
+
apiKey: parsed.apiKey,
|
|
56
|
+
marketplaceContract: parsed.marketplaceContract ?? MARKETPLACE_CONTRACT_MAINNET,
|
|
57
|
+
collectionContract: parsed.collectionContract ?? COLLECTION_CONTRACT_MAINNET
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function buildOrderTypedData(message, chainId) {
|
|
61
|
+
return {
|
|
62
|
+
domain: {
|
|
63
|
+
name: "Medialane",
|
|
64
|
+
version: "1",
|
|
65
|
+
chainId,
|
|
66
|
+
revision: TypedDataRevision.ACTIVE
|
|
67
|
+
},
|
|
68
|
+
primaryType: "OrderParameters",
|
|
69
|
+
types: {
|
|
70
|
+
StarknetDomain: [
|
|
71
|
+
{ name: "name", type: "shortstring" },
|
|
72
|
+
{ name: "version", type: "shortstring" },
|
|
73
|
+
{ name: "chainId", type: "shortstring" },
|
|
74
|
+
{ name: "revision", type: "shortstring" }
|
|
75
|
+
],
|
|
76
|
+
OrderParameters: [
|
|
77
|
+
{ name: "offerer", type: "ContractAddress" },
|
|
78
|
+
{ name: "offer", type: "OfferItem" },
|
|
79
|
+
{ name: "consideration", type: "ConsiderationItem" },
|
|
80
|
+
{ name: "start_time", type: "felt" },
|
|
81
|
+
{ name: "end_time", type: "felt" },
|
|
82
|
+
{ name: "salt", type: "felt" },
|
|
83
|
+
{ name: "nonce", type: "felt" }
|
|
84
|
+
],
|
|
85
|
+
OfferItem: [
|
|
86
|
+
{ name: "item_type", type: "shortstring" },
|
|
87
|
+
{ name: "token", type: "ContractAddress" },
|
|
88
|
+
{ name: "identifier_or_criteria", type: "felt" },
|
|
89
|
+
{ name: "start_amount", type: "felt" },
|
|
90
|
+
{ name: "end_amount", type: "felt" }
|
|
91
|
+
],
|
|
92
|
+
ConsiderationItem: [
|
|
93
|
+
{ name: "item_type", type: "shortstring" },
|
|
94
|
+
{ name: "token", type: "ContractAddress" },
|
|
95
|
+
{ name: "identifier_or_criteria", type: "felt" },
|
|
96
|
+
{ name: "start_amount", type: "felt" },
|
|
97
|
+
{ name: "end_amount", type: "felt" },
|
|
98
|
+
{ name: "recipient", type: "ContractAddress" }
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
message
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function buildFulfillmentTypedData(message, chainId) {
|
|
105
|
+
return {
|
|
106
|
+
domain: {
|
|
107
|
+
name: "Medialane",
|
|
108
|
+
version: "1",
|
|
109
|
+
chainId,
|
|
110
|
+
revision: TypedDataRevision.ACTIVE
|
|
111
|
+
},
|
|
112
|
+
primaryType: "OrderFulfillment",
|
|
113
|
+
types: {
|
|
114
|
+
StarknetDomain: [
|
|
115
|
+
{ name: "name", type: "shortstring" },
|
|
116
|
+
{ name: "version", type: "shortstring" },
|
|
117
|
+
{ name: "chainId", type: "shortstring" },
|
|
118
|
+
{ name: "revision", type: "shortstring" }
|
|
119
|
+
],
|
|
120
|
+
OrderFulfillment: [
|
|
121
|
+
{ name: "order_hash", type: "felt" },
|
|
122
|
+
{ name: "fulfiller", type: "ContractAddress" },
|
|
123
|
+
{ name: "nonce", type: "felt" }
|
|
124
|
+
]
|
|
125
|
+
},
|
|
126
|
+
message
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function buildCancellationTypedData(message, chainId) {
|
|
130
|
+
return {
|
|
131
|
+
domain: {
|
|
132
|
+
name: "Medialane",
|
|
133
|
+
version: "1",
|
|
134
|
+
chainId,
|
|
135
|
+
revision: TypedDataRevision.ACTIVE
|
|
136
|
+
},
|
|
137
|
+
primaryType: "OrderCancellation",
|
|
138
|
+
types: {
|
|
139
|
+
StarknetDomain: [
|
|
140
|
+
{ name: "name", type: "shortstring" },
|
|
141
|
+
{ name: "version", type: "shortstring" },
|
|
142
|
+
{ name: "chainId", type: "shortstring" },
|
|
143
|
+
{ name: "revision", type: "shortstring" }
|
|
144
|
+
],
|
|
145
|
+
OrderCancellation: [
|
|
146
|
+
{ name: "order_hash", type: "felt" },
|
|
147
|
+
{ name: "offerer", type: "ContractAddress" },
|
|
148
|
+
{ name: "nonce", type: "felt" }
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
message
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// src/abis.ts
|
|
156
|
+
var IPMarketplaceABI = [
|
|
157
|
+
{
|
|
158
|
+
type: "impl",
|
|
159
|
+
name: "UpgradeableImpl",
|
|
160
|
+
interface_name: "openzeppelin_upgrades::interface::IUpgradeable"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
type: "interface",
|
|
164
|
+
name: "openzeppelin_upgrades::interface::IUpgradeable",
|
|
165
|
+
items: [
|
|
166
|
+
{
|
|
167
|
+
type: "function",
|
|
168
|
+
name: "upgrade",
|
|
169
|
+
inputs: [{ name: "new_class_hash", type: "core::starknet::class_hash::ClassHash" }],
|
|
170
|
+
outputs: [],
|
|
171
|
+
state_mutability: "external"
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
type: "impl",
|
|
177
|
+
name: "MedialaneImpl",
|
|
178
|
+
interface_name: "mediolano_core::core::interface::IMedialane"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
type: "struct",
|
|
182
|
+
name: "mediolano_core::core::types::OfferItem",
|
|
183
|
+
members: [
|
|
184
|
+
{ name: "item_type", type: "core::felt252" },
|
|
185
|
+
{ name: "token", type: "core::starknet::contract_address::ContractAddress" },
|
|
186
|
+
{ name: "identifier_or_criteria", type: "core::felt252" },
|
|
187
|
+
{ name: "start_amount", type: "core::felt252" },
|
|
188
|
+
{ name: "end_amount", type: "core::felt252" }
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
type: "struct",
|
|
193
|
+
name: "mediolano_core::core::types::ConsiderationItem",
|
|
194
|
+
members: [
|
|
195
|
+
{ name: "item_type", type: "core::felt252" },
|
|
196
|
+
{ name: "token", type: "core::starknet::contract_address::ContractAddress" },
|
|
197
|
+
{ name: "identifier_or_criteria", type: "core::felt252" },
|
|
198
|
+
{ name: "start_amount", type: "core::felt252" },
|
|
199
|
+
{ name: "end_amount", type: "core::felt252" },
|
|
200
|
+
{ name: "recipient", type: "core::starknet::contract_address::ContractAddress" }
|
|
201
|
+
]
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
type: "struct",
|
|
205
|
+
name: "mediolano_core::core::types::OrderParameters",
|
|
206
|
+
members: [
|
|
207
|
+
{ name: "offerer", type: "core::starknet::contract_address::ContractAddress" },
|
|
208
|
+
{ name: "offer", type: "mediolano_core::core::types::OfferItem" },
|
|
209
|
+
{ name: "consideration", type: "mediolano_core::core::types::ConsiderationItem" },
|
|
210
|
+
{ name: "start_time", type: "core::felt252" },
|
|
211
|
+
{ name: "end_time", type: "core::felt252" },
|
|
212
|
+
{ name: "salt", type: "core::felt252" },
|
|
213
|
+
{ name: "nonce", type: "core::felt252" }
|
|
214
|
+
]
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
type: "struct",
|
|
218
|
+
name: "mediolano_core::core::types::Order",
|
|
219
|
+
members: [
|
|
220
|
+
{ name: "parameters", type: "mediolano_core::core::types::OrderParameters" },
|
|
221
|
+
{ name: "signature", type: "core::array::Array::<core::felt252>" }
|
|
222
|
+
]
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
type: "struct",
|
|
226
|
+
name: "mediolano_core::core::types::OrderFulfillment",
|
|
227
|
+
members: [
|
|
228
|
+
{ name: "order_hash", type: "core::felt252" },
|
|
229
|
+
{ name: "fulfiller", type: "core::starknet::contract_address::ContractAddress" },
|
|
230
|
+
{ name: "nonce", type: "core::felt252" }
|
|
231
|
+
]
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
type: "struct",
|
|
235
|
+
name: "mediolano_core::core::types::FulfillmentRequest",
|
|
236
|
+
members: [
|
|
237
|
+
{ name: "fulfillment", type: "mediolano_core::core::types::OrderFulfillment" },
|
|
238
|
+
{ name: "signature", type: "core::array::Array::<core::felt252>" }
|
|
239
|
+
]
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
type: "struct",
|
|
243
|
+
name: "mediolano_core::core::types::OrderCancellation",
|
|
244
|
+
members: [
|
|
245
|
+
{ name: "order_hash", type: "core::felt252" },
|
|
246
|
+
{ name: "offerer", type: "core::starknet::contract_address::ContractAddress" },
|
|
247
|
+
{ name: "nonce", type: "core::felt252" }
|
|
248
|
+
]
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
type: "struct",
|
|
252
|
+
name: "mediolano_core::core::types::CancelRequest",
|
|
253
|
+
members: [
|
|
254
|
+
{ name: "cancelation", type: "mediolano_core::core::types::OrderCancellation" },
|
|
255
|
+
{ name: "signature", type: "core::array::Array::<core::felt252>" }
|
|
256
|
+
]
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
type: "enum",
|
|
260
|
+
name: "mediolano_core::core::types::OrderStatus",
|
|
261
|
+
variants: [
|
|
262
|
+
{ name: "None", type: "()" },
|
|
263
|
+
{ name: "Created", type: "()" },
|
|
264
|
+
{ name: "Filled", type: "()" },
|
|
265
|
+
{ name: "Cancelled", type: "()" }
|
|
266
|
+
]
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
type: "enum",
|
|
270
|
+
name: "core::option::Option::<core::starknet::contract_address::ContractAddress>",
|
|
271
|
+
variants: [
|
|
272
|
+
{ name: "Some", type: "core::starknet::contract_address::ContractAddress" },
|
|
273
|
+
{ name: "None", type: "()" }
|
|
274
|
+
]
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
type: "struct",
|
|
278
|
+
name: "mediolano_core::core::types::OrderDetails",
|
|
279
|
+
members: [
|
|
280
|
+
{ name: "offerer", type: "core::starknet::contract_address::ContractAddress" },
|
|
281
|
+
{ name: "offer", type: "mediolano_core::core::types::OfferItem" },
|
|
282
|
+
{ name: "consideration", type: "mediolano_core::core::types::ConsiderationItem" },
|
|
283
|
+
{ name: "start_time", type: "core::integer::u64" },
|
|
284
|
+
{ name: "end_time", type: "core::integer::u64" },
|
|
285
|
+
{ name: "order_status", type: "mediolano_core::core::types::OrderStatus" },
|
|
286
|
+
{
|
|
287
|
+
name: "fulfiller",
|
|
288
|
+
type: "core::option::Option::<core::starknet::contract_address::ContractAddress>"
|
|
289
|
+
}
|
|
290
|
+
]
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
type: "interface",
|
|
294
|
+
name: "mediolano_core::core::interface::IMedialane",
|
|
295
|
+
items: [
|
|
296
|
+
{
|
|
297
|
+
type: "function",
|
|
298
|
+
name: "register_order",
|
|
299
|
+
inputs: [{ name: "order", type: "mediolano_core::core::types::Order" }],
|
|
300
|
+
outputs: [],
|
|
301
|
+
state_mutability: "external"
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
type: "function",
|
|
305
|
+
name: "fulfill_order",
|
|
306
|
+
inputs: [
|
|
307
|
+
{
|
|
308
|
+
name: "fulfillment_request",
|
|
309
|
+
type: "mediolano_core::core::types::FulfillmentRequest"
|
|
310
|
+
}
|
|
311
|
+
],
|
|
312
|
+
outputs: [],
|
|
313
|
+
state_mutability: "external"
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
type: "function",
|
|
317
|
+
name: "cancel_order",
|
|
318
|
+
inputs: [{ name: "cancel_request", type: "mediolano_core::core::types::CancelRequest" }],
|
|
319
|
+
outputs: [],
|
|
320
|
+
state_mutability: "external"
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
type: "function",
|
|
324
|
+
name: "get_order_details",
|
|
325
|
+
inputs: [{ name: "order_hash", type: "core::felt252" }],
|
|
326
|
+
outputs: [{ type: "mediolano_core::core::types::OrderDetails" }],
|
|
327
|
+
state_mutability: "view"
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
type: "function",
|
|
331
|
+
name: "get_order_hash",
|
|
332
|
+
inputs: [
|
|
333
|
+
{ name: "parameters", type: "mediolano_core::core::types::OrderParameters" },
|
|
334
|
+
{ name: "signer", type: "core::starknet::contract_address::ContractAddress" }
|
|
335
|
+
],
|
|
336
|
+
outputs: [{ type: "core::felt252" }],
|
|
337
|
+
state_mutability: "view"
|
|
338
|
+
}
|
|
339
|
+
]
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
type: "impl",
|
|
343
|
+
name: "NoncesImpl",
|
|
344
|
+
interface_name: "openzeppelin_utils::cryptography::interface::INonces"
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
type: "interface",
|
|
348
|
+
name: "openzeppelin_utils::cryptography::interface::INonces",
|
|
349
|
+
items: [
|
|
350
|
+
{
|
|
351
|
+
type: "function",
|
|
352
|
+
name: "nonces",
|
|
353
|
+
inputs: [
|
|
354
|
+
{ name: "owner", type: "core::starknet::contract_address::ContractAddress" }
|
|
355
|
+
],
|
|
356
|
+
outputs: [{ type: "core::felt252" }],
|
|
357
|
+
state_mutability: "view"
|
|
358
|
+
}
|
|
359
|
+
]
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
type: "impl",
|
|
363
|
+
name: "SRC5Impl",
|
|
364
|
+
interface_name: "openzeppelin_introspection::interface::ISRC5"
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
type: "enum",
|
|
368
|
+
name: "core::bool",
|
|
369
|
+
variants: [
|
|
370
|
+
{ name: "False", type: "()" },
|
|
371
|
+
{ name: "True", type: "()" }
|
|
372
|
+
]
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
type: "interface",
|
|
376
|
+
name: "openzeppelin_introspection::interface::ISRC5",
|
|
377
|
+
items: [
|
|
378
|
+
{
|
|
379
|
+
type: "function",
|
|
380
|
+
name: "supports_interface",
|
|
381
|
+
inputs: [{ name: "interface_id", type: "core::felt252" }],
|
|
382
|
+
outputs: [{ type: "core::bool" }],
|
|
383
|
+
state_mutability: "view"
|
|
384
|
+
}
|
|
385
|
+
]
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
type: "constructor",
|
|
389
|
+
name: "constructor",
|
|
390
|
+
inputs: [
|
|
391
|
+
{ name: "manager", type: "core::starknet::contract_address::ContractAddress" },
|
|
392
|
+
{ name: "native_token_address", type: "core::starknet::contract_address::ContractAddress" }
|
|
393
|
+
]
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
type: "event",
|
|
397
|
+
name: "mediolano_core::core::events::OrderCreated",
|
|
398
|
+
kind: "struct",
|
|
399
|
+
members: [
|
|
400
|
+
{ name: "order_hash", type: "core::felt252", kind: "key" },
|
|
401
|
+
{
|
|
402
|
+
name: "offerer",
|
|
403
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
404
|
+
kind: "key"
|
|
405
|
+
}
|
|
406
|
+
]
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
type: "event",
|
|
410
|
+
name: "mediolano_core::core::events::OrderFulfilled",
|
|
411
|
+
kind: "struct",
|
|
412
|
+
members: [
|
|
413
|
+
{ name: "order_hash", type: "core::felt252", kind: "key" },
|
|
414
|
+
{
|
|
415
|
+
name: "offerer",
|
|
416
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
417
|
+
kind: "key"
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
name: "fulfiller",
|
|
421
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
422
|
+
kind: "key"
|
|
423
|
+
}
|
|
424
|
+
]
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
type: "event",
|
|
428
|
+
name: "mediolano_core::core::events::OrderCancelled",
|
|
429
|
+
kind: "struct",
|
|
430
|
+
members: [
|
|
431
|
+
{ name: "order_hash", type: "core::felt252", kind: "key" },
|
|
432
|
+
{
|
|
433
|
+
name: "offerer",
|
|
434
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
435
|
+
kind: "key"
|
|
436
|
+
}
|
|
437
|
+
]
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
type: "event",
|
|
441
|
+
name: "mediolano_core::core::medialane::Medialane::Event",
|
|
442
|
+
kind: "enum",
|
|
443
|
+
variants: [
|
|
444
|
+
{
|
|
445
|
+
name: "OrderCreated",
|
|
446
|
+
type: "mediolano_core::core::events::OrderCreated",
|
|
447
|
+
kind: "nested"
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
name: "OrderFulfilled",
|
|
451
|
+
type: "mediolano_core::core::events::OrderFulfilled",
|
|
452
|
+
kind: "nested"
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
name: "OrderCancelled",
|
|
456
|
+
type: "mediolano_core::core::events::OrderCancelled",
|
|
457
|
+
kind: "nested"
|
|
458
|
+
}
|
|
459
|
+
]
|
|
460
|
+
}
|
|
461
|
+
];
|
|
462
|
+
|
|
463
|
+
// src/utils/bigint.ts
|
|
464
|
+
function stringifyBigInts(obj) {
|
|
465
|
+
if (typeof obj === "bigint") {
|
|
466
|
+
return obj.toString();
|
|
467
|
+
}
|
|
468
|
+
if (Array.isArray(obj)) {
|
|
469
|
+
return obj.map(stringifyBigInts);
|
|
470
|
+
}
|
|
471
|
+
if (obj !== null && typeof obj === "object") {
|
|
472
|
+
return Object.fromEntries(
|
|
473
|
+
Object.entries(obj).map(([key, value]) => [
|
|
474
|
+
key,
|
|
475
|
+
stringifyBigInts(value)
|
|
476
|
+
])
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
return obj;
|
|
480
|
+
}
|
|
481
|
+
function u256ToBigInt(low, high) {
|
|
482
|
+
return BigInt(low) + (BigInt(high) << 128n);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// src/utils/token.ts
|
|
486
|
+
function parseAmount(human, decimals) {
|
|
487
|
+
const [whole, frac = ""] = human.split(".");
|
|
488
|
+
const fracPadded = frac.padEnd(decimals, "0").slice(0, decimals);
|
|
489
|
+
return (BigInt(whole) * BigInt(10) ** BigInt(decimals) + BigInt(fracPadded)).toString();
|
|
490
|
+
}
|
|
491
|
+
function formatAmount(raw, decimals) {
|
|
492
|
+
const value = BigInt(raw);
|
|
493
|
+
const factor = BigInt(Math.pow(10, decimals));
|
|
494
|
+
const whole = value / factor;
|
|
495
|
+
const remainder = value % factor;
|
|
496
|
+
const fractional = remainder.toString().padStart(decimals, "0");
|
|
497
|
+
return `${whole}.${fractional}`;
|
|
498
|
+
}
|
|
499
|
+
function getTokenByAddress(address) {
|
|
500
|
+
const lower = address.toLowerCase();
|
|
501
|
+
return SUPPORTED_TOKENS.find((t) => t.address.toLowerCase() === lower);
|
|
502
|
+
}
|
|
503
|
+
function getTokenBySymbol(symbol) {
|
|
504
|
+
const upper = symbol.toUpperCase();
|
|
505
|
+
return SUPPORTED_TOKENS.find((t) => t.symbol === upper);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// src/marketplace/orders.ts
|
|
509
|
+
var MedialaneError = class extends Error {
|
|
510
|
+
constructor(message, cause) {
|
|
511
|
+
super(message);
|
|
512
|
+
this.cause = cause;
|
|
513
|
+
this.name = "MedialaneError";
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
function toSignatureArray(sig) {
|
|
517
|
+
if (Array.isArray(sig)) return sig;
|
|
518
|
+
const s = sig;
|
|
519
|
+
return [s.r.toString(), s.s.toString()];
|
|
520
|
+
}
|
|
521
|
+
function getChainId(config) {
|
|
522
|
+
return config.network === "mainnet" ? constants.StarknetChainId.SN_MAIN : constants.StarknetChainId.SN_SEPOLIA;
|
|
523
|
+
}
|
|
524
|
+
var _contractCache = /* @__PURE__ */ new WeakMap();
|
|
525
|
+
var _providerCache = /* @__PURE__ */ new WeakMap();
|
|
526
|
+
function getProvider(config) {
|
|
527
|
+
let provider = _providerCache.get(config);
|
|
528
|
+
if (!provider) {
|
|
529
|
+
provider = new RpcProvider({ nodeUrl: config.rpcUrl });
|
|
530
|
+
_providerCache.set(config, provider);
|
|
531
|
+
}
|
|
532
|
+
return provider;
|
|
533
|
+
}
|
|
534
|
+
function makeContract(config) {
|
|
535
|
+
const cached = _contractCache.get(config);
|
|
536
|
+
if (cached) return cached;
|
|
537
|
+
const provider = getProvider(config);
|
|
538
|
+
const contract = new Contract(
|
|
539
|
+
IPMarketplaceABI,
|
|
540
|
+
config.marketplaceContract,
|
|
541
|
+
provider
|
|
542
|
+
);
|
|
543
|
+
const result = { contract, provider };
|
|
544
|
+
_contractCache.set(config, result);
|
|
545
|
+
return result;
|
|
546
|
+
}
|
|
547
|
+
function resolveToken(currency) {
|
|
548
|
+
const token = SUPPORTED_TOKENS.find(
|
|
549
|
+
(t) => t.symbol === currency.toUpperCase() || t.address.toLowerCase() === currency.toLowerCase()
|
|
550
|
+
);
|
|
551
|
+
if (!token) throw new MedialaneError(`Unsupported currency: ${currency}`);
|
|
552
|
+
return token;
|
|
553
|
+
}
|
|
554
|
+
async function createListing(account, params, config) {
|
|
555
|
+
const { nftContract, tokenId, price, currency = DEFAULT_CURRENCY, durationSeconds } = params;
|
|
556
|
+
const { contract, provider } = makeContract(config);
|
|
557
|
+
const token = resolveToken(currency);
|
|
558
|
+
const priceWei = parseAmount(price, token.decimals);
|
|
559
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
560
|
+
const startTime = now + 300;
|
|
561
|
+
const endTime = now + durationSeconds;
|
|
562
|
+
const saltBytes = new Uint8Array(4);
|
|
563
|
+
crypto.getRandomValues(saltBytes);
|
|
564
|
+
const salt = new DataView(saltBytes.buffer).getUint32(0).toString();
|
|
565
|
+
const currentNonce = await contract.nonces(account.address);
|
|
566
|
+
const orderParams = {
|
|
567
|
+
offerer: account.address,
|
|
568
|
+
offer: {
|
|
569
|
+
item_type: "ERC721",
|
|
570
|
+
token: nftContract,
|
|
571
|
+
identifier_or_criteria: tokenId,
|
|
572
|
+
start_amount: "1",
|
|
573
|
+
end_amount: "1"
|
|
574
|
+
},
|
|
575
|
+
consideration: {
|
|
576
|
+
item_type: "ERC20",
|
|
577
|
+
token: token.address,
|
|
578
|
+
identifier_or_criteria: "0",
|
|
579
|
+
start_amount: priceWei,
|
|
580
|
+
end_amount: priceWei,
|
|
581
|
+
recipient: account.address
|
|
582
|
+
},
|
|
583
|
+
start_time: startTime.toString(),
|
|
584
|
+
end_time: endTime.toString(),
|
|
585
|
+
salt,
|
|
586
|
+
nonce: currentNonce.toString()
|
|
587
|
+
};
|
|
588
|
+
const chainId = getChainId(config);
|
|
589
|
+
const typedData = stringifyBigInts(buildOrderTypedData(orderParams, chainId));
|
|
590
|
+
const signature = await account.signMessage(typedData);
|
|
591
|
+
const signatureArray = toSignatureArray(signature);
|
|
592
|
+
const registerPayload = stringifyBigInts({
|
|
593
|
+
parameters: {
|
|
594
|
+
...orderParams,
|
|
595
|
+
offer: {
|
|
596
|
+
...orderParams.offer,
|
|
597
|
+
item_type: shortString.encodeShortString(orderParams.offer.item_type)
|
|
598
|
+
},
|
|
599
|
+
consideration: {
|
|
600
|
+
...orderParams.consideration,
|
|
601
|
+
item_type: shortString.encodeShortString(orderParams.consideration.item_type)
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
signature: signatureArray
|
|
605
|
+
});
|
|
606
|
+
const tokenIdUint256 = cairo.uint256(tokenId);
|
|
607
|
+
let isAlreadyApproved = false;
|
|
608
|
+
try {
|
|
609
|
+
const result = await provider.callContract({
|
|
610
|
+
contractAddress: nftContract,
|
|
611
|
+
entrypoint: "get_approved",
|
|
612
|
+
calldata: [tokenIdUint256.low.toString(), tokenIdUint256.high.toString()]
|
|
613
|
+
});
|
|
614
|
+
isAlreadyApproved = BigInt(result[0]).toString() === BigInt(config.marketplaceContract).toString();
|
|
615
|
+
} catch {
|
|
616
|
+
}
|
|
617
|
+
const registerCall = contract.populate("register_order", [registerPayload]);
|
|
618
|
+
const calls = isAlreadyApproved ? [registerCall] : [
|
|
619
|
+
{
|
|
620
|
+
contractAddress: nftContract,
|
|
621
|
+
entrypoint: "approve",
|
|
622
|
+
calldata: [
|
|
623
|
+
config.marketplaceContract,
|
|
624
|
+
tokenIdUint256.low.toString(),
|
|
625
|
+
tokenIdUint256.high.toString()
|
|
626
|
+
]
|
|
627
|
+
},
|
|
628
|
+
registerCall
|
|
629
|
+
];
|
|
630
|
+
try {
|
|
631
|
+
const tx = await account.execute(calls);
|
|
632
|
+
await provider.waitForTransaction(tx.transaction_hash);
|
|
633
|
+
return { txHash: tx.transaction_hash };
|
|
634
|
+
} catch (err) {
|
|
635
|
+
throw new MedialaneError("Failed to create listing", err);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
async function makeOffer(account, params, config) {
|
|
639
|
+
const { nftContract, tokenId, price, currency = DEFAULT_CURRENCY, durationSeconds } = params;
|
|
640
|
+
const { contract, provider } = makeContract(config);
|
|
641
|
+
const token = resolveToken(currency);
|
|
642
|
+
const priceWei = parseAmount(price, token.decimals);
|
|
643
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
644
|
+
const startTime = now + 300;
|
|
645
|
+
const endTime = now + durationSeconds;
|
|
646
|
+
const saltBytes = new Uint8Array(4);
|
|
647
|
+
crypto.getRandomValues(saltBytes);
|
|
648
|
+
const salt = new DataView(saltBytes.buffer).getUint32(0).toString();
|
|
649
|
+
const currentNonce = await contract.nonces(account.address);
|
|
650
|
+
const orderParams = {
|
|
651
|
+
offerer: account.address,
|
|
652
|
+
offer: {
|
|
653
|
+
item_type: "ERC20",
|
|
654
|
+
token: token.address,
|
|
655
|
+
identifier_or_criteria: "0",
|
|
656
|
+
start_amount: priceWei,
|
|
657
|
+
end_amount: priceWei
|
|
658
|
+
},
|
|
659
|
+
consideration: {
|
|
660
|
+
item_type: "ERC721",
|
|
661
|
+
token: nftContract,
|
|
662
|
+
identifier_or_criteria: tokenId,
|
|
663
|
+
start_amount: "1",
|
|
664
|
+
end_amount: "1",
|
|
665
|
+
recipient: account.address
|
|
666
|
+
},
|
|
667
|
+
start_time: startTime.toString(),
|
|
668
|
+
end_time: endTime.toString(),
|
|
669
|
+
salt,
|
|
670
|
+
nonce: currentNonce.toString()
|
|
671
|
+
};
|
|
672
|
+
const chainId = getChainId(config);
|
|
673
|
+
const typedData = stringifyBigInts(buildOrderTypedData(orderParams, chainId));
|
|
674
|
+
const signature = await account.signMessage(typedData);
|
|
675
|
+
const signatureArray = toSignatureArray(signature);
|
|
676
|
+
const registerPayload = stringifyBigInts({
|
|
677
|
+
parameters: {
|
|
678
|
+
...orderParams,
|
|
679
|
+
offer: {
|
|
680
|
+
...orderParams.offer,
|
|
681
|
+
item_type: shortString.encodeShortString(orderParams.offer.item_type)
|
|
682
|
+
},
|
|
683
|
+
consideration: {
|
|
684
|
+
...orderParams.consideration,
|
|
685
|
+
item_type: shortString.encodeShortString(orderParams.consideration.item_type)
|
|
686
|
+
}
|
|
687
|
+
},
|
|
688
|
+
signature: signatureArray
|
|
689
|
+
});
|
|
690
|
+
const amountUint256 = cairo.uint256(priceWei);
|
|
691
|
+
const approveCall = {
|
|
692
|
+
contractAddress: token.address,
|
|
693
|
+
entrypoint: "approve",
|
|
694
|
+
calldata: [
|
|
695
|
+
config.marketplaceContract,
|
|
696
|
+
amountUint256.low.toString(),
|
|
697
|
+
amountUint256.high.toString()
|
|
698
|
+
]
|
|
699
|
+
};
|
|
700
|
+
const registerCall = contract.populate("register_order", [registerPayload]);
|
|
701
|
+
try {
|
|
702
|
+
const tx = await account.execute([approveCall, registerCall]);
|
|
703
|
+
await provider.waitForTransaction(tx.transaction_hash);
|
|
704
|
+
return { txHash: tx.transaction_hash };
|
|
705
|
+
} catch (err) {
|
|
706
|
+
throw new MedialaneError("Failed to make offer", err);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
async function fulfillOrder(account, params, config) {
|
|
710
|
+
const { orderHash } = params;
|
|
711
|
+
const { contract, provider } = makeContract(config);
|
|
712
|
+
const currentNonce = await contract.nonces(account.address);
|
|
713
|
+
const chainId = getChainId(config);
|
|
714
|
+
const fulfillmentParams = {
|
|
715
|
+
order_hash: orderHash,
|
|
716
|
+
fulfiller: account.address,
|
|
717
|
+
nonce: currentNonce.toString()
|
|
718
|
+
};
|
|
719
|
+
const typedData = stringifyBigInts(
|
|
720
|
+
buildFulfillmentTypedData(fulfillmentParams, chainId)
|
|
721
|
+
);
|
|
722
|
+
const signature = await account.signMessage(typedData);
|
|
723
|
+
const signatureArray = toSignatureArray(signature);
|
|
724
|
+
const fulfillPayload = stringifyBigInts({
|
|
725
|
+
fulfillment: fulfillmentParams,
|
|
726
|
+
signature: signatureArray
|
|
727
|
+
});
|
|
728
|
+
const call = contract.populate("fulfill_order", [fulfillPayload]);
|
|
729
|
+
try {
|
|
730
|
+
const tx = await account.execute(call);
|
|
731
|
+
await provider.waitForTransaction(tx.transaction_hash);
|
|
732
|
+
return { txHash: tx.transaction_hash };
|
|
733
|
+
} catch (err) {
|
|
734
|
+
throw new MedialaneError("Failed to fulfill order", err);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
async function cancelOrder(account, params, config) {
|
|
738
|
+
const { orderHash } = params;
|
|
739
|
+
const { contract, provider } = makeContract(config);
|
|
740
|
+
const currentNonce = await contract.nonces(account.address);
|
|
741
|
+
const chainId = getChainId(config);
|
|
742
|
+
const cancelParams = {
|
|
743
|
+
order_hash: orderHash,
|
|
744
|
+
offerer: account.address,
|
|
745
|
+
nonce: currentNonce.toString()
|
|
746
|
+
};
|
|
747
|
+
const typedData = stringifyBigInts(
|
|
748
|
+
buildCancellationTypedData(cancelParams, chainId)
|
|
749
|
+
);
|
|
750
|
+
const signature = await account.signMessage(typedData);
|
|
751
|
+
const signatureArray = toSignatureArray(signature);
|
|
752
|
+
const cancelRequest = stringifyBigInts({
|
|
753
|
+
cancelation: cancelParams,
|
|
754
|
+
signature: signatureArray
|
|
755
|
+
});
|
|
756
|
+
const call = contract.populate("cancel_order", [cancelRequest]);
|
|
757
|
+
try {
|
|
758
|
+
const tx = await account.execute(call);
|
|
759
|
+
await provider.waitForTransaction(tx.transaction_hash);
|
|
760
|
+
return { txHash: tx.transaction_hash };
|
|
761
|
+
} catch (err) {
|
|
762
|
+
throw new MedialaneError("Failed to cancel order", err);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
function encodeByteArray(str) {
|
|
766
|
+
const ba = byteArray.byteArrayFromString(str);
|
|
767
|
+
return [
|
|
768
|
+
ba.data.length.toString(),
|
|
769
|
+
...ba.data.map((d) => num.toHex(d)),
|
|
770
|
+
num.toHex(ba.pending_word),
|
|
771
|
+
ba.pending_word_len.toString()
|
|
772
|
+
];
|
|
773
|
+
}
|
|
774
|
+
async function mint(account, params, config) {
|
|
775
|
+
const { collectionId, recipient, tokenUri, collectionContract } = params;
|
|
776
|
+
const provider = getProvider(config);
|
|
777
|
+
const contractAddress = collectionContract ?? config.collectionContract;
|
|
778
|
+
const id = cairo.uint256(collectionId);
|
|
779
|
+
const calldata = [id.low.toString(), id.high.toString(), recipient, ...encodeByteArray(tokenUri)];
|
|
780
|
+
try {
|
|
781
|
+
const tx = await account.execute([{ contractAddress, entrypoint: "mint", calldata }]);
|
|
782
|
+
await provider.waitForTransaction(tx.transaction_hash);
|
|
783
|
+
return { txHash: tx.transaction_hash };
|
|
784
|
+
} catch (err) {
|
|
785
|
+
throw new MedialaneError("Failed to mint NFT", err);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
async function createCollection(account, params, config) {
|
|
789
|
+
const { name, symbol, baseUri, collectionContract } = params;
|
|
790
|
+
const provider = getProvider(config);
|
|
791
|
+
const contractAddress = collectionContract ?? config.collectionContract;
|
|
792
|
+
const calldata = [
|
|
793
|
+
...encodeByteArray(name),
|
|
794
|
+
...encodeByteArray(symbol),
|
|
795
|
+
...encodeByteArray(baseUri)
|
|
796
|
+
];
|
|
797
|
+
try {
|
|
798
|
+
const tx = await account.execute([{ contractAddress, entrypoint: "create_collection", calldata }]);
|
|
799
|
+
await provider.waitForTransaction(tx.transaction_hash);
|
|
800
|
+
return { txHash: tx.transaction_hash };
|
|
801
|
+
} catch (err) {
|
|
802
|
+
throw new MedialaneError("Failed to create collection", err);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
async function checkoutCart(account, items, config) {
|
|
806
|
+
if (items.length === 0) throw new MedialaneError("Cart is empty");
|
|
807
|
+
const { contract, provider } = makeContract(config);
|
|
808
|
+
const tokenTotals = /* @__PURE__ */ new Map();
|
|
809
|
+
for (const item of items) {
|
|
810
|
+
const prev = tokenTotals.get(item.considerationToken) ?? 0n;
|
|
811
|
+
tokenTotals.set(item.considerationToken, prev + BigInt(item.considerationAmount));
|
|
812
|
+
}
|
|
813
|
+
const approveCalls = Array.from(tokenTotals.entries()).map(([tokenAddr, totalWei]) => {
|
|
814
|
+
const amount = cairo.uint256(totalWei.toString());
|
|
815
|
+
return {
|
|
816
|
+
contractAddress: tokenAddr,
|
|
817
|
+
entrypoint: "approve",
|
|
818
|
+
calldata: [
|
|
819
|
+
config.marketplaceContract,
|
|
820
|
+
amount.low.toString(),
|
|
821
|
+
amount.high.toString()
|
|
822
|
+
]
|
|
823
|
+
};
|
|
824
|
+
});
|
|
825
|
+
const currentNonce = await contract.nonces(account.address);
|
|
826
|
+
const baseNonce = BigInt(currentNonce.toString());
|
|
827
|
+
const chainId = getChainId(config);
|
|
828
|
+
const fulfillCalls = [];
|
|
829
|
+
for (let i = 0; i < items.length; i++) {
|
|
830
|
+
const item = items[i];
|
|
831
|
+
const nonce = (baseNonce + BigInt(i)).toString();
|
|
832
|
+
const fulfillmentParams = {
|
|
833
|
+
order_hash: item.orderHash,
|
|
834
|
+
fulfiller: account.address,
|
|
835
|
+
nonce
|
|
836
|
+
};
|
|
837
|
+
const typedData = stringifyBigInts(
|
|
838
|
+
buildFulfillmentTypedData(fulfillmentParams, chainId)
|
|
839
|
+
);
|
|
840
|
+
const signature = await account.signMessage(typedData);
|
|
841
|
+
const signatureArray = toSignatureArray(signature);
|
|
842
|
+
const fulfillPayload = stringifyBigInts({
|
|
843
|
+
fulfillment: fulfillmentParams,
|
|
844
|
+
signature: signatureArray
|
|
845
|
+
});
|
|
846
|
+
fulfillCalls.push(contract.populate("fulfill_order", [fulfillPayload]));
|
|
847
|
+
}
|
|
848
|
+
try {
|
|
849
|
+
const tx = await account.execute([...approveCalls, ...fulfillCalls]);
|
|
850
|
+
await provider.waitForTransaction(tx.transaction_hash);
|
|
851
|
+
return { txHash: tx.transaction_hash };
|
|
852
|
+
} catch (err) {
|
|
853
|
+
throw new MedialaneError("Cart checkout failed", err);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// src/marketplace/index.ts
|
|
858
|
+
var MarketplaceModule = class {
|
|
859
|
+
constructor(config) {
|
|
860
|
+
this.config = config;
|
|
861
|
+
}
|
|
862
|
+
// ─── Writes ───────────────────────────────────────────────────────────────
|
|
863
|
+
createListing(account, params) {
|
|
864
|
+
return createListing(account, params, this.config);
|
|
865
|
+
}
|
|
866
|
+
makeOffer(account, params) {
|
|
867
|
+
return makeOffer(account, params, this.config);
|
|
868
|
+
}
|
|
869
|
+
fulfillOrder(account, params) {
|
|
870
|
+
return fulfillOrder(account, params, this.config);
|
|
871
|
+
}
|
|
872
|
+
cancelOrder(account, params) {
|
|
873
|
+
return cancelOrder(account, params, this.config);
|
|
874
|
+
}
|
|
875
|
+
checkoutCart(account, items) {
|
|
876
|
+
return checkoutCart(account, items, this.config);
|
|
877
|
+
}
|
|
878
|
+
mint(account, params) {
|
|
879
|
+
return mint(account, params, this.config);
|
|
880
|
+
}
|
|
881
|
+
createCollection(account, params) {
|
|
882
|
+
return createCollection(account, params, this.config);
|
|
883
|
+
}
|
|
884
|
+
// ─── Typed data builders (for ChipiPay / custom signing flows) ───────────
|
|
885
|
+
buildListingTypedData(params, chainId) {
|
|
886
|
+
return buildOrderTypedData(params, chainId);
|
|
887
|
+
}
|
|
888
|
+
buildFulfillmentTypedData(params, chainId) {
|
|
889
|
+
return buildFulfillmentTypedData(params, chainId);
|
|
890
|
+
}
|
|
891
|
+
buildCancellationTypedData(params, chainId) {
|
|
892
|
+
return buildCancellationTypedData(params, chainId);
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
|
|
896
|
+
// src/api/client.ts
|
|
897
|
+
var MedialaneApiError = class extends Error {
|
|
898
|
+
constructor(status, message) {
|
|
899
|
+
super(message);
|
|
900
|
+
this.status = status;
|
|
901
|
+
this.name = "MedialaneApiError";
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
var ApiClient = class {
|
|
905
|
+
constructor(baseUrl, apiKey) {
|
|
906
|
+
this.baseUrl = baseUrl;
|
|
907
|
+
this.baseHeaders = apiKey ? { "x-api-key": apiKey } : {};
|
|
908
|
+
}
|
|
909
|
+
async request(path, init) {
|
|
910
|
+
const url = `${this.baseUrl.replace(/\/$/, "")}${path}`;
|
|
911
|
+
const headers = { ...this.baseHeaders };
|
|
912
|
+
if (!(init?.body instanceof FormData)) {
|
|
913
|
+
headers["Content-Type"] = "application/json";
|
|
914
|
+
}
|
|
915
|
+
const res = await fetch(url, {
|
|
916
|
+
...init,
|
|
917
|
+
headers: { ...headers, ...init?.headers }
|
|
918
|
+
});
|
|
919
|
+
if (!res.ok) {
|
|
920
|
+
let message = res.statusText;
|
|
921
|
+
try {
|
|
922
|
+
const body = await res.json();
|
|
923
|
+
if (body.error) message = body.error;
|
|
924
|
+
} catch {
|
|
925
|
+
}
|
|
926
|
+
throw new MedialaneApiError(res.status, message);
|
|
927
|
+
}
|
|
928
|
+
return res.json();
|
|
929
|
+
}
|
|
930
|
+
get(path) {
|
|
931
|
+
return this.request(path, { method: "GET" });
|
|
932
|
+
}
|
|
933
|
+
post(path, body) {
|
|
934
|
+
return this.request(path, { method: "POST", body: JSON.stringify(body) });
|
|
935
|
+
}
|
|
936
|
+
patch(path, body) {
|
|
937
|
+
return this.request(path, { method: "PATCH", body: JSON.stringify(body) });
|
|
938
|
+
}
|
|
939
|
+
del(path) {
|
|
940
|
+
return this.request(path, { method: "DELETE" });
|
|
941
|
+
}
|
|
942
|
+
// ─── Orders ────────────────────────────────────────────────────────────────
|
|
943
|
+
getOrders(query = {}) {
|
|
944
|
+
const params = new URLSearchParams();
|
|
945
|
+
if (query.status) params.set("status", query.status);
|
|
946
|
+
if (query.collection) params.set("collection", query.collection);
|
|
947
|
+
if (query.currency) params.set("currency", query.currency);
|
|
948
|
+
if (query.sort) params.set("sort", query.sort);
|
|
949
|
+
if (query.page !== void 0) params.set("page", String(query.page));
|
|
950
|
+
if (query.limit !== void 0) params.set("limit", String(query.limit));
|
|
951
|
+
if (query.offerer) params.set("offerer", query.offerer);
|
|
952
|
+
const qs = params.toString();
|
|
953
|
+
return this.get(`/v1/orders${qs ? `?${qs}` : ""}`);
|
|
954
|
+
}
|
|
955
|
+
getOrder(orderHash) {
|
|
956
|
+
return this.get(`/v1/orders/${orderHash}`);
|
|
957
|
+
}
|
|
958
|
+
getActiveOrdersForToken(contract, tokenId) {
|
|
959
|
+
return this.get(`/v1/orders/token/${contract}/${tokenId}`);
|
|
960
|
+
}
|
|
961
|
+
getOrdersByUser(address, page = 1, limit = 20) {
|
|
962
|
+
return this.get(
|
|
963
|
+
`/v1/orders/user/${address}?page=${page}&limit=${limit}`
|
|
964
|
+
);
|
|
965
|
+
}
|
|
966
|
+
// ─── Tokens ────────────────────────────────────────────────────────────────
|
|
967
|
+
getToken(contract, tokenId, wait = false) {
|
|
968
|
+
return this.get(
|
|
969
|
+
`/v1/tokens/${contract}/${tokenId}${wait ? "?wait=true" : ""}`
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
getTokensByOwner(address, page = 1, limit = 20) {
|
|
973
|
+
return this.get(
|
|
974
|
+
`/v1/tokens/owned/${address}?page=${page}&limit=${limit}`
|
|
975
|
+
);
|
|
976
|
+
}
|
|
977
|
+
getTokenHistory(contract, tokenId, page = 1, limit = 20) {
|
|
978
|
+
return this.get(
|
|
979
|
+
`/v1/tokens/${contract}/${tokenId}/history?page=${page}&limit=${limit}`
|
|
980
|
+
);
|
|
981
|
+
}
|
|
982
|
+
// ─── Collections ───────────────────────────────────────────────────────────
|
|
983
|
+
getCollections(page = 1, limit = 20) {
|
|
984
|
+
return this.get(`/v1/collections?page=${page}&limit=${limit}`);
|
|
985
|
+
}
|
|
986
|
+
getCollection(contract) {
|
|
987
|
+
return this.get(`/v1/collections/${contract}`);
|
|
988
|
+
}
|
|
989
|
+
getCollectionTokens(contract, page = 1, limit = 20) {
|
|
990
|
+
return this.get(
|
|
991
|
+
`/v1/collections/${contract}/tokens?page=${page}&limit=${limit}`
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
// ─── Activities ────────────────────────────────────────────────────────────
|
|
995
|
+
getActivities(query = {}) {
|
|
996
|
+
const params = new URLSearchParams();
|
|
997
|
+
if (query.type) params.set("type", query.type);
|
|
998
|
+
if (query.page !== void 0) params.set("page", String(query.page));
|
|
999
|
+
if (query.limit !== void 0) params.set("limit", String(query.limit));
|
|
1000
|
+
const qs = params.toString();
|
|
1001
|
+
return this.get(`/v1/activities${qs ? `?${qs}` : ""}`);
|
|
1002
|
+
}
|
|
1003
|
+
getActivitiesByAddress(address, page = 1, limit = 20) {
|
|
1004
|
+
return this.get(
|
|
1005
|
+
`/v1/activities/${address}?page=${page}&limit=${limit}`
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
// ─── Search ────────────────────────────────────────────────────────────────
|
|
1009
|
+
search(q, limit = 10) {
|
|
1010
|
+
const params = new URLSearchParams({ q, limit: String(limit) });
|
|
1011
|
+
return this.get(
|
|
1012
|
+
`/v1/search?${params.toString()}`
|
|
1013
|
+
);
|
|
1014
|
+
}
|
|
1015
|
+
// ─── Intents ───────────────────────────────────────────────────────────────
|
|
1016
|
+
createListingIntent(params) {
|
|
1017
|
+
return this.post("/v1/intents/listing", params);
|
|
1018
|
+
}
|
|
1019
|
+
createOfferIntent(params) {
|
|
1020
|
+
return this.post("/v1/intents/offer", params);
|
|
1021
|
+
}
|
|
1022
|
+
createFulfillIntent(params) {
|
|
1023
|
+
return this.post("/v1/intents/fulfill", params);
|
|
1024
|
+
}
|
|
1025
|
+
createCancelIntent(params) {
|
|
1026
|
+
return this.post("/v1/intents/cancel", params);
|
|
1027
|
+
}
|
|
1028
|
+
getIntent(id) {
|
|
1029
|
+
return this.get(`/v1/intents/${id}`);
|
|
1030
|
+
}
|
|
1031
|
+
submitIntentSignature(id, signature) {
|
|
1032
|
+
return this.patch(`/v1/intents/${id}/signature`, { signature });
|
|
1033
|
+
}
|
|
1034
|
+
createMintIntent(params) {
|
|
1035
|
+
return this.post("/v1/intents/mint", params);
|
|
1036
|
+
}
|
|
1037
|
+
createCollectionIntent(params) {
|
|
1038
|
+
return this.post("/v1/intents/create-collection", params);
|
|
1039
|
+
}
|
|
1040
|
+
// ─── Metadata ──────────────────────────────────────────────────────────────
|
|
1041
|
+
getMetadataSignedUrl() {
|
|
1042
|
+
return this.get("/v1/metadata/signed-url");
|
|
1043
|
+
}
|
|
1044
|
+
uploadMetadata(metadata) {
|
|
1045
|
+
return this.post("/v1/metadata/upload", metadata);
|
|
1046
|
+
}
|
|
1047
|
+
resolveMetadata(uri) {
|
|
1048
|
+
const params = new URLSearchParams({ uri });
|
|
1049
|
+
return this.get(`/v1/metadata/resolve?${params.toString()}`);
|
|
1050
|
+
}
|
|
1051
|
+
uploadFile(file) {
|
|
1052
|
+
const formData = new FormData();
|
|
1053
|
+
formData.append("file", file);
|
|
1054
|
+
return this.request("/v1/metadata/upload-file", {
|
|
1055
|
+
method: "POST",
|
|
1056
|
+
body: formData
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
// ─── Portal (tenant self-service) ──────────────────────────────────────────
|
|
1060
|
+
getMe() {
|
|
1061
|
+
return this.get("/v1/portal/me");
|
|
1062
|
+
}
|
|
1063
|
+
getApiKeys() {
|
|
1064
|
+
return this.get("/v1/portal/keys");
|
|
1065
|
+
}
|
|
1066
|
+
createApiKey(label) {
|
|
1067
|
+
return this.post("/v1/portal/keys", label ? { label } : {});
|
|
1068
|
+
}
|
|
1069
|
+
deleteApiKey(id) {
|
|
1070
|
+
return this.del(`/v1/portal/keys/${id}`);
|
|
1071
|
+
}
|
|
1072
|
+
getUsage() {
|
|
1073
|
+
return this.get("/v1/portal/usage");
|
|
1074
|
+
}
|
|
1075
|
+
getWebhooks() {
|
|
1076
|
+
return this.get("/v1/portal/webhooks");
|
|
1077
|
+
}
|
|
1078
|
+
createWebhook(params) {
|
|
1079
|
+
return this.post("/v1/portal/webhooks", params);
|
|
1080
|
+
}
|
|
1081
|
+
deleteWebhook(id) {
|
|
1082
|
+
return this.del(
|
|
1083
|
+
`/v1/portal/webhooks/${id}`
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
};
|
|
1087
|
+
|
|
1088
|
+
// src/client.ts
|
|
1089
|
+
var MedialaneClient = class {
|
|
1090
|
+
constructor(rawConfig = {}) {
|
|
1091
|
+
this.config = resolveConfig(rawConfig);
|
|
1092
|
+
this.marketplace = new MarketplaceModule(this.config);
|
|
1093
|
+
if (!this.config.backendUrl) {
|
|
1094
|
+
this.api = new Proxy({}, {
|
|
1095
|
+
get(_target, prop) {
|
|
1096
|
+
return () => {
|
|
1097
|
+
throw new Error(
|
|
1098
|
+
`backendUrl not configured. Pass backendUrl to MedialaneClient to use .api.${String(prop)}()`
|
|
1099
|
+
);
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
});
|
|
1103
|
+
} else {
|
|
1104
|
+
this.api = new ApiClient(this.config.backendUrl, this.config.apiKey);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
get network() {
|
|
1108
|
+
return this.config.network;
|
|
1109
|
+
}
|
|
1110
|
+
get rpcUrl() {
|
|
1111
|
+
return this.config.rpcUrl;
|
|
1112
|
+
}
|
|
1113
|
+
get marketplaceContract() {
|
|
1114
|
+
return this.config.marketplaceContract;
|
|
1115
|
+
}
|
|
1116
|
+
};
|
|
1117
|
+
|
|
1118
|
+
// src/utils/address.ts
|
|
1119
|
+
function normalizeAddress(address) {
|
|
1120
|
+
const hex = address.replace(/^0x/, "").toLowerCase();
|
|
1121
|
+
return "0x" + hex.padStart(64, "0");
|
|
1122
|
+
}
|
|
1123
|
+
function shortenAddress(address, chars = 4) {
|
|
1124
|
+
const norm = normalizeAddress(address);
|
|
1125
|
+
return `${norm.slice(0, chars + 2)}...${norm.slice(-chars)}`;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
export { ApiClient, COLLECTION_CONTRACT_MAINNET, DEFAULT_RPC_URLS, IPMarketplaceABI, MARKETPLACE_CONTRACT_MAINNET, MarketplaceModule, MedialaneApiError, MedialaneClient, MedialaneError, SUPPORTED_NETWORKS, SUPPORTED_TOKENS, buildCancellationTypedData, buildFulfillmentTypedData, buildOrderTypedData, formatAmount, getTokenByAddress, getTokenBySymbol, normalizeAddress, parseAmount, resolveConfig, shortenAddress, stringifyBigInts, u256ToBigInt };
|
|
1129
|
+
//# sourceMappingURL=index.js.map
|
|
1130
|
+
//# sourceMappingURL=index.js.map
|