@bosonprotocol/core-sdk 1.33.0-alpha.0 → 1.33.0-alpha.10

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.
Files changed (87) hide show
  1. package/dist/cjs/core-sdk.d.ts +2 -1
  2. package/dist/cjs/core-sdk.d.ts.map +1 -1
  3. package/dist/cjs/core-sdk.js +3 -1
  4. package/dist/cjs/core-sdk.js.map +1 -1
  5. package/dist/cjs/erc165/handler.d.ts +7 -0
  6. package/dist/cjs/erc165/handler.d.ts.map +1 -0
  7. package/dist/cjs/erc165/handler.js +27 -0
  8. package/dist/cjs/erc165/handler.js.map +1 -0
  9. package/dist/cjs/erc165/interface.d.ts +3 -0
  10. package/dist/cjs/erc165/interface.d.ts.map +1 -0
  11. package/dist/cjs/erc165/interface.js +7 -0
  12. package/dist/cjs/erc165/interface.js.map +1 -0
  13. package/dist/cjs/erc165/mixin.d.ts +6 -0
  14. package/dist/cjs/erc165/mixin.d.ts.map +1 -0
  15. package/dist/cjs/erc165/mixin.js +26 -0
  16. package/dist/cjs/erc165/mixin.js.map +1 -0
  17. package/dist/cjs/event-logs/mixin.d.ts +6 -0
  18. package/dist/cjs/event-logs/mixin.d.ts.map +1 -1
  19. package/dist/cjs/event-logs/mixin.js +10 -0
  20. package/dist/cjs/event-logs/mixin.js.map +1 -1
  21. package/dist/cjs/event-logs/subgraph.d.ts +2 -1
  22. package/dist/cjs/event-logs/subgraph.d.ts.map +1 -1
  23. package/dist/cjs/event-logs/subgraph.js +9 -1
  24. package/dist/cjs/event-logs/subgraph.js.map +1 -1
  25. package/dist/cjs/offers/mixin.d.ts +1 -1
  26. package/dist/cjs/offers/mixin.d.ts.map +1 -1
  27. package/dist/cjs/offers/mixin.js +216 -25
  28. package/dist/cjs/offers/mixin.js.map +1 -1
  29. package/dist/cjs/subgraph.d.ts +41 -0
  30. package/dist/cjs/subgraph.d.ts.map +1 -1
  31. package/dist/cjs/subgraph.js +40 -2
  32. package/dist/cjs/subgraph.js.map +1 -1
  33. package/dist/cjs/utils/graphql.d.ts +7 -0
  34. package/dist/cjs/utils/graphql.d.ts.map +1 -1
  35. package/dist/cjs/utils/promises.d.ts +2 -0
  36. package/dist/cjs/utils/promises.d.ts.map +1 -0
  37. package/dist/cjs/utils/promises.js +32 -0
  38. package/dist/cjs/utils/promises.js.map +1 -0
  39. package/dist/esm/core-sdk.d.ts +2 -1
  40. package/dist/esm/core-sdk.d.ts.map +1 -1
  41. package/dist/esm/core-sdk.js +3 -1
  42. package/dist/esm/core-sdk.js.map +1 -1
  43. package/dist/esm/erc165/handler.d.ts +7 -0
  44. package/dist/esm/erc165/handler.d.ts.map +1 -0
  45. package/dist/esm/erc165/handler.js +12 -0
  46. package/dist/esm/erc165/handler.js.map +1 -0
  47. package/dist/esm/erc165/interface.d.ts +3 -0
  48. package/dist/esm/erc165/interface.d.ts.map +1 -0
  49. package/dist/esm/erc165/interface.js +4 -0
  50. package/dist/esm/erc165/interface.js.map +1 -0
  51. package/dist/esm/erc165/mixin.d.ts +6 -0
  52. package/dist/esm/erc165/mixin.d.ts.map +1 -0
  53. package/dist/esm/erc165/mixin.js +11 -0
  54. package/dist/esm/erc165/mixin.js.map +1 -0
  55. package/dist/esm/event-logs/mixin.d.ts +6 -0
  56. package/dist/esm/event-logs/mixin.d.ts.map +1 -1
  57. package/dist/esm/event-logs/mixin.js +9 -1
  58. package/dist/esm/event-logs/mixin.js.map +1 -1
  59. package/dist/esm/event-logs/subgraph.d.ts +2 -1
  60. package/dist/esm/event-logs/subgraph.d.ts.map +1 -1
  61. package/dist/esm/event-logs/subgraph.js +5 -0
  62. package/dist/esm/event-logs/subgraph.js.map +1 -1
  63. package/dist/esm/offers/mixin.d.ts +1 -1
  64. package/dist/esm/offers/mixin.d.ts.map +1 -1
  65. package/dist/esm/offers/mixin.js +158 -26
  66. package/dist/esm/offers/mixin.js.map +1 -1
  67. package/dist/esm/subgraph.d.ts +41 -0
  68. package/dist/esm/subgraph.d.ts.map +1 -1
  69. package/dist/esm/subgraph.js +38 -0
  70. package/dist/esm/subgraph.js.map +1 -1
  71. package/dist/esm/utils/graphql.d.ts +7 -0
  72. package/dist/esm/utils/graphql.d.ts.map +1 -1
  73. package/dist/esm/utils/promises.d.ts +2 -0
  74. package/dist/esm/utils/promises.d.ts.map +1 -0
  75. package/dist/esm/utils/promises.js +14 -0
  76. package/dist/esm/utils/promises.js.map +1 -0
  77. package/package.json +3 -3
  78. package/src/accounts/queries.graphql +32 -0
  79. package/src/core-sdk.ts +5 -2
  80. package/src/erc165/handler.ts +21 -0
  81. package/src/erc165/interface.ts +4 -0
  82. package/src/erc165/mixin.ts +13 -0
  83. package/src/event-logs/mixin.ts +17 -1
  84. package/src/event-logs/subgraph.ts +13 -1
  85. package/src/offers/mixin.ts +212 -28
  86. package/src/subgraph.ts +91 -0
  87. package/src/utils/promises.ts +18 -0
