@imtbl/sdk 0.9.0 → 0.11.0-alpha

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.
@@ -0,0 +1,2063 @@
1
+ import axios from 'axios';
2
+ import FormData from 'form-data';
3
+ import { providers, BigNumber, constants as constants$1, utils, Contract } from 'ethers';
4
+ import { Seaport as Seaport$1 } from '@opensea/seaport-js';
5
+
6
+ var Environment;
7
+ (function (Environment) {
8
+ Environment["PRODUCTION"] = "production";
9
+ Environment["SANDBOX"] = "sandbox";
10
+ })(Environment || (Environment = {}));
11
+
12
+ class BaseHttpRequest {
13
+ config;
14
+ constructor(config) {
15
+ this.config = config;
16
+ }
17
+ }
18
+
19
+ class ApiError extends Error {
20
+ url;
21
+ status;
22
+ statusText;
23
+ body;
24
+ request;
25
+ constructor(request, response, message) {
26
+ super(message);
27
+ this.name = 'ApiError';
28
+ this.url = response.url;
29
+ this.status = response.status;
30
+ this.statusText = response.statusText;
31
+ this.body = response.body;
32
+ this.request = request;
33
+ }
34
+ }
35
+
36
+ /* istanbul ignore file */
37
+ /* tslint:disable */
38
+ /* eslint-disable */
39
+ class CancelError extends Error {
40
+ constructor(message) {
41
+ super(message);
42
+ this.name = 'CancelError';
43
+ }
44
+ get isCancelled() {
45
+ return true;
46
+ }
47
+ }
48
+ class CancelablePromise {
49
+ [Symbol.toStringTag];
50
+ _isResolved;
51
+ _isRejected;
52
+ _isCancelled;
53
+ _cancelHandlers;
54
+ _promise;
55
+ _resolve;
56
+ _reject;
57
+ constructor(executor) {
58
+ this._isResolved = false;
59
+ this._isRejected = false;
60
+ this._isCancelled = false;
61
+ this._cancelHandlers = [];
62
+ this._promise = new Promise((resolve, reject) => {
63
+ this._resolve = resolve;
64
+ this._reject = reject;
65
+ const onResolve = (value) => {
66
+ if (this._isResolved || this._isRejected || this._isCancelled) {
67
+ return;
68
+ }
69
+ this._isResolved = true;
70
+ this._resolve?.(value);
71
+ };
72
+ const onReject = (reason) => {
73
+ if (this._isResolved || this._isRejected || this._isCancelled) {
74
+ return;
75
+ }
76
+ this._isRejected = true;
77
+ this._reject?.(reason);
78
+ };
79
+ const onCancel = (cancelHandler) => {
80
+ if (this._isResolved || this._isRejected || this._isCancelled) {
81
+ return;
82
+ }
83
+ this._cancelHandlers.push(cancelHandler);
84
+ };
85
+ Object.defineProperty(onCancel, 'isResolved', {
86
+ get: () => this._isResolved,
87
+ });
88
+ Object.defineProperty(onCancel, 'isRejected', {
89
+ get: () => this._isRejected,
90
+ });
91
+ Object.defineProperty(onCancel, 'isCancelled', {
92
+ get: () => this._isCancelled,
93
+ });
94
+ return executor(onResolve, onReject, onCancel);
95
+ });
96
+ }
97
+ then(onFulfilled, onRejected) {
98
+ return this._promise.then(onFulfilled, onRejected);
99
+ }
100
+ catch(onRejected) {
101
+ return this._promise.catch(onRejected);
102
+ }
103
+ finally(onFinally) {
104
+ return this._promise.finally(onFinally);
105
+ }
106
+ cancel() {
107
+ if (this._isResolved || this._isRejected || this._isCancelled) {
108
+ return;
109
+ }
110
+ this._isCancelled = true;
111
+ if (this._cancelHandlers.length) {
112
+ try {
113
+ for (const cancelHandler of this._cancelHandlers) {
114
+ cancelHandler();
115
+ }
116
+ }
117
+ catch (error) {
118
+ console.warn('Cancellation threw an error', error);
119
+ return;
120
+ }
121
+ }
122
+ this._cancelHandlers.length = 0;
123
+ this._reject?.(new CancelError('Request aborted'));
124
+ }
125
+ get isCancelled() {
126
+ return this._isCancelled;
127
+ }
128
+ }
129
+
130
+ /* istanbul ignore file */
131
+ /* tslint:disable */
132
+ /* eslint-disable */
133
+ const isDefined = (value) => {
134
+ return value !== undefined && value !== null;
135
+ };
136
+ const isString = (value) => {
137
+ return typeof value === 'string';
138
+ };
139
+ const isStringWithValue = (value) => {
140
+ return isString(value) && value !== '';
141
+ };
142
+ const isBlob = (value) => {
143
+ return (typeof value === 'object' &&
144
+ typeof value.type === 'string' &&
145
+ typeof value.stream === 'function' &&
146
+ typeof value.arrayBuffer === 'function' &&
147
+ typeof value.constructor === 'function' &&
148
+ typeof value.constructor.name === 'string' &&
149
+ /^(Blob|File)$/.test(value.constructor.name) &&
150
+ /^(Blob|File)$/.test(value[Symbol.toStringTag]));
151
+ };
152
+ const isFormData = (value) => {
153
+ return value instanceof FormData;
154
+ };
155
+ const isSuccess = (status) => {
156
+ return status >= 200 && status < 300;
157
+ };
158
+ const base64 = (str) => {
159
+ try {
160
+ return btoa(str);
161
+ }
162
+ catch (err) {
163
+ // @ts-ignore
164
+ return Buffer.from(str).toString('base64');
165
+ }
166
+ };
167
+ const getQueryString = (params) => {
168
+ const qs = [];
169
+ const append = (key, value) => {
170
+ qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
171
+ };
172
+ const process = (key, value) => {
173
+ if (isDefined(value)) {
174
+ if (Array.isArray(value)) {
175
+ value.forEach(v => {
176
+ process(key, v);
177
+ });
178
+ }
179
+ else if (typeof value === 'object') {
180
+ Object.entries(value).forEach(([k, v]) => {
181
+ process(`${key}[${k}]`, v);
182
+ });
183
+ }
184
+ else {
185
+ append(key, value);
186
+ }
187
+ }
188
+ };
189
+ Object.entries(params).forEach(([key, value]) => {
190
+ process(key, value);
191
+ });
192
+ if (qs.length > 0) {
193
+ return `?${qs.join('&')}`;
194
+ }
195
+ return '';
196
+ };
197
+ const getUrl = (config, options) => {
198
+ const encoder = config.ENCODE_PATH || encodeURI;
199
+ const path = options.url
200
+ .replace('{api-version}', config.VERSION)
201
+ .replace(/{(.*?)}/g, (substring, group) => {
202
+ if (options.path?.hasOwnProperty(group)) {
203
+ return encoder(String(options.path[group]));
204
+ }
205
+ return substring;
206
+ });
207
+ const url = `${config.BASE}${path}`;
208
+ if (options.query) {
209
+ return `${url}${getQueryString(options.query)}`;
210
+ }
211
+ return url;
212
+ };
213
+ const getFormData = (options) => {
214
+ if (options.formData) {
215
+ const formData = new FormData();
216
+ const process = (key, value) => {
217
+ if (isString(value) || isBlob(value)) {
218
+ formData.append(key, value);
219
+ }
220
+ else {
221
+ formData.append(key, JSON.stringify(value));
222
+ }
223
+ };
224
+ Object.entries(options.formData)
225
+ .filter(([_, value]) => isDefined(value))
226
+ .forEach(([key, value]) => {
227
+ if (Array.isArray(value)) {
228
+ value.forEach(v => process(key, v));
229
+ }
230
+ else {
231
+ process(key, value);
232
+ }
233
+ });
234
+ return formData;
235
+ }
236
+ return undefined;
237
+ };
238
+ const resolve = async (options, resolver) => {
239
+ if (typeof resolver === 'function') {
240
+ return resolver(options);
241
+ }
242
+ return resolver;
243
+ };
244
+ const getHeaders = async (config, options, formData) => {
245
+ const token = await resolve(options, config.TOKEN);
246
+ const username = await resolve(options, config.USERNAME);
247
+ const password = await resolve(options, config.PASSWORD);
248
+ const additionalHeaders = await resolve(options, config.HEADERS);
249
+ const formHeaders = typeof formData?.getHeaders === 'function' && formData?.getHeaders() || {};
250
+ const headers = Object.entries({
251
+ Accept: 'application/json',
252
+ ...additionalHeaders,
253
+ ...options.headers,
254
+ ...formHeaders,
255
+ })
256
+ .filter(([_, value]) => isDefined(value))
257
+ .reduce((headers, [key, value]) => ({
258
+ ...headers,
259
+ [key]: String(value),
260
+ }), {});
261
+ if (isStringWithValue(token)) {
262
+ headers['Authorization'] = `Bearer ${token}`;
263
+ }
264
+ if (isStringWithValue(username) && isStringWithValue(password)) {
265
+ const credentials = base64(`${username}:${password}`);
266
+ headers['Authorization'] = `Basic ${credentials}`;
267
+ }
268
+ if (options.body) {
269
+ if (options.mediaType) {
270
+ headers['Content-Type'] = options.mediaType;
271
+ }
272
+ else if (isBlob(options.body)) {
273
+ headers['Content-Type'] = options.body.type || 'application/octet-stream';
274
+ }
275
+ else if (isString(options.body)) {
276
+ headers['Content-Type'] = 'text/plain';
277
+ }
278
+ else if (!isFormData(options.body)) {
279
+ headers['Content-Type'] = 'application/json';
280
+ }
281
+ }
282
+ return headers;
283
+ };
284
+ const getRequestBody = (options) => {
285
+ if (options.body) {
286
+ return options.body;
287
+ }
288
+ return undefined;
289
+ };
290
+ const sendRequest = async (config, options, url, body, formData, headers, onCancel) => {
291
+ const source = axios.CancelToken.source();
292
+ const requestConfig = {
293
+ url,
294
+ headers,
295
+ data: body ?? formData,
296
+ method: options.method,
297
+ withCredentials: config.WITH_CREDENTIALS,
298
+ cancelToken: source.token,
299
+ };
300
+ onCancel(() => source.cancel('The user aborted a request.'));
301
+ try {
302
+ return await axios.request(requestConfig);
303
+ }
304
+ catch (error) {
305
+ const axiosError = error;
306
+ if (axiosError.response) {
307
+ return axiosError.response;
308
+ }
309
+ throw error;
310
+ }
311
+ };
312
+ const getResponseHeader = (response, responseHeader) => {
313
+ if (responseHeader) {
314
+ const content = response.headers[responseHeader];
315
+ if (isString(content)) {
316
+ return content;
317
+ }
318
+ }
319
+ return undefined;
320
+ };
321
+ const getResponseBody = (response) => {
322
+ if (response.status !== 204) {
323
+ return response.data;
324
+ }
325
+ return undefined;
326
+ };
327
+ const catchErrorCodes = (options, result) => {
328
+ const errors = {
329
+ 400: 'Bad Request',
330
+ 401: 'Unauthorized',
331
+ 403: 'Forbidden',
332
+ 404: 'Not Found',
333
+ 500: 'Internal Server Error',
334
+ 502: 'Bad Gateway',
335
+ 503: 'Service Unavailable',
336
+ ...options.errors,
337
+ };
338
+ const error = errors[result.status];
339
+ if (error) {
340
+ throw new ApiError(options, result, error);
341
+ }
342
+ if (!result.ok) {
343
+ throw new ApiError(options, result, 'Generic Error');
344
+ }
345
+ };
346
+ /**
347
+ * Request method
348
+ * @param config The OpenAPI configuration object
349
+ * @param options The request options from the service
350
+ * @returns CancelablePromise<T>
351
+ * @throws ApiError
352
+ */
353
+ const request = (config, options) => {
354
+ return new CancelablePromise(async (resolve, reject, onCancel) => {
355
+ try {
356
+ const url = getUrl(config, options);
357
+ const formData = getFormData(options);
358
+ const body = getRequestBody(options);
359
+ const headers = await getHeaders(config, options, formData);
360
+ if (!onCancel.isCancelled) {
361
+ const response = await sendRequest(config, options, url, body, formData, headers, onCancel);
362
+ const responseBody = getResponseBody(response);
363
+ const responseHeader = getResponseHeader(response, options.responseHeader);
364
+ const result = {
365
+ url,
366
+ ok: isSuccess(response.status),
367
+ status: response.status,
368
+ statusText: response.statusText,
369
+ body: responseHeader ?? responseBody,
370
+ };
371
+ catchErrorCodes(options, result);
372
+ resolve(result.body);
373
+ }
374
+ }
375
+ catch (error) {
376
+ reject(error);
377
+ }
378
+ });
379
+ };
380
+
381
+ class AxiosHttpRequest extends BaseHttpRequest {
382
+ constructor(config) {
383
+ super(config);
384
+ }
385
+ /**
386
+ * Request method
387
+ * @param options The request options from the service
388
+ * @returns CancelablePromise<T>
389
+ * @throws ApiError
390
+ */
391
+ request(options) {
392
+ return request(this.config, options);
393
+ }
394
+ }
395
+
396
+ class OrdersService {
397
+ httpRequest;
398
+ constructor(httpRequest) {
399
+ this.httpRequest = httpRequest;
400
+ }
401
+ /**
402
+ * List all listings
403
+ * List all listings
404
+ * @returns ListListingsResult OK response.
405
+ * @throws ApiError
406
+ */
407
+ listListings({ chainName, status, sellItemContractAddress, buyItemContractAddress, sellItemTokenId, pageSize, sortBy, sortDirection, pageCursor, }) {
408
+ return this.httpRequest.request({
409
+ method: 'GET',
410
+ url: '/v1/chains/{chain_name}/orders/listings',
411
+ path: {
412
+ 'chain_name': chainName,
413
+ },
414
+ query: {
415
+ 'status': status,
416
+ 'sell_item_contract_address': sellItemContractAddress,
417
+ 'buy_item_contract_address': buyItemContractAddress,
418
+ 'sell_item_token_id': sellItemTokenId,
419
+ 'page_size': pageSize,
420
+ 'sort_by': sortBy,
421
+ 'sort_direction': sortDirection,
422
+ 'page_cursor': pageCursor,
423
+ },
424
+ errors: {
425
+ 400: `Bad Request (400)`,
426
+ 404: `The specified resource was not found (404)`,
427
+ 500: `Internal Server Error (500)`,
428
+ },
429
+ });
430
+ }
431
+ /**
432
+ * Create a listing
433
+ * Create a listing
434
+ * @returns ListingResult Created response.
435
+ * @throws ApiError
436
+ */
437
+ createListing({ chainName, requestBody, }) {
438
+ return this.httpRequest.request({
439
+ method: 'POST',
440
+ url: '/v1/chains/{chain_name}/orders/listings',
441
+ path: {
442
+ 'chain_name': chainName,
443
+ },
444
+ body: requestBody,
445
+ mediaType: 'application/json',
446
+ errors: {
447
+ 400: `Bad Request (400)`,
448
+ 404: `The specified resource was not found (404)`,
449
+ 500: `Internal Server Error (500)`,
450
+ },
451
+ });
452
+ }
453
+ /**
454
+ * Get a single listing by ID
455
+ * Get a single listing by ID
456
+ * @returns ListingResult OK response.
457
+ * @throws ApiError
458
+ */
459
+ getListing({ chainName, listingId, }) {
460
+ return this.httpRequest.request({
461
+ method: 'GET',
462
+ url: '/v1/chains/{chain_name}/orders/listings/{listing_id}',
463
+ path: {
464
+ 'chain_name': chainName,
465
+ 'listing_id': listingId,
466
+ },
467
+ errors: {
468
+ 400: `Bad Request (400)`,
469
+ 404: `The specified resource was not found (404)`,
470
+ 500: `Internal Server Error (500)`,
471
+ },
472
+ });
473
+ }
474
+ /**
475
+ * Retrieve fulfillment data for orders
476
+ * Retrieve signed fulfillment data based on the list of order IDs and corresponding fees.
477
+ * @returns any Successful response
478
+ * @throws ApiError
479
+ */
480
+ fulfillmentData({ chainName, requestBody, }) {
481
+ return this.httpRequest.request({
482
+ method: 'POST',
483
+ url: '/v1/chains/{chain_name}/orders/fulfillment-data',
484
+ path: {
485
+ 'chain_name': chainName,
486
+ },
487
+ body: requestBody,
488
+ mediaType: 'application/json',
489
+ errors: {
490
+ 400: `Bad Request (400)`,
491
+ 404: `The specified resource was not found (404)`,
492
+ 500: `Internal Server Error (500)`,
493
+ },
494
+ });
495
+ }
496
+ }
497
+
498
+ class OrderBookClient {
499
+ orders;
500
+ request;
501
+ constructor(config, HttpRequest = AxiosHttpRequest) {
502
+ this.request = new HttpRequest({
503
+ BASE: config?.BASE ?? 'https://api.sandbox.immutable.com',
504
+ VERSION: config?.VERSION ?? '1.0.0',
505
+ WITH_CREDENTIALS: config?.WITH_CREDENTIALS ?? false,
506
+ CREDENTIALS: config?.CREDENTIALS ?? 'include',
507
+ TOKEN: config?.TOKEN,
508
+ USERNAME: config?.USERNAME,
509
+ PASSWORD: config?.PASSWORD,
510
+ HEADERS: config?.HEADERS,
511
+ ENCODE_PATH: config?.ENCODE_PATH,
512
+ });
513
+ this.orders = new OrdersService(this.request);
514
+ }
515
+ }
516
+
517
+ /* istanbul ignore file */
518
+ /* tslint:disable */
519
+ /* eslint-disable */
520
+ var CreateOrderProtocolData;
521
+ (function (CreateOrderProtocolData) {
522
+ (function (order_type) {
523
+ order_type["FULL_RESTRICTED"] = "FULL_RESTRICTED";
524
+ })(CreateOrderProtocolData.order_type || (CreateOrderProtocolData.order_type = {}));
525
+ })(CreateOrderProtocolData || (CreateOrderProtocolData = {}));
526
+
527
+ /* istanbul ignore file */
528
+ /* tslint:disable */
529
+ /* eslint-disable */
530
+ var Fee;
531
+ (function (Fee) {
532
+ (function (fee_type) {
533
+ fee_type["ROYALTY"] = "ROYALTY";
534
+ })(Fee.fee_type || (Fee.fee_type = {}));
535
+ })(Fee || (Fee = {}));
536
+
537
+ /* istanbul ignore file */
538
+ /* tslint:disable */
539
+ /* eslint-disable */
540
+ /**
541
+ * The Order status
542
+ */
543
+ var OrderStatus;
544
+ (function (OrderStatus) {
545
+ OrderStatus["PENDING"] = "PENDING";
546
+ OrderStatus["ACTIVE"] = "ACTIVE";
547
+ OrderStatus["INACTIVE"] = "INACTIVE";
548
+ OrderStatus["FILLED"] = "FILLED";
549
+ OrderStatus["CANCELLED"] = "CANCELLED";
550
+ OrderStatus["EXPIRED"] = "EXPIRED";
551
+ })(OrderStatus || (OrderStatus = {}));
552
+
553
+ var TransactionPurpose;
554
+ (function (TransactionPurpose) {
555
+ TransactionPurpose["APPROVAL"] = "APPROVAL";
556
+ TransactionPurpose["FULFILL_ORDER"] = "FULFILL_ORDER";
557
+ })(TransactionPurpose || (TransactionPurpose = {}));
558
+ var SignablePurpose;
559
+ (function (SignablePurpose) {
560
+ SignablePurpose["CREATE_LISTING"] = "CREATE_LISTING";
561
+ })(SignablePurpose || (SignablePurpose = {}));
562
+ var ActionType;
563
+ (function (ActionType) {
564
+ ActionType["TRANSACTION"] = "TRANSACTION";
565
+ ActionType["SIGNABLE"] = "SIGNABLE";
566
+ })(ActionType || (ActionType = {}));
567
+
568
+ /* eslint-disable */
569
+ // TODO: Resolve these from seaport-js.
570
+ // There is some bundling issue that is preventing this from working
571
+ const SEAPORT_CONTRACT_NAME = 'ImmutableSeaport';
572
+ // export const SEAPORT_CONTRACT_VERSION_V1_4 = '1.4';
573
+ const SEAPORT_CONTRACT_VERSION_V1_5 = '1.5';
574
+ const EIP_712_ORDER_TYPE = {
575
+ OrderComponents: [
576
+ { name: 'offerer', type: 'address' },
577
+ { name: 'zone', type: 'address' },
578
+ { name: 'offer', type: 'OfferItem[]' },
579
+ { name: 'consideration', type: 'ConsiderationItem[]' },
580
+ { name: 'orderType', type: 'uint8' },
581
+ { name: 'startTime', type: 'uint256' },
582
+ { name: 'endTime', type: 'uint256' },
583
+ { name: 'zoneHash', type: 'bytes32' },
584
+ { name: 'salt', type: 'uint256' },
585
+ { name: 'conduitKey', type: 'bytes32' },
586
+ { name: 'counter', type: 'uint256' },
587
+ ],
588
+ OfferItem: [
589
+ { name: 'itemType', type: 'uint8' },
590
+ { name: 'token', type: 'address' },
591
+ { name: 'identifierOrCriteria', type: 'uint256' },
592
+ { name: 'startAmount', type: 'uint256' },
593
+ { name: 'endAmount', type: 'uint256' },
594
+ ],
595
+ ConsiderationItem: [
596
+ { name: 'itemType', type: 'uint8' },
597
+ { name: 'token', type: 'address' },
598
+ { name: 'identifierOrCriteria', type: 'uint256' },
599
+ { name: 'startAmount', type: 'uint256' },
600
+ { name: 'endAmount', type: 'uint256' },
601
+ { name: 'recipient', type: 'address' },
602
+ ],
603
+ };
604
+ var OrderType;
605
+ (function (OrderType) {
606
+ OrderType[OrderType["FULL_OPEN"] = 0] = "FULL_OPEN";
607
+ OrderType[OrderType["PARTIAL_OPEN"] = 1] = "PARTIAL_OPEN";
608
+ OrderType[OrderType["FULL_RESTRICTED"] = 2] = "FULL_RESTRICTED";
609
+ OrderType[OrderType["PARTIAL_RESTRICTED"] = 3] = "PARTIAL_RESTRICTED";
610
+ })(OrderType || (OrderType = {}));
611
+ var ItemType;
612
+ (function (ItemType) {
613
+ ItemType[ItemType["NATIVE"] = 0] = "NATIVE";
614
+ ItemType[ItemType["ERC20"] = 1] = "ERC20";
615
+ ItemType[ItemType["ERC721"] = 2] = "ERC721";
616
+ ItemType[ItemType["ERC1155"] = 3] = "ERC1155";
617
+ ItemType[ItemType["ERC721_WITH_CRITERIA"] = 4] = "ERC721_WITH_CRITERIA";
618
+ ItemType[ItemType["ERC1155_WITH_CRITERIA"] = 5] = "ERC1155_WITH_CRITERIA";
619
+ })(ItemType || (ItemType = {}));
620
+ var Side;
621
+ (function (Side) {
622
+ Side[Side["OFFER"] = 0] = "OFFER";
623
+ Side[Side["CONSIDERATION"] = 1] = "CONSIDERATION";
624
+ })(Side || (Side = {}));
625
+ var BasicOrderRouteType;
626
+ (function (BasicOrderRouteType) {
627
+ BasicOrderRouteType[BasicOrderRouteType["ETH_TO_ERC721"] = 0] = "ETH_TO_ERC721";
628
+ BasicOrderRouteType[BasicOrderRouteType["ETH_TO_ERC1155"] = 1] = "ETH_TO_ERC1155";
629
+ BasicOrderRouteType[BasicOrderRouteType["ERC20_TO_ERC721"] = 2] = "ERC20_TO_ERC721";
630
+ BasicOrderRouteType[BasicOrderRouteType["ERC20_TO_ERC1155"] = 3] = "ERC20_TO_ERC1155";
631
+ BasicOrderRouteType[BasicOrderRouteType["ERC721_TO_ERC20"] = 4] = "ERC721_TO_ERC20";
632
+ BasicOrderRouteType[BasicOrderRouteType["ERC1155_TO_ERC20"] = 5] = "ERC1155_TO_ERC20";
633
+ })(BasicOrderRouteType || (BasicOrderRouteType = {}));
634
+
635
+ function getOrderComponentsFromMessage(orderMessage) {
636
+ const data = JSON.parse(orderMessage);
637
+ const orderComponents = data.message;
638
+ orderComponents.salt = BigNumber.from(orderComponents.salt).toHexString();
639
+ return orderComponents;
640
+ }
641
+
642
+ // Add 20% more gas than estimate to prevent out of gas errors
643
+ // This can always be overwritten by the user signing the transaction
644
+ function prepareTransaction(transactionMethods) {
645
+ return async () => {
646
+ const transaction = await transactionMethods.buildTransaction();
647
+ transaction.gasLimit = await transactionMethods.estimateGas();
648
+ transaction.gasLimit = transaction.gasLimit
649
+ .add(transaction.gasLimit.div(5));
650
+ return transaction;
651
+ };
652
+ }
653
+
654
+ function mapImmutableOrderToSeaportOrderComponents(order, counter, zoneAddress) {
655
+ const considerationItems = order.buy.map((buyItem) => {
656
+ switch (buyItem.item_type) {
657
+ case 'NATIVE':
658
+ return {
659
+ startAmount: buyItem.start_amount,
660
+ endAmount: buyItem.start_amount,
661
+ itemType: ItemType.NATIVE,
662
+ recipient: order.account_address,
663
+ token: constants$1.AddressZero,
664
+ identifierOrCriteria: '0',
665
+ };
666
+ case 'ERC20':
667
+ return {
668
+ startAmount: buyItem.start_amount,
669
+ endAmount: buyItem.start_amount,
670
+ itemType: ItemType.ERC20,
671
+ recipient: order.account_address,
672
+ token: buyItem.contract_address || constants$1.AddressZero,
673
+ identifierOrCriteria: '0',
674
+ };
675
+ default: // ERC721
676
+ return {
677
+ startAmount: '1',
678
+ endAmount: '1',
679
+ itemType: ItemType.ERC721,
680
+ recipient: order.account_address,
681
+ token: buyItem.contract_address || constants$1.AddressZero,
682
+ identifierOrCriteria: '0',
683
+ };
684
+ }
685
+ });
686
+ const fees = order.fees.map((fee) => ({
687
+ startAmount: fee.amount,
688
+ endAmount: fee.amount,
689
+ itemType: order.buy[0].item_type === 'ERC20' ? ItemType.ERC20 : ItemType.NATIVE,
690
+ recipient: fee.recipient,
691
+ token: order.buy[0].item_type === 'ERC20'
692
+ ? order.buy[0].contract_address
693
+ : constants$1.AddressZero,
694
+ identifierOrCriteria: '0',
695
+ }));
696
+ return {
697
+ conduitKey: constants$1.HashZero,
698
+ consideration: [...considerationItems, ...fees],
699
+ offer: order.sell.map((sellItem) => {
700
+ const erc721Item = sellItem;
701
+ return {
702
+ startAmount: '1',
703
+ endAmount: '1',
704
+ itemType: ItemType.ERC721,
705
+ token: erc721Item.contract_address,
706
+ identifierOrCriteria: erc721Item.token_id,
707
+ };
708
+ }),
709
+ counter,
710
+ endTime: Math.round(new Date(order.end_time).getTime() / 1000).toString(),
711
+ startTime: Math.round(new Date(order.start_time).getTime() / 1000).toString(),
712
+ salt: order.salt,
713
+ offerer: order.account_address,
714
+ zone: zoneAddress,
715
+ totalOriginalConsiderationItems: 2,
716
+ orderType: OrderType.FULL_RESTRICTED,
717
+ zoneHash: constants$1.HashZero,
718
+ };
719
+ }
720
+
721
+ class Seaport {
722
+ seaportLibFactory;
723
+ provider;
724
+ seaportContractAddress;
725
+ zoneContractAddress;
726
+ constructor(seaportLibFactory, provider, seaportContractAddress, zoneContractAddress) {
727
+ this.seaportLibFactory = seaportLibFactory;
728
+ this.provider = provider;
729
+ this.seaportContractAddress = seaportContractAddress;
730
+ this.zoneContractAddress = zoneContractAddress;
731
+ }
732
+ async prepareSeaportOrder(offerer, listingItem, considerationItem, royaltyInfo, orderStart, orderExpiry) {
733
+ const { actions: seaportActions } = await this.createSeaportOrder(offerer, listingItem, considerationItem, royaltyInfo, orderStart, orderExpiry);
734
+ const listingActions = [];
735
+ const approvalAction = seaportActions
736
+ .find((action) => action.type === 'approval');
737
+ if (approvalAction) {
738
+ listingActions.push({
739
+ type: ActionType.TRANSACTION,
740
+ purpose: TransactionPurpose.APPROVAL,
741
+ buildTransaction: prepareTransaction(approvalAction.transactionMethods),
742
+ });
743
+ }
744
+ const createAction = seaportActions
745
+ .find((action) => action.type === 'create');
746
+ if (!createAction) {
747
+ throw new Error('No create order action found');
748
+ }
749
+ const orderMessageToSign = await createAction.getMessageToSign();
750
+ const orderComponents = getOrderComponentsFromMessage(orderMessageToSign);
751
+ listingActions.push({
752
+ type: ActionType.SIGNABLE,
753
+ purpose: SignablePurpose.CREATE_LISTING,
754
+ message: await this.getTypedDataFromOrderComponents(orderComponents),
755
+ });
756
+ return {
757
+ actions: listingActions,
758
+ orderComponents,
759
+ orderHash: this.getSeaportLib().getOrderHash(orderComponents),
760
+ };
761
+ }
762
+ async fulfillOrder(order, account, extraData) {
763
+ const orderComponents = await this.mapImmutableOrderToSeaportOrderComponents(order);
764
+ const seaportLib = this.getSeaportLib(order);
765
+ const { actions: seaportActions } = await seaportLib.fulfillOrders({
766
+ accountAddress: account,
767
+ fulfillOrderDetails: [{
768
+ order: {
769
+ parameters: orderComponents,
770
+ signature: order.signature,
771
+ },
772
+ extraData,
773
+ }],
774
+ });
775
+ const fulfillmentActions = [];
776
+ const approvalAction = seaportActions
777
+ .find((action) => action.type === 'approval');
778
+ if (approvalAction) {
779
+ fulfillmentActions.push({
780
+ type: ActionType.TRANSACTION,
781
+ buildTransaction: prepareTransaction(approvalAction.transactionMethods),
782
+ purpose: TransactionPurpose.APPROVAL,
783
+ });
784
+ }
785
+ const fulfilOrderAction = seaportActions
786
+ .find((action) => action.type === 'exchange');
787
+ if (!fulfilOrderAction) {
788
+ throw new Error('No exchange action found');
789
+ }
790
+ fulfillmentActions.push({
791
+ type: ActionType.TRANSACTION,
792
+ buildTransaction: prepareTransaction(fulfilOrderAction.transactionMethods),
793
+ purpose: TransactionPurpose.FULFILL_ORDER,
794
+ });
795
+ return { actions: fulfillmentActions };
796
+ }
797
+ async cancelOrder(order, account) {
798
+ const orderComponents = await this.mapImmutableOrderToSeaportOrderComponents(order);
799
+ const seaportLib = this.getSeaportLib(order);
800
+ const cancellationTransaction = await seaportLib.cancelOrders([orderComponents], account);
801
+ return prepareTransaction(cancellationTransaction)();
802
+ }
803
+ mapImmutableOrderToSeaportOrderComponents(order) {
804
+ const orderCounter = order.protocol_data.counter;
805
+ return mapImmutableOrderToSeaportOrderComponents(order, orderCounter, this.zoneContractAddress);
806
+ }
807
+ createSeaportOrder(offerer, listingItem, considerationItem, royaltyInfo, orderStart, orderExpiry) {
808
+ const seaportLib = this.getSeaportLib();
809
+ return seaportLib.createOrder({
810
+ allowPartialFills: false,
811
+ offer: [
812
+ {
813
+ itemType: ItemType.ERC721,
814
+ token: listingItem.contractAddress,
815
+ identifier: listingItem.tokenId,
816
+ },
817
+ ],
818
+ consideration: [
819
+ {
820
+ token: considerationItem.type === 'ERC20' ? considerationItem.contractAddress : undefined,
821
+ amount: considerationItem.amount,
822
+ recipient: offerer,
823
+ },
824
+ {
825
+ token: considerationItem.type === 'ERC20' ? considerationItem.contractAddress : undefined,
826
+ amount: royaltyInfo.amountRequired,
827
+ recipient: royaltyInfo.recipient,
828
+ },
829
+ ],
830
+ startTime: (orderStart.getTime() / 1000).toFixed(0),
831
+ endTime: (orderExpiry.getTime() / 1000).toFixed(0),
832
+ zone: this.zoneContractAddress,
833
+ restrictedByZone: true,
834
+ }, offerer);
835
+ }
836
+ async getTypedDataFromOrderComponents(orderComponents) {
837
+ const { chainId } = await this.provider.getNetwork();
838
+ const domainData = {
839
+ name: SEAPORT_CONTRACT_NAME,
840
+ version: SEAPORT_CONTRACT_VERSION_V1_5,
841
+ chainId,
842
+ verifyingContract: this.seaportContractAddress,
843
+ };
844
+ return {
845
+ domain: domainData,
846
+ types: EIP_712_ORDER_TYPE,
847
+ value: orderComponents,
848
+ };
849
+ }
850
+ getSeaportLib(order) {
851
+ const seaportAddress = order?.protocol_data?.seaport_address ?? this.seaportContractAddress;
852
+ const seaportVersion = SEAPORT_CONTRACT_VERSION_V1_5;
853
+ // if (order?.protocol_data?.seaport_version === SEAPORT_CONTRACT_VERSION_V1_5) {
854
+ // seaportVersion = SEAPORT_CONTRACT_VERSION_V1_5;
855
+ // }
856
+ return this.seaportLibFactory.create(seaportVersion, seaportAddress);
857
+ }
858
+ }
859
+
860
+ class ImmutableApiClient {
861
+ orderbookService;
862
+ chainName;
863
+ seaportAddress;
864
+ constructor(orderbookService, chainName, seaportAddress) {
865
+ this.orderbookService = orderbookService;
866
+ this.chainName = chainName;
867
+ this.seaportAddress = seaportAddress;
868
+ }
869
+ async fulfillmentData(requests) {
870
+ return this.orderbookService.fulfillmentData({
871
+ chainName: this.chainName,
872
+ requestBody: requests,
873
+ });
874
+ }
875
+ async getListing(listingId) {
876
+ return this.orderbookService.getListing({
877
+ chainName: this.chainName,
878
+ listingId,
879
+ });
880
+ }
881
+ async listListings(listOrderParams) {
882
+ return this.orderbookService.listListings({
883
+ chainName: this.chainName,
884
+ ...listOrderParams,
885
+ });
886
+ }
887
+ async createListing({ orderHash, orderComponents, orderSignature, }) {
888
+ if (orderComponents.offer.length !== 1) {
889
+ throw new Error('Only one item can be listed at a time');
890
+ }
891
+ if (Number(orderComponents.offer[0].itemType) !== ItemType.ERC721) {
892
+ throw new Error('Only ERC721 tokens can be listed');
893
+ }
894
+ const orderTypes = [
895
+ ...orderComponents.consideration.map((c) => c.itemType),
896
+ ];
897
+ const isSameConsiderationType = new Set(orderTypes).size === 1;
898
+ if (!isSameConsiderationType) {
899
+ throw new Error('All consideration items must be of the same type');
900
+ }
901
+ return this.orderbookService.createListing({
902
+ chainName: this.chainName,
903
+ requestBody: {
904
+ order_hash: orderHash,
905
+ account_address: orderComponents.offerer,
906
+ buy: [
907
+ {
908
+ item_type: Number(orderComponents.consideration[0].itemType)
909
+ === ItemType.NATIVE
910
+ ? 'NATIVE'
911
+ : 'ERC20',
912
+ start_amount: orderComponents.consideration[0].startAmount,
913
+ contract_address: orderComponents.consideration[0].token,
914
+ },
915
+ ],
916
+ fees: orderComponents.consideration.length > 1
917
+ ? [
918
+ {
919
+ amount: orderComponents.consideration[1].startAmount,
920
+ recipient: orderComponents.consideration[1].recipient,
921
+ fee_type: Fee.fee_type.ROYALTY,
922
+ },
923
+ ]
924
+ : [],
925
+ end_time: new Date(parseInt(`${orderComponents.endTime.toString()}000`, 10)).toISOString(),
926
+ protocol_data: {
927
+ order_type: CreateOrderProtocolData.order_type.FULL_RESTRICTED,
928
+ zone_address: orderComponents.zone,
929
+ seaport_address: this.seaportAddress,
930
+ seaport_version: SEAPORT_CONTRACT_VERSION_V1_5,
931
+ counter: orderComponents.counter.toString(),
932
+ },
933
+ salt: orderComponents.salt,
934
+ sell: [
935
+ {
936
+ contract_address: orderComponents.offer[0].token,
937
+ token_id: orderComponents.offer[0].identifierOrCriteria,
938
+ item_type: 'ERC721',
939
+ },
940
+ ],
941
+ signature: orderSignature,
942
+ start_time: new Date(parseInt(`${orderComponents.startTime.toString()}000`, 10)).toISOString(),
943
+ },
944
+ });
945
+ }
946
+ }
947
+
948
+ class ImmutableApiClientFactory {
949
+ chainName;
950
+ seaportAddress;
951
+ orderbookClient;
952
+ constructor(apiEndpoint, chainName, seaportAddress) {
953
+ this.chainName = chainName;
954
+ this.seaportAddress = seaportAddress;
955
+ this.orderbookClient = new OrderBookClient({
956
+ // eslint-disable-next-line @typescript-eslint/naming-convention
957
+ BASE: apiEndpoint,
958
+ });
959
+ }
960
+ create() {
961
+ return new ImmutableApiClient(this.orderbookClient.orders, this.chainName, this.seaportAddress);
962
+ }
963
+ }
964
+
965
+ const TESTNET_CHAIN_NAME = 'imtbl-zkevm-testnet';
966
+ const MAINNET_CHAIN_NAME = 'imtbl-zkevm-mainnet';
967
+ function getOrderbookConfig(environment) {
968
+ switch (environment) {
969
+ case Environment.SANDBOX:
970
+ return {
971
+ seaportContractAddress: '0x7Fb7Da6De152597830eD16361633e362A2F59410',
972
+ zoneContractAddress: '0x63441cBfBd15Dd8f5E92598E535661Ac5aCB808E',
973
+ apiEndpoint: 'https://api.sandbox.immutable.com',
974
+ chainName: TESTNET_CHAIN_NAME,
975
+ provider: new providers.JsonRpcProvider('https://rpc.testnet.immutable.com'),
976
+ };
977
+ // not yet deployed
978
+ case Environment.PRODUCTION:
979
+ return {
980
+ seaportContractAddress: '',
981
+ zoneContractAddress: '',
982
+ apiEndpoint: 'https://api.immutable.com',
983
+ chainName: MAINNET_CHAIN_NAME,
984
+ provider: new providers.JsonRpcProvider('https://rpc.immutable.com'),
985
+ };
986
+ default:
987
+ return null;
988
+ }
989
+ }
990
+
991
+ class ERC721 {
992
+ erc721;
993
+ constructor(erc721) {
994
+ this.erc721 = erc721;
995
+ }
996
+ async royaltyInfo(tokenId, salePrice) {
997
+ const [recipient, royaltyRequired] = await this.erc721.royaltyInfo(tokenId, salePrice);
998
+ return { recipient, amountRequired: royaltyRequired.toString() };
999
+ }
1000
+ }
1001
+
1002
+ /* Autogenerated file. Do not edit manually. */
1003
+ /* tslint:disable */
1004
+ /* eslint-disable */
1005
+ const _abi = [
1006
+ {
1007
+ inputs: [
1008
+ {
1009
+ internalType: "address",
1010
+ name: "owner_",
1011
+ type: "address",
1012
+ },
1013
+ {
1014
+ internalType: "string",
1015
+ name: "name_",
1016
+ type: "string",
1017
+ },
1018
+ {
1019
+ internalType: "string",
1020
+ name: "symbol_",
1021
+ type: "string",
1022
+ },
1023
+ {
1024
+ internalType: "string",
1025
+ name: "baseURI_",
1026
+ type: "string",
1027
+ },
1028
+ {
1029
+ internalType: "string",
1030
+ name: "contractURI_",
1031
+ type: "string",
1032
+ },
1033
+ {
1034
+ internalType: "address",
1035
+ name: "_receiver",
1036
+ type: "address",
1037
+ },
1038
+ {
1039
+ internalType: "uint96",
1040
+ name: "_feeNumerator",
1041
+ type: "uint96",
1042
+ },
1043
+ ],
1044
+ stateMutability: "nonpayable",
1045
+ type: "constructor",
1046
+ },
1047
+ {
1048
+ inputs: [
1049
+ {
1050
+ internalType: "address",
1051
+ name: "target",
1052
+ type: "address",
1053
+ },
1054
+ ],
1055
+ name: "ApproveTargetNotInAllowlist",
1056
+ type: "error",
1057
+ },
1058
+ {
1059
+ inputs: [
1060
+ {
1061
+ internalType: "address",
1062
+ name: "caller",
1063
+ type: "address",
1064
+ },
1065
+ ],
1066
+ name: "CallerNotInAllowlist",
1067
+ type: "error",
1068
+ },
1069
+ {
1070
+ anonymous: false,
1071
+ inputs: [
1072
+ {
1073
+ indexed: true,
1074
+ internalType: "address",
1075
+ name: "owner",
1076
+ type: "address",
1077
+ },
1078
+ {
1079
+ indexed: true,
1080
+ internalType: "address",
1081
+ name: "approved",
1082
+ type: "address",
1083
+ },
1084
+ {
1085
+ indexed: true,
1086
+ internalType: "uint256",
1087
+ name: "tokenId",
1088
+ type: "uint256",
1089
+ },
1090
+ ],
1091
+ name: "Approval",
1092
+ type: "event",
1093
+ },
1094
+ {
1095
+ anonymous: false,
1096
+ inputs: [
1097
+ {
1098
+ indexed: true,
1099
+ internalType: "address",
1100
+ name: "owner",
1101
+ type: "address",
1102
+ },
1103
+ {
1104
+ indexed: true,
1105
+ internalType: "address",
1106
+ name: "operator",
1107
+ type: "address",
1108
+ },
1109
+ {
1110
+ indexed: false,
1111
+ internalType: "bool",
1112
+ name: "approved",
1113
+ type: "bool",
1114
+ },
1115
+ ],
1116
+ name: "ApprovalForAll",
1117
+ type: "event",
1118
+ },
1119
+ {
1120
+ anonymous: false,
1121
+ inputs: [
1122
+ {
1123
+ indexed: true,
1124
+ internalType: "bytes32",
1125
+ name: "role",
1126
+ type: "bytes32",
1127
+ },
1128
+ {
1129
+ indexed: true,
1130
+ internalType: "bytes32",
1131
+ name: "previousAdminRole",
1132
+ type: "bytes32",
1133
+ },
1134
+ {
1135
+ indexed: true,
1136
+ internalType: "bytes32",
1137
+ name: "newAdminRole",
1138
+ type: "bytes32",
1139
+ },
1140
+ ],
1141
+ name: "RoleAdminChanged",
1142
+ type: "event",
1143
+ },
1144
+ {
1145
+ anonymous: false,
1146
+ inputs: [
1147
+ {
1148
+ indexed: true,
1149
+ internalType: "bytes32",
1150
+ name: "role",
1151
+ type: "bytes32",
1152
+ },
1153
+ {
1154
+ indexed: true,
1155
+ internalType: "address",
1156
+ name: "account",
1157
+ type: "address",
1158
+ },
1159
+ {
1160
+ indexed: true,
1161
+ internalType: "address",
1162
+ name: "sender",
1163
+ type: "address",
1164
+ },
1165
+ ],
1166
+ name: "RoleGranted",
1167
+ type: "event",
1168
+ },
1169
+ {
1170
+ anonymous: false,
1171
+ inputs: [
1172
+ {
1173
+ indexed: true,
1174
+ internalType: "bytes32",
1175
+ name: "role",
1176
+ type: "bytes32",
1177
+ },
1178
+ {
1179
+ indexed: true,
1180
+ internalType: "address",
1181
+ name: "account",
1182
+ type: "address",
1183
+ },
1184
+ {
1185
+ indexed: true,
1186
+ internalType: "address",
1187
+ name: "sender",
1188
+ type: "address",
1189
+ },
1190
+ ],
1191
+ name: "RoleRevoked",
1192
+ type: "event",
1193
+ },
1194
+ {
1195
+ anonymous: false,
1196
+ inputs: [
1197
+ {
1198
+ indexed: false,
1199
+ internalType: "address",
1200
+ name: "oldRegistry",
1201
+ type: "address",
1202
+ },
1203
+ {
1204
+ indexed: false,
1205
+ internalType: "address",
1206
+ name: "newRegistry",
1207
+ type: "address",
1208
+ },
1209
+ ],
1210
+ name: "RoyaltytAllowlistRegistryUpdated",
1211
+ type: "event",
1212
+ },
1213
+ {
1214
+ anonymous: false,
1215
+ inputs: [
1216
+ {
1217
+ indexed: true,
1218
+ internalType: "address",
1219
+ name: "from",
1220
+ type: "address",
1221
+ },
1222
+ {
1223
+ indexed: true,
1224
+ internalType: "address",
1225
+ name: "to",
1226
+ type: "address",
1227
+ },
1228
+ {
1229
+ indexed: true,
1230
+ internalType: "uint256",
1231
+ name: "tokenId",
1232
+ type: "uint256",
1233
+ },
1234
+ ],
1235
+ name: "Transfer",
1236
+ type: "event",
1237
+ },
1238
+ {
1239
+ inputs: [],
1240
+ name: "DEFAULT_ADMIN_ROLE",
1241
+ outputs: [
1242
+ {
1243
+ internalType: "bytes32",
1244
+ name: "",
1245
+ type: "bytes32",
1246
+ },
1247
+ ],
1248
+ stateMutability: "view",
1249
+ type: "function",
1250
+ },
1251
+ {
1252
+ inputs: [],
1253
+ name: "MINTER_ROLE",
1254
+ outputs: [
1255
+ {
1256
+ internalType: "bytes32",
1257
+ name: "",
1258
+ type: "bytes32",
1259
+ },
1260
+ ],
1261
+ stateMutability: "view",
1262
+ type: "function",
1263
+ },
1264
+ {
1265
+ inputs: [
1266
+ {
1267
+ internalType: "address",
1268
+ name: "to",
1269
+ type: "address",
1270
+ },
1271
+ {
1272
+ internalType: "uint256",
1273
+ name: "tokenId",
1274
+ type: "uint256",
1275
+ },
1276
+ ],
1277
+ name: "approve",
1278
+ outputs: [],
1279
+ stateMutability: "nonpayable",
1280
+ type: "function",
1281
+ },
1282
+ {
1283
+ inputs: [
1284
+ {
1285
+ internalType: "address",
1286
+ name: "owner",
1287
+ type: "address",
1288
+ },
1289
+ ],
1290
+ name: "balanceOf",
1291
+ outputs: [
1292
+ {
1293
+ internalType: "uint256",
1294
+ name: "",
1295
+ type: "uint256",
1296
+ },
1297
+ ],
1298
+ stateMutability: "view",
1299
+ type: "function",
1300
+ },
1301
+ {
1302
+ inputs: [],
1303
+ name: "baseURI",
1304
+ outputs: [
1305
+ {
1306
+ internalType: "string",
1307
+ name: "",
1308
+ type: "string",
1309
+ },
1310
+ ],
1311
+ stateMutability: "view",
1312
+ type: "function",
1313
+ },
1314
+ {
1315
+ inputs: [
1316
+ {
1317
+ internalType: "uint256",
1318
+ name: "tokenId",
1319
+ type: "uint256",
1320
+ },
1321
+ ],
1322
+ name: "burn",
1323
+ outputs: [],
1324
+ stateMutability: "nonpayable",
1325
+ type: "function",
1326
+ },
1327
+ {
1328
+ inputs: [],
1329
+ name: "contractURI",
1330
+ outputs: [
1331
+ {
1332
+ internalType: "string",
1333
+ name: "",
1334
+ type: "string",
1335
+ },
1336
+ ],
1337
+ stateMutability: "view",
1338
+ type: "function",
1339
+ },
1340
+ {
1341
+ inputs: [],
1342
+ name: "getAdmins",
1343
+ outputs: [
1344
+ {
1345
+ internalType: "address[]",
1346
+ name: "",
1347
+ type: "address[]",
1348
+ },
1349
+ ],
1350
+ stateMutability: "view",
1351
+ type: "function",
1352
+ },
1353
+ {
1354
+ inputs: [
1355
+ {
1356
+ internalType: "uint256",
1357
+ name: "tokenId",
1358
+ type: "uint256",
1359
+ },
1360
+ ],
1361
+ name: "getApproved",
1362
+ outputs: [
1363
+ {
1364
+ internalType: "address",
1365
+ name: "",
1366
+ type: "address",
1367
+ },
1368
+ ],
1369
+ stateMutability: "view",
1370
+ type: "function",
1371
+ },
1372
+ {
1373
+ inputs: [
1374
+ {
1375
+ internalType: "bytes32",
1376
+ name: "role",
1377
+ type: "bytes32",
1378
+ },
1379
+ ],
1380
+ name: "getRoleAdmin",
1381
+ outputs: [
1382
+ {
1383
+ internalType: "bytes32",
1384
+ name: "",
1385
+ type: "bytes32",
1386
+ },
1387
+ ],
1388
+ stateMutability: "view",
1389
+ type: "function",
1390
+ },
1391
+ {
1392
+ inputs: [
1393
+ {
1394
+ internalType: "bytes32",
1395
+ name: "role",
1396
+ type: "bytes32",
1397
+ },
1398
+ {
1399
+ internalType: "uint256",
1400
+ name: "index",
1401
+ type: "uint256",
1402
+ },
1403
+ ],
1404
+ name: "getRoleMember",
1405
+ outputs: [
1406
+ {
1407
+ internalType: "address",
1408
+ name: "",
1409
+ type: "address",
1410
+ },
1411
+ ],
1412
+ stateMutability: "view",
1413
+ type: "function",
1414
+ },
1415
+ {
1416
+ inputs: [
1417
+ {
1418
+ internalType: "bytes32",
1419
+ name: "role",
1420
+ type: "bytes32",
1421
+ },
1422
+ ],
1423
+ name: "getRoleMemberCount",
1424
+ outputs: [
1425
+ {
1426
+ internalType: "uint256",
1427
+ name: "",
1428
+ type: "uint256",
1429
+ },
1430
+ ],
1431
+ stateMutability: "view",
1432
+ type: "function",
1433
+ },
1434
+ {
1435
+ inputs: [
1436
+ {
1437
+ internalType: "address",
1438
+ name: "user",
1439
+ type: "address",
1440
+ },
1441
+ ],
1442
+ name: "grantMinterRole",
1443
+ outputs: [],
1444
+ stateMutability: "nonpayable",
1445
+ type: "function",
1446
+ },
1447
+ {
1448
+ inputs: [
1449
+ {
1450
+ internalType: "bytes32",
1451
+ name: "role",
1452
+ type: "bytes32",
1453
+ },
1454
+ {
1455
+ internalType: "address",
1456
+ name: "account",
1457
+ type: "address",
1458
+ },
1459
+ ],
1460
+ name: "grantRole",
1461
+ outputs: [],
1462
+ stateMutability: "nonpayable",
1463
+ type: "function",
1464
+ },
1465
+ {
1466
+ inputs: [
1467
+ {
1468
+ internalType: "bytes32",
1469
+ name: "role",
1470
+ type: "bytes32",
1471
+ },
1472
+ {
1473
+ internalType: "address",
1474
+ name: "account",
1475
+ type: "address",
1476
+ },
1477
+ ],
1478
+ name: "hasRole",
1479
+ outputs: [
1480
+ {
1481
+ internalType: "bool",
1482
+ name: "",
1483
+ type: "bool",
1484
+ },
1485
+ ],
1486
+ stateMutability: "view",
1487
+ type: "function",
1488
+ },
1489
+ {
1490
+ inputs: [
1491
+ {
1492
+ internalType: "address",
1493
+ name: "owner",
1494
+ type: "address",
1495
+ },
1496
+ {
1497
+ internalType: "address",
1498
+ name: "operator",
1499
+ type: "address",
1500
+ },
1501
+ ],
1502
+ name: "isApprovedForAll",
1503
+ outputs: [
1504
+ {
1505
+ internalType: "bool",
1506
+ name: "",
1507
+ type: "bool",
1508
+ },
1509
+ ],
1510
+ stateMutability: "view",
1511
+ type: "function",
1512
+ },
1513
+ {
1514
+ inputs: [
1515
+ {
1516
+ internalType: "address",
1517
+ name: "to",
1518
+ type: "address",
1519
+ },
1520
+ {
1521
+ internalType: "uint256",
1522
+ name: "amount",
1523
+ type: "uint256",
1524
+ },
1525
+ ],
1526
+ name: "mint",
1527
+ outputs: [],
1528
+ stateMutability: "nonpayable",
1529
+ type: "function",
1530
+ },
1531
+ {
1532
+ inputs: [],
1533
+ name: "name",
1534
+ outputs: [
1535
+ {
1536
+ internalType: "string",
1537
+ name: "",
1538
+ type: "string",
1539
+ },
1540
+ ],
1541
+ stateMutability: "view",
1542
+ type: "function",
1543
+ },
1544
+ {
1545
+ inputs: [
1546
+ {
1547
+ internalType: "uint256",
1548
+ name: "tokenId",
1549
+ type: "uint256",
1550
+ },
1551
+ ],
1552
+ name: "ownerOf",
1553
+ outputs: [
1554
+ {
1555
+ internalType: "address",
1556
+ name: "",
1557
+ type: "address",
1558
+ },
1559
+ ],
1560
+ stateMutability: "view",
1561
+ type: "function",
1562
+ },
1563
+ {
1564
+ inputs: [
1565
+ {
1566
+ internalType: "bytes32",
1567
+ name: "role",
1568
+ type: "bytes32",
1569
+ },
1570
+ {
1571
+ internalType: "address",
1572
+ name: "account",
1573
+ type: "address",
1574
+ },
1575
+ ],
1576
+ name: "renounceRole",
1577
+ outputs: [],
1578
+ stateMutability: "nonpayable",
1579
+ type: "function",
1580
+ },
1581
+ {
1582
+ inputs: [
1583
+ {
1584
+ internalType: "address",
1585
+ name: "user",
1586
+ type: "address",
1587
+ },
1588
+ ],
1589
+ name: "revokeMinterRole",
1590
+ outputs: [],
1591
+ stateMutability: "nonpayable",
1592
+ type: "function",
1593
+ },
1594
+ {
1595
+ inputs: [
1596
+ {
1597
+ internalType: "bytes32",
1598
+ name: "role",
1599
+ type: "bytes32",
1600
+ },
1601
+ {
1602
+ internalType: "address",
1603
+ name: "account",
1604
+ type: "address",
1605
+ },
1606
+ ],
1607
+ name: "revokeRole",
1608
+ outputs: [],
1609
+ stateMutability: "nonpayable",
1610
+ type: "function",
1611
+ },
1612
+ {
1613
+ inputs: [],
1614
+ name: "royaltyAllowlist",
1615
+ outputs: [
1616
+ {
1617
+ internalType: "contract IRoyaltyAllowlist",
1618
+ name: "",
1619
+ type: "address",
1620
+ },
1621
+ ],
1622
+ stateMutability: "view",
1623
+ type: "function",
1624
+ },
1625
+ {
1626
+ inputs: [
1627
+ {
1628
+ internalType: "uint256",
1629
+ name: "_tokenId",
1630
+ type: "uint256",
1631
+ },
1632
+ {
1633
+ internalType: "uint256",
1634
+ name: "_salePrice",
1635
+ type: "uint256",
1636
+ },
1637
+ ],
1638
+ name: "royaltyInfo",
1639
+ outputs: [
1640
+ {
1641
+ internalType: "address",
1642
+ name: "",
1643
+ type: "address",
1644
+ },
1645
+ {
1646
+ internalType: "uint256",
1647
+ name: "",
1648
+ type: "uint256",
1649
+ },
1650
+ ],
1651
+ stateMutability: "view",
1652
+ type: "function",
1653
+ },
1654
+ {
1655
+ inputs: [
1656
+ {
1657
+ internalType: "address",
1658
+ name: "from",
1659
+ type: "address",
1660
+ },
1661
+ {
1662
+ internalType: "address",
1663
+ name: "to",
1664
+ type: "address",
1665
+ },
1666
+ {
1667
+ internalType: "uint256",
1668
+ name: "tokenId",
1669
+ type: "uint256",
1670
+ },
1671
+ ],
1672
+ name: "safeTransferFrom",
1673
+ outputs: [],
1674
+ stateMutability: "nonpayable",
1675
+ type: "function",
1676
+ },
1677
+ {
1678
+ inputs: [
1679
+ {
1680
+ internalType: "address",
1681
+ name: "from",
1682
+ type: "address",
1683
+ },
1684
+ {
1685
+ internalType: "address",
1686
+ name: "to",
1687
+ type: "address",
1688
+ },
1689
+ {
1690
+ internalType: "uint256",
1691
+ name: "tokenId",
1692
+ type: "uint256",
1693
+ },
1694
+ {
1695
+ internalType: "bytes",
1696
+ name: "data",
1697
+ type: "bytes",
1698
+ },
1699
+ ],
1700
+ name: "safeTransferFrom",
1701
+ outputs: [],
1702
+ stateMutability: "nonpayable",
1703
+ type: "function",
1704
+ },
1705
+ {
1706
+ inputs: [
1707
+ {
1708
+ internalType: "address",
1709
+ name: "operator",
1710
+ type: "address",
1711
+ },
1712
+ {
1713
+ internalType: "bool",
1714
+ name: "approved",
1715
+ type: "bool",
1716
+ },
1717
+ ],
1718
+ name: "setApprovalForAll",
1719
+ outputs: [],
1720
+ stateMutability: "nonpayable",
1721
+ type: "function",
1722
+ },
1723
+ {
1724
+ inputs: [
1725
+ {
1726
+ internalType: "string",
1727
+ name: "baseURI_",
1728
+ type: "string",
1729
+ },
1730
+ ],
1731
+ name: "setBaseURI",
1732
+ outputs: [],
1733
+ stateMutability: "nonpayable",
1734
+ type: "function",
1735
+ },
1736
+ {
1737
+ inputs: [
1738
+ {
1739
+ internalType: "string",
1740
+ name: "_contractURI",
1741
+ type: "string",
1742
+ },
1743
+ ],
1744
+ name: "setContractURI",
1745
+ outputs: [],
1746
+ stateMutability: "nonpayable",
1747
+ type: "function",
1748
+ },
1749
+ {
1750
+ inputs: [
1751
+ {
1752
+ internalType: "address",
1753
+ name: "_royaltyAllowlist",
1754
+ type: "address",
1755
+ },
1756
+ ],
1757
+ name: "setRoyaltyAllowlistRegistry",
1758
+ outputs: [],
1759
+ stateMutability: "nonpayable",
1760
+ type: "function",
1761
+ },
1762
+ {
1763
+ inputs: [
1764
+ {
1765
+ internalType: "bytes4",
1766
+ name: "interfaceId",
1767
+ type: "bytes4",
1768
+ },
1769
+ ],
1770
+ name: "supportsInterface",
1771
+ outputs: [
1772
+ {
1773
+ internalType: "bool",
1774
+ name: "",
1775
+ type: "bool",
1776
+ },
1777
+ ],
1778
+ stateMutability: "view",
1779
+ type: "function",
1780
+ },
1781
+ {
1782
+ inputs: [],
1783
+ name: "symbol",
1784
+ outputs: [
1785
+ {
1786
+ internalType: "string",
1787
+ name: "",
1788
+ type: "string",
1789
+ },
1790
+ ],
1791
+ stateMutability: "view",
1792
+ type: "function",
1793
+ },
1794
+ {
1795
+ inputs: [
1796
+ {
1797
+ internalType: "uint256",
1798
+ name: "index",
1799
+ type: "uint256",
1800
+ },
1801
+ ],
1802
+ name: "tokenByIndex",
1803
+ outputs: [
1804
+ {
1805
+ internalType: "uint256",
1806
+ name: "",
1807
+ type: "uint256",
1808
+ },
1809
+ ],
1810
+ stateMutability: "view",
1811
+ type: "function",
1812
+ },
1813
+ {
1814
+ inputs: [
1815
+ {
1816
+ internalType: "address",
1817
+ name: "owner",
1818
+ type: "address",
1819
+ },
1820
+ {
1821
+ internalType: "uint256",
1822
+ name: "index",
1823
+ type: "uint256",
1824
+ },
1825
+ ],
1826
+ name: "tokenOfOwnerByIndex",
1827
+ outputs: [
1828
+ {
1829
+ internalType: "uint256",
1830
+ name: "",
1831
+ type: "uint256",
1832
+ },
1833
+ ],
1834
+ stateMutability: "view",
1835
+ type: "function",
1836
+ },
1837
+ {
1838
+ inputs: [
1839
+ {
1840
+ internalType: "uint256",
1841
+ name: "tokenId",
1842
+ type: "uint256",
1843
+ },
1844
+ ],
1845
+ name: "tokenURI",
1846
+ outputs: [
1847
+ {
1848
+ internalType: "string",
1849
+ name: "",
1850
+ type: "string",
1851
+ },
1852
+ ],
1853
+ stateMutability: "view",
1854
+ type: "function",
1855
+ },
1856
+ {
1857
+ inputs: [],
1858
+ name: "totalSupply",
1859
+ outputs: [
1860
+ {
1861
+ internalType: "uint256",
1862
+ name: "",
1863
+ type: "uint256",
1864
+ },
1865
+ ],
1866
+ stateMutability: "view",
1867
+ type: "function",
1868
+ },
1869
+ {
1870
+ inputs: [
1871
+ {
1872
+ internalType: "address",
1873
+ name: "from",
1874
+ type: "address",
1875
+ },
1876
+ {
1877
+ internalType: "address",
1878
+ name: "to",
1879
+ type: "address",
1880
+ },
1881
+ {
1882
+ internalType: "uint256",
1883
+ name: "tokenId",
1884
+ type: "uint256",
1885
+ },
1886
+ ],
1887
+ name: "transferFrom",
1888
+ outputs: [],
1889
+ stateMutability: "nonpayable",
1890
+ type: "function",
1891
+ },
1892
+ ];
1893
+ class ImmutableERC721Base__factory {
1894
+ static abi = _abi;
1895
+ static createInterface() {
1896
+ return new utils.Interface(_abi);
1897
+ }
1898
+ static connect(address, signerOrProvider) {
1899
+ return new Contract(address, _abi, signerOrProvider);
1900
+ }
1901
+ }
1902
+
1903
+ class ERC721Factory {
1904
+ erc721;
1905
+ constructor(contractAddress, provider) {
1906
+ this.erc721 = ImmutableERC721Base__factory.connect(contractAddress, provider);
1907
+ }
1908
+ create() {
1909
+ return new ERC721(this.erc721);
1910
+ }
1911
+ }
1912
+
1913
+ class SeaportLibFactory {
1914
+ defaultSeaportContractAddress;
1915
+ provider;
1916
+ constructor(defaultSeaportContractAddress, provider) {
1917
+ this.defaultSeaportContractAddress = defaultSeaportContractAddress;
1918
+ this.provider = provider;
1919
+ }
1920
+ create(orderSeaportVersion, orderSeaportAddress) {
1921
+ const seaportVersion = orderSeaportVersion ?? SEAPORT_CONTRACT_VERSION_V1_5;
1922
+ const seaportContractAddress = orderSeaportAddress ?? this.defaultSeaportContractAddress;
1923
+ return new Seaport$1(this.provider, {
1924
+ seaportVersion,
1925
+ balanceAndApprovalChecksOnOrderCreation: true,
1926
+ overrides: {
1927
+ contractAddress: seaportContractAddress,
1928
+ },
1929
+ });
1930
+ }
1931
+ }
1932
+
1933
+ /**
1934
+ * zkEVM orderbook SDK
1935
+ * @constructor
1936
+ * @param {OrderbookModuleConfiguration} config - Configuration for Immutable services.
1937
+ */
1938
+ class Orderbook {
1939
+ apiClient;
1940
+ seaport;
1941
+ orderbookConfig;
1942
+ constructor(config) {
1943
+ const obConfig = getOrderbookConfig(config.baseConfig.environment);
1944
+ const finalConfig = {
1945
+ ...obConfig,
1946
+ ...config.overrides,
1947
+ };
1948
+ if (!finalConfig) {
1949
+ throw new Error('Orderbook configuration not passed, please specify the environment under config.baseConfig.environment');
1950
+ }
1951
+ this.orderbookConfig = finalConfig;
1952
+ const { apiEndpoint, chainName } = this.orderbookConfig;
1953
+ if (!apiEndpoint) {
1954
+ throw new Error('API endpoint must be provided');
1955
+ }
1956
+ this.apiClient = new ImmutableApiClientFactory(apiEndpoint, chainName, this.orderbookConfig.seaportContractAddress).create();
1957
+ const seaportLibFactory = new SeaportLibFactory(this.orderbookConfig.seaportContractAddress, this.orderbookConfig.provider);
1958
+ this.seaport = new Seaport(seaportLibFactory, this.orderbookConfig.provider, this.orderbookConfig.seaportContractAddress, this.orderbookConfig.zoneContractAddress);
1959
+ }
1960
+ /**
1961
+ * Return the configuration for the orderbook module.
1962
+ * @return {OrderbookModuleConfiguration} The configuration for the orderbook module.
1963
+ */
1964
+ config() {
1965
+ return this.orderbookConfig;
1966
+ }
1967
+ /**
1968
+ * Get an order by ID
1969
+ * @param {string} listingId - The listingId to find.
1970
+ * @return {ListingResult} The returned order result.
1971
+ */
1972
+ getListing(listingId) {
1973
+ return this.apiClient.getListing(listingId);
1974
+ }
1975
+ /**
1976
+ * List orders. This method is used to get a list of orders filtered by conditions specified
1977
+ * in the params object.
1978
+ * @param {ListOrderParams} listOrderParams - Filtering, ordering and page parameters.
1979
+ * @return {Orders} The paged orders.
1980
+ */
1981
+ listListings(listOrderParams) {
1982
+ return this.apiClient.listListings(listOrderParams);
1983
+ }
1984
+ /**
1985
+ * Get required transactions and messages for signing prior to creating a listing
1986
+ * through the createListing method
1987
+ * @param {PrepareListingParams} prepareListingParams - Details about the listing to be created.
1988
+ * @return {PrepareListingResponse} PrepareListingResponse includes
1989
+ * the unsigned approval transaction, the typed order message for signing and
1990
+ * the order components that can be submitted to `createListing` with a signature.
1991
+ */
1992
+ async prepareListing({ makerAddress, sell, buy, orderExpiry, }) {
1993
+ const erc721 = new ERC721Factory(sell.contractAddress, this.orderbookConfig.provider).create();
1994
+ const royaltyInfo = await erc721.royaltyInfo(sell.tokenId, buy.amount);
1995
+ return this.seaport.prepareSeaportOrder(makerAddress, sell, buy, royaltyInfo,
1996
+ // Default order start to now
1997
+ new Date(),
1998
+ // Default order expiry to 2 years from now
1999
+ orderExpiry || new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 2));
2000
+ }
2001
+ /**
2002
+ * Create an order
2003
+ * @param {CreateListingParams} createListingParams - create an order with the given params.
2004
+ * @return {ListingResult} The result of the order created in the Immutable services.
2005
+ */
2006
+ createListing(createListingParams) {
2007
+ return this.apiClient.createListing(createListingParams);
2008
+ }
2009
+ /**
2010
+ * Get unsigned transactions that can be submitted to fulfil an open order. If the approval
2011
+ * transaction exists it must be signed and submitted to the chain before the fulfilment
2012
+ * transaction can be submitted or it will be reverted.
2013
+ * @param {string} listingId - The listingId to fulfil.
2014
+ * @param {string} fulfillerAddress - The address of the account fulfilling the order.
2015
+ * @return {FulfillOrderResponse} Approval and fulfilment transactions.
2016
+ */
2017
+ async fulfillOrder(listingId, takerAddress) {
2018
+ const fulfillmentDataRes = await this.apiClient.fulfillmentData([{
2019
+ order_id: listingId,
2020
+ // fee: takerFee,
2021
+ fee: undefined,
2022
+ }]);
2023
+ if (fulfillmentDataRes.result.length !== 1) {
2024
+ throw new Error('unexpected fulfillment data result length');
2025
+ }
2026
+ const extraData = fulfillmentDataRes.result[0].extra_data;
2027
+ const orderResult = fulfillmentDataRes.result[0].order;
2028
+ if (orderResult.status !== OrderStatus.ACTIVE) {
2029
+ throw new Error(`Cannot fulfil order that is not active. Current status: ${orderResult.status}`);
2030
+ }
2031
+ return this.seaport.fulfillOrder(orderResult, takerAddress, extraData);
2032
+ }
2033
+ /**
2034
+ * Get an unsigned cancel order transaction. Orders can only be cancelled by
2035
+ * the account that created them.
2036
+ * @param {string} listingId - The listingId to cancel.
2037
+ * @param {string} accountAddress - The address of the account cancelling the order.
2038
+ * @return {CancelOrderResponse} The unsigned cancel order transaction
2039
+ */
2040
+ async cancelOrder(listingId, accountAddress) {
2041
+ const orderResult = await this.apiClient.getListing(listingId);
2042
+ if (orderResult.result.status !== OrderStatus.ACTIVE
2043
+ && orderResult.result.status !== OrderStatus.INACTIVE
2044
+ && orderResult.result.status !== OrderStatus.PENDING) {
2045
+ throw new Error(`Cannot cancel order with status ${orderResult.result.status}`);
2046
+ }
2047
+ if (orderResult.result.account_address !== accountAddress.toLowerCase()) {
2048
+ throw new Error(`Only account ${orderResult.result.account_address} can cancel order ${listingId}`);
2049
+ }
2050
+ const cancelOrderTransaction = await this.seaport.cancelOrder(orderResult.result, accountAddress);
2051
+ return { unsignedCancelOrderTransaction: cancelOrderTransaction };
2052
+ }
2053
+ }
2054
+
2055
+ // Consumers might want an estimated gas limit for fulfilling an order
2056
+ // without calling the transaction builder. This is an estimate that
2057
+ // should work for all fulfillment scenarios.
2058
+ const ESTIMATED_FULFILLMENT_GAS_GWEI = 400000;
2059
+ const constants = {
2060
+ estimatedFulfillmentGasGwei: ESTIMATED_FULFILLMENT_GAS_GWEI,
2061
+ };
2062
+
2063
+ export { ActionType, Orderbook, SignablePurpose, TransactionPurpose, constants };