@@ -11,11 +11,17 @@ import {
11
11
  TransactionResponse,
12
12
  Log,
13
13
  TokenType,
14
- EvaluationMethod
14
+ EvaluationMethod,
15
+ GatingType
15
16
  } from "@bosonprotocol/common";
17
+ import groupBy from "lodash/groupBy";
16
18
  import { BigNumber, BigNumberish } from "@ethersproject/bignumber";
17
19
  import { getValueFromLogs, getValuesFromLogs } from "../utils/logs";
18
20
  import { ITokenInfo, TokenInfoManager } from "../utils/tokenInfoManager";
21
+ import { batchTasks } from "../utils/promises";
22
+ import { ExchangesMixin } from "../exchanges/mixin";
23
+ import { EventLogsMixin } from "../event-logs/mixin";
24
+ import { MetadataMixin } from "../metadata/mixin";
19
25
 
20
26
  export class OfferMixin extends BaseCoreSDK {
21
27
  /* -------------------------------------------------------------------------- */
@@ -405,53 +411,231 @@ export class OfferMixin extends BaseCoreSDK {
405
411
  }
406
412
 
407
413
  public async checkTokenGatedCondition(
408
- offerCondition: subgraph.OfferFieldsFragment["condition"],
414
+ offerId: subgraph.OfferFieldsFragment["id"],
409
415
  buyerAddress: string
410
416
  ): Promise<boolean> {
417
+ const offer = await this.getOfferById(offerId);
418
+
419
+ if (!offer?.condition) {
420
+ return true;
421
+ }
422
+ const getCanTokenIdBeUsedToCommit = async (): Promise<
423
+ (tokenId: string) => boolean
424
+ > => {
425
+ const conditionalCommitLogs = await (
426
+ this as unknown as EventLogsMixin
427
+ ).getConditionalCommitAuthorizedEventLogs({
428
+ conditionalCommitAuthorizedLogsFilter: {
429
+ groupId: offer.condition.id, // all offers of the same product have the same condition.id
430
+ buyerAddress
431
+ }
432
+ });
433
+
434
+ const tokenIdMapWithMultipleEntries = groupBy(
435
+ conditionalCommitLogs,
436
+ (log) => log.tokenId
437
+ );
438
+ type TokenId = string;
439
+ // build a map of tokenId -> log with the min available commits (or the most recent log) in all the logs
440
+ const tokenIdToAvailableCommitsMap = new Map<
441
+ TokenId,
442
+ subgraph.BaseConditionalCommitAuthorizedEventLogsFieldsFragment
443
+ >();
444
+ Object.entries(tokenIdMapWithMultipleEntries).forEach(
445
+ ([tokenId, logs]) => {
446
+ let logWithMinAvailableCommits = logs[0];
447
+ for (const log of logs) {
448
+ const currentAvailableCommits =
449
+ Number(log.maxCommits) - Number(log.commitCount);
450
+ const savedAvailableCommits =
451
+ Number(logWithMinAvailableCommits.maxCommits) -
452
+ Number(logWithMinAvailableCommits.commitCount);
453
+ if (currentAvailableCommits < savedAvailableCommits) {
454
+ logWithMinAvailableCommits = log;
455
+ }
456
+ }
457
+ tokenIdToAvailableCommitsMap.set(tokenId, logWithMinAvailableCommits);
458
+ }
459
+ );
460
+ const canTokenIdBeUsedToCommit = (tokenId: TokenId): boolean => {
461
+ if (!tokenIdToAvailableCommitsMap.has(tokenId)) {
462
+ return true;
463
+ }
464
+ const log = tokenIdToAvailableCommitsMap.get(tokenId);
465
+ return Number(log.maxCommits) - Number(log.commitCount) > 0;
466
+ };
467
+ return canTokenIdBeUsedToCommit;
468
+ };
469
+
470
+ const getCurrentCommits = async (): Promise<number> => {
471
+ const exchanges = await (this as unknown as ExchangesMixin).getExchanges({
472
+ exchangesFilter: {
473
+ buyer: buyerAddress,
474
+ offer_: {
475
+ condition: offer.condition.id
476
+ }
477
+ }
478
+ });
479
+
480
+ const currentCommits = exchanges.length;
481
+ return currentCommits;
482
+ };
483
+
484
+ const concurrencyLimit = 5;
411
485
  const {
412
- minTokenId: tokenId,
486
+ minTokenId: _minTokenId,
487
+ maxTokenId: _maxTokenId,
413
488
  tokenType,
414
489
  threshold,
415
490
  method,
416
- tokenAddress
417
- } = offerCondition;
491
+ tokenAddress,
492
+ gatingType,
493
+ maxCommits: _maxCommits
494
+ } = offer.condition;
495
+ const maxCommits = Number(_maxCommits);
496
+
418
497
  if (tokenType === TokenType.FungibleToken) {
419
498
  const balance: string = await erc20.handler.balanceOf({
420
499
  contractAddress: tokenAddress,
421
500
  owner: buyerAddress,
422
501
  web3Lib: this._web3Lib
423
502
  });
424
- return BigNumber.from(balance).gte(threshold);
503
+ if (!BigNumber.from(balance).gte(threshold)) {
504
+ return false;
505
+ }
506
+ const currentCommits = await getCurrentCommits();
507
+ return currentCommits < maxCommits;
425
508
  }
509
+
510
+ const minTokenId = Number(_minTokenId);
511
+ const maxTokenId = Number(_maxTokenId);
512
+
426
513
  if (tokenType === TokenType.NonFungibleToken) {
427
- if (method === EvaluationMethod.Threshold) {
428
- const balance: string = await erc721.handler.balanceOf({
429
- contractAddress: tokenAddress,
430
- owner: buyerAddress,
431
- web3Lib: this._web3Lib
432
- });
433
- return BigNumber.from(balance).gte(threshold);
514
+ if (gatingType === GatingType.PerAddress) {
515
+ if (method === EvaluationMethod.Threshold) {
516
+ const balance: string = await erc721.handler.balanceOf({
517
+ contractAddress: tokenAddress,
518
+ owner: buyerAddress,
519
+ web3Lib: this._web3Lib
520
+ });
521
+ if (!BigNumber.from(balance).gte(threshold)) {
522
+ return false;
523
+ }
524
+ const currentCommits = await getCurrentCommits();
525
+ return currentCommits < maxCommits;
526
+ }
527
+ if (method === EvaluationMethod.TokenRange) {
528
+ const promises: (() => Promise<string>)[] = [];
529
+ for (let i = minTokenId; i <= maxTokenId; i++) {
530
+ const tokenId = i;
531
+ promises.push(() =>
532
+ erc721.handler.ownerOf({
533
+ contractAddress: tokenAddress,
534
+ tokenId,
535
+ web3Lib: this._web3Lib
536
+ })
537
+ );
538
+ }
539
+ const currentCommits = await getCurrentCommits();
540
+ for await (const owners of batchTasks(promises, concurrencyLimit)) {
541
+ if (owners.some((owner) => owner === buyerAddress)) {
542
+ return currentCommits < maxCommits;
543
+ }
544
+ }
545
+ return false;
546
+ }
547
+ throw new Error(
548
+ `Unsupported method=${method} for this tokenType=${tokenType} and gatingType=${gatingType}`
549
+ );
434
550
  }
435
- if (method === EvaluationMethod.SpecificToken) {
436
- const owner: string = await erc721.handler.ownerOf({
437
- contractAddress: tokenAddress,
438
- tokenId,
439
- web3Lib: this._web3Lib
440
- });
441
- return owner === buyerAddress;
551
+ if (gatingType === GatingType.PerTokenId) {
552
+ if (method === EvaluationMethod.TokenRange) {
553
+ const canTokenIdBeUsedToCommit = await getCanTokenIdBeUsedToCommit();
554
+ const promises: (() => Promise<string>)[] = [];
555
+ for (let i = minTokenId; i <= maxTokenId; i++) {
556
+ const tokenId = i;
557
+ promises.push(() =>
558
+ erc721.handler.ownerOf({
559
+ contractAddress: tokenAddress,
560
+ tokenId,
561
+ web3Lib: this._web3Lib
562
+ })
563
+ );
564
+ }
565
+ let tokenId = minTokenId;
566
+ for await (const owners of batchTasks(promises, concurrencyLimit)) {
567
+ if (
568
+ owners.some((owner) => owner === buyerAddress) &&
569
+ canTokenIdBeUsedToCommit(tokenId.toString())
570
+ ) {
571
+ return true;
572
+ }
573
+ tokenId++;
574
+ }
575
+ return false;
576
+ }
577
+ throw new Error(
578
+ `Unsupported method=${method} for this tokenType=${tokenType} and gatingType=${gatingType}`
579
+ );
442
580
  }
443
581
  throw new Error(
444
- `Unsupported method=${method} for this tokenType=${tokenType}`
582
+ `Unsupported gatingType=${gatingType} for this tokenType=${tokenType}`
445
583
  );
446
584
  }
447
585
  if (tokenType === TokenType.MultiToken) {
448
- const balance: string = await erc1155.handler.balanceOf({
449
- contractAddress: tokenAddress,
450
- tokenId,
451
- owner: buyerAddress,
452
- web3Lib: this._web3Lib
453
- });
454
- return BigNumber.from(balance).gte(threshold);
586
+ if (gatingType === GatingType.PerAddress) {
587
+ const promises: (() => Promise<string>)[] = [];
588
+ for (let i = minTokenId; i <= maxTokenId; i++) {
589
+ const tokenId = i;
590
+ promises.push(() =>
591
+ erc1155.handler.balanceOf({
592
+ contractAddress: tokenAddress,
593
+ tokenId,
594
+ owner: buyerAddress,
595
+ web3Lib: this._web3Lib
596
+ })
597
+ );
598
+ }
599
+ for await (const balances of batchTasks(promises, concurrencyLimit)) {
600
+ if (
601
+ balances.some((balance) => BigNumber.from(balance).gte(threshold))
602
+ ) {
603
+ return true;
604
+ }
605
+ }
606
+ return false;
607
+ }
608
+ if (gatingType === GatingType.PerTokenId) {
609
+ const canTokenIdBeUsedToCommit = await getCanTokenIdBeUsedToCommit();
610
+ const promises: (() => Promise<string>)[] = [];
611
+ for (let i = minTokenId; i <= maxTokenId; i++) {
612
+ const tokenId = i;
613
+ promises.push(() =>
614
+ erc1155.handler.balanceOf({
615
+ contractAddress: tokenAddress,
616
+ tokenId,
617
+ owner: buyerAddress,
618
+ web3Lib: this._web3Lib
619
+ })
620
+ );
621
+ }
622
+ let tokenId = minTokenId;
623
+ for await (const balances of batchTasks(promises, concurrencyLimit)) {
624
+ if (
625
+ balances.some((balance) =>
626
+ BigNumber.from(balance).gte(threshold)
627
+ ) &&
628
+ canTokenIdBeUsedToCommit(tokenId.toString())
629
+ ) {
630
+ return true;
631
+ }
632
+ tokenId++;
633
+ }
634
+ return false;
635
+ }
636
+ throw new Error(
637
+ `Unsupported gatingType=${gatingType} for this tokenType=${tokenType}`
638
+ );
455
639
  }
456
640
  throw new Error(`Unsupported tokenType=${tokenType}`);
457
641
  }
package/src/subgraph.ts CHANGED
@@ -13514,6 +13514,32 @@ export type GetDisputeResolversQueryQuery = {
13514
13514
  }>;
13515
13515
  };
13516
13516
 
13517
+ export type GetConditionalCommitAuthorizedEventLogsQueryQueryVariables = Exact<{
13518
+ conditionalCommitAuthorizedLogsSkip?: InputMaybe<Scalars["Int"]>;
13519
+ conditionalCommitAuthorizedLogsFirst?: InputMaybe<Scalars["Int"]>;
13520
+ conditionalCommitAuthorizedLogsOrderBy?: InputMaybe<ConditionalCommitAuthorizedEventLog_OrderBy>;
13521
+ conditionalCommitAuthorizedLogsOrderDirection?: InputMaybe<OrderDirection>;
13522
+ conditionalCommitAuthorizedLogsFilter?: InputMaybe<ConditionalCommitAuthorizedEventLog_Filter>;
13523
+ }>;
13524
+
13525
+ export type GetConditionalCommitAuthorizedEventLogsQueryQuery = {
13526
+ __typename?: "Query";
13527
+ conditionalCommitAuthorizedEventLogs: Array<{
13528
+ __typename?: "ConditionalCommitAuthorizedEventLog";
13529
+ id: string;
13530
+ hash: string;
13531
+ groupId: string;
13532
+ gating: number;
13533
+ commitCount: string;
13534
+ buyerAddress: string;
13535
+ maxCommits: string;
13536
+ offerId: string;
13537
+ timestamp: string;
13538
+ tokenId: string;
13539
+ type: EventType;
13540
+ }>;
13541
+ };
13542
+
13517
13543
  export type SellerFieldsFragment = {
13518
13544
  __typename?: "Seller";
13519
13545
  id: string;
@@ -15454,6 +15480,21 @@ export type BaseDisputeResolutionTermsEntityFieldsFragment = {
15454
15480
  buyerEscalationDeposit: string;
15455
15481
  };
15456
15482
 
15483
+ export type BaseConditionalCommitAuthorizedEventLogsFieldsFragment = {
15484
+ __typename?: "ConditionalCommitAuthorizedEventLog";
15485
+ id: string;
15486
+ hash: string;
15487
+ groupId: string;
15488
+ gating: number;
15489
+ commitCount: string;
15490
+ buyerAddress: string;
15491
+ maxCommits: string;
15492
+ offerId: string;
15493
+ timestamp: string;
15494
+ tokenId: string;
15495
+ type: EventType;
15496
+ };
15497
+
15457
15498
  export type GetDisputeByIdQueryQueryVariables = Exact<{
15458
15499
  disputeId: Scalars["ID"];
15459
15500
  offersSkip?: InputMaybe<Scalars["Int"]>;
@@ -35607,6 +35648,21 @@ export const DisputeResolverFieldsFragmentDoc = gql`
35607
35648
  ${BaseOfferFieldsFragmentDoc}
35608
35649
  ${BaseEventLogFieldsFragmentDoc}
35609
35650
  `;
35651
+ export const BaseConditionalCommitAuthorizedEventLogsFieldsFragmentDoc = gql`
35652
+ fragment BaseConditionalCommitAuthorizedEventLogsFields on ConditionalCommitAuthorizedEventLog {
35653
+ id
35654
+ hash
35655
+ groupId
35656
+ gating
35657
+ commitCount
35658
+ buyerAddress
35659
+ maxCommits
35660
+ offerId
35661
+ timestamp
35662
+ tokenId
35663
+ type
35664
+ }
35665
+ `;
35610
35666
  export const DisputeFieldsFragmentDoc = gql`
35611
35667
  fragment DisputeFields on Dispute {
35612
35668
  ...BaseDisputeFields
@@ -36048,6 +36104,26 @@ export const GetDisputeResolversQueryDocument = gql`
36048
36104
  }
36049
36105
  ${DisputeResolverFieldsFragmentDoc}
36050
36106
  `;
36107
+ export const GetConditionalCommitAuthorizedEventLogsQueryDocument = gql`
36108
+ query getConditionalCommitAuthorizedEventLogsQuery(
36109
+ $conditionalCommitAuthorizedLogsSkip: Int
36110
+ $conditionalCommitAuthorizedLogsFirst: Int
36111
+ $conditionalCommitAuthorizedLogsOrderBy: ConditionalCommitAuthorizedEventLog_orderBy
36112
+ $conditionalCommitAuthorizedLogsOrderDirection: OrderDirection
36113
+ $conditionalCommitAuthorizedLogsFilter: ConditionalCommitAuthorizedEventLog_filter
36114
+ ) {
36115
+ conditionalCommitAuthorizedEventLogs(
36116
+ skip: $conditionalCommitAuthorizedLogsSkip
36117
+ first: $conditionalCommitAuthorizedLogsFirst
36118
+ orderBy: $conditionalCommitAuthorizedLogsOrderBy
36119
+ orderDirection: $conditionalCommitAuthorizedLogsOrderDirection
36120
+ where: $conditionalCommitAuthorizedLogsFilter
36121
+ ) {
36122
+ ...BaseConditionalCommitAuthorizedEventLogsFields
36123
+ }
36124
+ }
36125
+ ${BaseConditionalCommitAuthorizedEventLogsFieldsFragmentDoc}
36126
+ `;
36051
36127
  export const GetDisputeByIdQueryDocument = gql`
36052
36128
  query getDisputeByIdQuery(
36053
36129
  $disputeId: ID!
@@ -36592,6 +36668,21 @@ export function getSdk(
36592
36668
  "query"
36593
36669
  );
36594
36670
  },
36671
+ getConditionalCommitAuthorizedEventLogsQuery(
36672
+ variables?: GetConditionalCommitAuthorizedEventLogsQueryQueryVariables,
36673
+ requestHeaders?: Dom.RequestInit["headers"]
36674
+ ): Promise<GetConditionalCommitAuthorizedEventLogsQueryQuery> {
36675
+ return withWrapper(
36676
+ (wrappedRequestHeaders) =>
36677
+ client.request<GetConditionalCommitAuthorizedEventLogsQueryQuery>(
36678
+ GetConditionalCommitAuthorizedEventLogsQueryDocument,
36679
+ variables,
36680
+ { ...requestHeaders, ...wrappedRequestHeaders }
36681
+ ),
36682
+ "getConditionalCommitAuthorizedEventLogsQuery",
36683
+ "query"
36684
+ );
36685
+ },
36595
36686
  getDisputeByIdQuery(
36596
36687
  variables: GetDisputeByIdQueryQueryVariables,
36597
36688
  requestHeaders?: Dom.RequestInit["headers"]
@@ -0,0 +1,18 @@
1
+ export async function* batchTasks<T>(
2
+ tasks: (() => Promise<T>)[],
3
+ limit: number,
4
+ taskCallback = (r: T): T => r
5
+ ) {
6
+ // iterate over tasks
7
+ for (let i = 0; i < tasks.length; i = i + limit) {
8
+ // grab the batch of tasks for current iteration
9
+ const batch = tasks.slice(i, i + limit);
10
+ // wait for them to resolve concurrently
11
+ const result = await Promise.all(
12
+ // optionally attach callback to perform any side effects
13
+ batch.map((task) => task().then((r) => taskCallback(r)))
14
+ );
15
+ // yield the batched result and let consumer know
16
+ yield result;
17
+ }
18
+ }