@xoxno/sdk-js 0.0.1

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 (137) hide show
  1. package/.editorconfig +9 -0
  2. package/.eslintrc.json +19 -0
  3. package/.github/workflows/npm-publish-github-packages.yml +36 -0
  4. package/.prettierrc +8 -0
  5. package/.releaserc +10 -0
  6. package/.vscode/settings.json +3 -0
  7. package/LICENSE +674 -0
  8. package/commitlint.config.js +3 -0
  9. package/coverage/clover.xml +280 -0
  10. package/coverage/coverage-final.json +12 -0
  11. package/coverage/lcov-report/base.css +224 -0
  12. package/coverage/lcov-report/block-navigation.js +87 -0
  13. package/coverage/lcov-report/collection/index.html +116 -0
  14. package/coverage/lcov-report/collection/index.ts.html +559 -0
  15. package/coverage/lcov-report/favicon.png +0 -0
  16. package/coverage/lcov-report/index.html +161 -0
  17. package/coverage/lcov-report/interactions/index.html +116 -0
  18. package/coverage/lcov-report/interactions/index.ts.html +775 -0
  19. package/coverage/lcov-report/nft/index.html +116 -0
  20. package/coverage/lcov-report/nft/index.ts.html +379 -0
  21. package/coverage/lcov-report/prettify.css +1 -0
  22. package/coverage/lcov-report/prettify.js +2 -0
  23. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  24. package/coverage/lcov-report/sorter.js +196 -0
  25. package/coverage/lcov-report/utils/SmartContractAbis.ts.html +331 -0
  26. package/coverage/lcov-report/utils/SmartContractService.ts.html +136 -0
  27. package/coverage/lcov-report/utils/api.ts.html +484 -0
  28. package/coverage/lcov-report/utils/const.ts.html +163 -0
  29. package/coverage/lcov-report/utils/getActivity.ts.html +250 -0
  30. package/coverage/lcov-report/utils/helpers.ts.html +127 -0
  31. package/coverage/lcov-report/utils/index.html +221 -0
  32. package/coverage/lcov-report/utils/regex.ts.html +106 -0
  33. package/coverage/lcov-report/utils/scCalls.ts.html +229 -0
  34. package/coverage/lcov.info +525 -0
  35. package/docs/.nojekyll +1 -0
  36. package/docs/assets/highlight.css +64 -0
  37. package/docs/assets/main.js +58 -0
  38. package/docs/assets/search.js +1 -0
  39. package/docs/assets/style.css +1279 -0
  40. package/docs/classes/collection.CollectionModule.html +232 -0
  41. package/docs/classes/interactions.SCInteraction.html +370 -0
  42. package/docs/classes/nft.NFTModule.html +208 -0
  43. package/docs/classes/utils_SmartContractAbis.SmartContractAbis.html +198 -0
  44. package/docs/classes/utils_api.APIClient.html +212 -0
  45. package/docs/classes/utils_scCalls.ContractQueryRunner.html +129 -0
  46. package/docs/enums/types_collection.FieldsToSelect.html +186 -0
  47. package/docs/enums/types_collection.Marketplace.html +102 -0
  48. package/docs/enums/types_collection.SearchOrderBy.html +130 -0
  49. package/docs/enums/types_trading.OrderByTradingActivity.html +102 -0
  50. package/docs/enums/types_trading.SelectFieldsTradingActivity.html +144 -0
  51. package/docs/enums/utils_api.Chain.html +88 -0
  52. package/docs/functions/utils_SmartContractService.getSmartContract.html +77 -0
  53. package/docs/functions/utils_getActivity.getActivity.html +89 -0
  54. package/docs/functions/utils_helpers.getIdentifierFromColAndNonce.html +76 -0
  55. package/docs/functions/utils_helpers.nonceToHex.html +74 -0
  56. package/docs/functions/utils_regex.isValidCollectionTicker.html +74 -0
  57. package/docs/functions/utils_regex.isValidNftIdentifier.html +74 -0
  58. package/docs/index.html +55 -0
  59. package/docs/interfaces/types_collection.AttributeData.html +99 -0
  60. package/docs/interfaces/types_collection.Filter.html +157 -0
  61. package/docs/interfaces/types_collection.GlobalOffer.html +176 -0
  62. package/docs/interfaces/types_collection.ICollectionAttributes.html +85 -0
  63. package/docs/interfaces/types_collection.ICollectionProfile.html +263 -0
  64. package/docs/interfaces/types_collection.IMintInfo.html +155 -0
  65. package/docs/interfaces/types_collection.ISocials.html +127 -0
  66. package/docs/interfaces/types_collection.MetadataAttribute.html +92 -0
  67. package/docs/interfaces/types_collection.SearchNFTs.html +127 -0
  68. package/docs/interfaces/types_collection.SearchNFTsArgs.html +225 -0
  69. package/docs/interfaces/types_collection.SearchNFTsResponse.html +132 -0
  70. package/docs/interfaces/types_collection.TradingActivity.html +232 -0
  71. package/docs/interfaces/types_collection.TraitValues.html +85 -0
  72. package/docs/interfaces/types_nft.GameData.html +92 -0
  73. package/docs/interfaces/types_nft.NFTAttribute.html +127 -0
  74. package/docs/interfaces/types_nft.NFTMetadata.html +104 -0
  75. package/docs/interfaces/types_nft.NftData.html +253 -0
  76. package/docs/interfaces/types_nft.NftValue.html +106 -0
  77. package/docs/interfaces/types_nft.OffersInfo.html +169 -0
  78. package/docs/interfaces/types_nft.OriginalMedia.html +92 -0
  79. package/docs/interfaces/types_nft.SaleInfoNft.html +211 -0
  80. package/docs/interfaces/types_trading.TradincActivityArgs.html +225 -0
  81. package/docs/interfaces/types_trading.TradingActivityQueryFilter.html +151 -0
  82. package/docs/interfaces/types_trading.TradingActivityResponse.html +106 -0
  83. package/docs/modules/collection.html +71 -0
  84. package/docs/modules/interactions.html +71 -0
  85. package/docs/modules/nft.html +71 -0
  86. package/docs/modules/types.html +189 -0
  87. package/docs/modules/types_collection.html +104 -0
  88. package/docs/modules/types_interactions.html +69 -0
  89. package/docs/modules/types_nft.html +85 -0
  90. package/docs/modules/types_trading.html +82 -0
  91. package/docs/modules/utils_SmartContractAbis.html +71 -0
  92. package/docs/modules/utils_SmartContractService.html +71 -0
  93. package/docs/modules/utils_api.html +76 -0
  94. package/docs/modules/utils_const.html +95 -0
  95. package/docs/modules/utils_getActivity.html +71 -0
  96. package/docs/modules/utils_helpers.html +73 -0
  97. package/docs/modules/utils_regex.html +73 -0
  98. package/docs/modules/utils_scCalls.html +71 -0
  99. package/docs/modules.html +76 -0
  100. package/docs/types/types_interactions.Offer.html +89 -0
  101. package/docs/variables/utils_const.API_URL.html +76 -0
  102. package/docs/variables/utils_const.API_URL_DEV.html +76 -0
  103. package/docs/variables/utils_const.DR_SC.html +76 -0
  104. package/docs/variables/utils_const.FM_SC.html +76 -0
  105. package/docs/variables/utils_const.KG_SC.html +76 -0
  106. package/docs/variables/utils_const.Manager_SC.html +76 -0
  107. package/docs/variables/utils_const.Manager_SC_DEV.html +76 -0
  108. package/docs/variables/utils_const.P2P_SC.html +76 -0
  109. package/docs/variables/utils_const.P2P_SC_DEV.html +76 -0
  110. package/docs/variables/utils_const.Staking_SC.html +76 -0
  111. package/docs/variables/utils_const.Staking_SC_DEV.html +76 -0
  112. package/docs/variables/utils_const.XOXNO_SC.html +76 -0
  113. package/docs/variables/utils_const.XOXNO_SC_DEV.html +76 -0
  114. package/jest.config.js +7 -0
  115. package/package.json +74 -0
  116. package/src/collection/__tests__/collection.test.ts +100 -0
  117. package/src/collection/index.ts +158 -0
  118. package/src/index.ts +20 -0
  119. package/src/interactions/__tests__/market.test.ts +92 -0
  120. package/src/interactions/index.ts +228 -0
  121. package/src/nft/__tests__/nft.test.ts +84 -0
  122. package/src/nft/index.ts +98 -0
  123. package/src/types/collection.d.ts +267 -0
  124. package/src/types/index.ts +3 -0
  125. package/src/types/interactions.d.ts +16 -0
  126. package/src/types/nft.d.ts +100 -0
  127. package/src/types/trading.d.ts +95 -0
  128. package/src/utils/SmartContractAbis.ts +82 -0
  129. package/src/utils/SmartContractService.ts +17 -0
  130. package/src/utils/api.ts +133 -0
  131. package/src/utils/const.ts +26 -0
  132. package/src/utils/getActivity.ts +55 -0
  133. package/src/utils/helpers.ts +14 -0
  134. package/src/utils/regex.ts +7 -0
  135. package/src/utils/scCalls.ts +48 -0
  136. package/tsconfig.json +13 -0
  137. package/webpack.config.js +28 -0
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@xoxno/sdk-js",
3
+ "version": "0.0.1",
4
+ "description": "The SDK to interact with the XOXNO Protocol!",
5
+ "main": "./src/index.ts",
6
+ "scripts": {
7
+ "test": "jest",
8
+ "build": "webpack",
9
+ "lint": "eslint 'src/**/*.ts'",
10
+ "format": "prettier --write 'src/**/*.ts'",
11
+ "commit": "git-cz",
12
+ "release": "semantic-release",
13
+ "docs": "typedoc --out docs src/**/*.ts"
14
+ },
15
+ "config": {
16
+ "commitizen": {
17
+ "path": "./node_modules/cz-conventional-changelog"
18
+ }
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/XOXNO/sdk-js.git"
23
+ },
24
+ "husky": {
25
+ "hooks": {
26
+ "commit-msg": "npx --no-install commitlint --edit \"$1\"",
27
+ "pre-commit": "npm run format && npm run lint && npm run docs",
28
+ "pre-push": "npm test"
29
+ }
30
+ },
31
+ "keywords": [
32
+ "XOXNO",
33
+ "MultiversX",
34
+ "NFTs",
35
+ "Blockchain",
36
+ "Crypto"
37
+ ],
38
+ "author": "Mihai Eremia",
39
+ "license": "ISC",
40
+ "bugs": {
41
+ "url": "https://github.com/XOXNO/sdk-js/issues"
42
+ },
43
+ "homepage": "https://github.com/XOXNO/sdk-js#readme",
44
+ "devDependencies": {
45
+ "@commitlint/cli": "^17.5.0",
46
+ "@commitlint/config-conventional": "^17.4.4",
47
+ "@semantic-release/changelog": "^6.0.3",
48
+ "@semantic-release/git": "^10.0.1",
49
+ "@types/jest": "^29.5.0",
50
+ "@types/node": "^18.15.10",
51
+ "@typescript-eslint/eslint-plugin": "^5.56.0",
52
+ "@typescript-eslint/parser": "^5.56.0",
53
+ "commitizen": "^4.3.0",
54
+ "cz-conventional-changelog": "^3.3.0",
55
+ "eslint": "^8.36.0",
56
+ "eslint-config-prettier": "^8.8.0",
57
+ "eslint-plugin-prettier": "^4.2.1",
58
+ "husky": "^8.0.3",
59
+ "jest": "^29.5.0",
60
+ "prettier": "^2.8.7",
61
+ "semantic-release": "^21.0.0",
62
+ "ts-jest": "^29.0.5",
63
+ "ts-loader": "^9.4.2",
64
+ "typedoc": "^0.23.28",
65
+ "typescript": "^5.0.2",
66
+ "webpack": "^5.76.3",
67
+ "webpack-cli": "^5.0.1"
68
+ },
69
+ "dependencies": {
70
+ "@multiversx/sdk-core": "^11.5.0",
71
+ "@multiversx/sdk-network-providers": "^1.3.0",
72
+ "axios": "^1.3.4"
73
+ }
74
+ }
@@ -0,0 +1,100 @@
1
+ import { CollectionModule } from './../index';
2
+ import { APIClient } from '../../utils/api';
3
+ import { FieldsToSelect } from '../../types';
4
+
5
+ describe('CollectionModule', () => {
6
+ let collectionModule: CollectionModule;
7
+ const inputCollection = 'BANANA-e955fd';
8
+ beforeAll(() => {
9
+ APIClient.init('https://api.xoxno.com', '');
10
+ collectionModule = new CollectionModule();
11
+ });
12
+
13
+ test('getCollectionProfile should return the correct result', async () => {
14
+ const collectionModule = new CollectionModule();
15
+ const result = await collectionModule.getCollectionProfile(inputCollection);
16
+ expect(result.collection).toEqual(inputCollection);
17
+ });
18
+
19
+ it('should get the floor price of a collection', async () => {
20
+ const floorPrice = await collectionModule.getCollectionFloorPrice(
21
+ inputCollection
22
+ );
23
+ expect(floorPrice).toBeLessThan(1);
24
+ });
25
+
26
+ it('should get the collection attributes', async () => {
27
+ const attributesInfo = await collectionModule.getCollectionAttributes(
28
+ inputCollection
29
+ );
30
+ expect(attributesInfo).toMatchObject({
31
+ Accessorie: {
32
+ Dollars: {
33
+ attributeOccurrence: 260,
34
+ },
35
+ },
36
+ });
37
+ });
38
+
39
+ it('should get the collection trading activity', async () => {
40
+ const tradingActivity = await collectionModule.getTradingActivity({
41
+ collections: [inputCollection],
42
+ top: 1,
43
+ });
44
+ expect(tradingActivity).toMatchObject({
45
+ getNextPagePayload: {
46
+ top: 1,
47
+ skip: 1,
48
+ collections: [inputCollection],
49
+ },
50
+ });
51
+
52
+ const tradingActivitySecondPage = await collectionModule.getTradingActivity(
53
+ tradingActivity.getNextPagePayload
54
+ );
55
+ expect(tradingActivitySecondPage).toMatchObject({
56
+ getNextPagePayload: {
57
+ top: 1,
58
+ skip: 2,
59
+ collections: [inputCollection],
60
+ },
61
+ });
62
+ });
63
+
64
+ it('should get fetch and filter NFTs from a collection', async () => {
65
+ const nfts = await collectionModule.searchNFTs({
66
+ collection: inputCollection,
67
+ onlyOnSale: true,
68
+ top: 1,
69
+ onlySelectFields: [
70
+ FieldsToSelect.Attributes,
71
+ FieldsToSelect.Name,
72
+ FieldsToSelect.SaleInfo,
73
+ FieldsToSelect.Rank,
74
+ FieldsToSelect.Description,
75
+ FieldsToSelect.Royalties,
76
+ FieldsToSelect.Collection,
77
+ ],
78
+ });
79
+ expect(nfts).toMatchObject({
80
+ getNextPagePayload: {
81
+ top: 1,
82
+ skip: 1,
83
+ collection: inputCollection,
84
+ onlyOnSale: true,
85
+ },
86
+ });
87
+
88
+ const nftsSecondPage = await collectionModule.searchNFTs(
89
+ nfts.getNextPagePayload
90
+ );
91
+ expect(nftsSecondPage).toMatchObject({
92
+ getNextPagePayload: {
93
+ top: 1,
94
+ skip: 2,
95
+ collection: inputCollection,
96
+ onlyOnSale: true,
97
+ },
98
+ });
99
+ });
100
+ });
@@ -0,0 +1,158 @@
1
+ import {
2
+ ICollectionAttributes,
3
+ ICollectionProfile,
4
+ SearchNFTs,
5
+ SearchNFTsArgs,
6
+ SearchNFTsResponse,
7
+ } from '../types/collection';
8
+ import { TradincActivityArgs, TradingActivityResponse } from '../types/trading';
9
+ import { APIClient } from '../utils/api';
10
+ import { getActivity } from '../utils/getActivity';
11
+ import { isValidCollectionTicker } from '../utils/regex';
12
+
13
+ /**
14
+ * CollectionModule provides a set of methods to interact with NFT collections.
15
+ * It includes methods for getting collection profile information, floor price,
16
+ * collection attributes, and searching NFTs within a collection.
17
+ *
18
+ * @example
19
+ * const xoxno = new XOXNO({ apiURL: 'https://api.xoxno.com', apiKey: 'your-api-key' });
20
+ * const collectionModule = xoxno.collection;
21
+ */
22
+ export class CollectionModule {
23
+ private api: APIClient;
24
+ constructor() {
25
+ this.api = APIClient.getClient();
26
+ }
27
+
28
+ /**
29
+ * Fetches the profile of a collection.
30
+ * @param collection - The ticker of the collection.
31
+ * @returns A Promise that resolves to the ICollectionProfile object.
32
+ * @throws An error if the provided collection ticker is invalid.
33
+ */
34
+ public getCollectionProfile = async (
35
+ collection: string
36
+ ): Promise<ICollectionProfile> => {
37
+ if (!isValidCollectionTicker(collection)) {
38
+ throw new Error('Invalid collection ticker: ' + collection);
39
+ }
40
+ const response = await this.api.fetchWithTimeout<ICollectionProfile>(
41
+ `/getCollectionProfile/${collection}`
42
+ );
43
+ return response;
44
+ };
45
+
46
+ /**
47
+ * Fetches the floor price of a collection.
48
+ * @param collection - The ticker of the collection.
49
+ * @param token - The token for the floor price calculation (default: 'EGLD').
50
+ * @returns A Promise that resolves to the collection's floor price as a number.
51
+ * @throws An error if the provided collection ticker is invalid.
52
+ */
53
+ public getCollectionFloorPrice = async (
54
+ collection: string,
55
+ token = 'EGLD'
56
+ ): Promise<number> => {
57
+ if (!isValidCollectionTicker(collection)) {
58
+ throw new Error('Invalid collection ticker: ' + collection);
59
+ }
60
+ const response = await this.api.fetchWithTimeout<number>(
61
+ `/getFloorPrice/${collection}/${token}`
62
+ );
63
+ return response;
64
+ };
65
+
66
+ /**
67
+ * Fetches the attributes of a collection.
68
+ * @param collection - The ticker of the collection.
69
+ * @returns A Promise that resolves to the ICollectionAttributes object.
70
+ * @throws An error if the provided collection ticker is invalid.
71
+ */
72
+ public getCollectionAttributes = async (
73
+ collection: string
74
+ ): Promise<ICollectionAttributes> => {
75
+ if (!isValidCollectionTicker(collection)) {
76
+ throw new Error('Invalid collection ticker: ' + collection);
77
+ }
78
+ const response = await this.api.fetchWithTimeout<ICollectionAttributes>(
79
+ `/getCollectionAttributes/${collection}`
80
+ );
81
+ return response;
82
+ };
83
+
84
+ /**
85
+ * Searches for NFTs in a collection based on the provided arguments.
86
+ * @param args - The SearchNFTsArgs object containing the search parameters.
87
+ * @returns A Promise that resolves to the SearchNFTsResponse object.
88
+ * @throws An error if the provided collection ticker is invalid or if the 'top' value is greater than 35.
89
+ */
90
+ public searchNFTs = async (
91
+ args: SearchNFTsArgs
92
+ ): Promise<SearchNFTsResponse> => {
93
+ if (!isValidCollectionTicker(args.collection)) {
94
+ throw new Error('Invalid collection ticker: ' + args.collection);
95
+ }
96
+
97
+ if (args.top && args.top > 35) {
98
+ throw new Error('Top cannot be greater than 35');
99
+ }
100
+
101
+ const payloadBody: SearchNFTs = {
102
+ filters: {
103
+ onSale: args.onlyOnSale || false,
104
+ marketplace: args.listedOnlyOn || undefined,
105
+ auctionTypes: args.onlyOnSale
106
+ ? args.onlyAuctions
107
+ ? ['NftBid', 'SftAll']
108
+ : ['Nft', 'SftOnePerPayment']
109
+ : undefined,
110
+ tokens: args.listedInToken || undefined,
111
+ attributes: args.attributes || undefined,
112
+ range: args.priceRange
113
+ ? {
114
+ ...args.priceRange,
115
+ type: args.onlyAuctions
116
+ ? 'saleInfoNft/current_bid_short'
117
+ : 'saleInfoNft/min_bid_short',
118
+ }
119
+ : undefined,
120
+ rankRange: args.rankRange || undefined,
121
+ levelRange: args.cantinaLevelRange || undefined,
122
+ },
123
+ name: args.searchName || '',
124
+ orderBy: args.orderBy || undefined,
125
+ collection: args.collection,
126
+ select: args.onlySelectFields || undefined,
127
+ top: args.top || 35,
128
+ skip: args.skip || 0,
129
+ };
130
+
131
+ const buffer = Buffer.from(JSON.stringify(payloadBody)).toString('base64');
132
+ const response = await this.api.fetchWithTimeout<SearchNFTsResponse>(
133
+ `/searchNFTs/${buffer}`
134
+ );
135
+ return {
136
+ ...response,
137
+ getNextPagePayload: {
138
+ ...args,
139
+ skip: (args.skip ?? 0) + (args.top ?? 35),
140
+ },
141
+ hasMoreResults:
142
+ response.resultsCount > (args.skip ?? 0) + (args.top ?? 35),
143
+ };
144
+ };
145
+
146
+ /**
147
+ * Retrieves trading history based on the provided arguments.
148
+ *
149
+ * @param {TradincActivityArgs} args - The arguments for filtering the trading activity.
150
+ * @returns {Promise<TradingActivityResponse>} A promise resolving to a TradingActivityResponse object containing the activity.
151
+ * @throws {Error} Throws an error if the 'top' argument is greater than 35.
152
+ */
153
+ public getTradingActivity = async (
154
+ args: TradincActivityArgs
155
+ ): Promise<TradingActivityResponse> => {
156
+ return await getActivity(args, this.api);
157
+ };
158
+ }
package/src/index.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { CollectionModule } from './collection';
2
+ import { APIClient } from './utils/api';
3
+ import { API_URL } from './utils/const';
4
+
5
+ /**
6
+ * Represents an XOXNO Marketplace SDK, providing a simplified interface for
7
+ * interacting with an XOXNO API.
8
+ */
9
+ export class XOXNO {
10
+ public collection: CollectionModule;
11
+ /**
12
+ * Creates a new XOXNO instance.
13
+ * @param apiUrl - The base URL of the XOXNO API.
14
+ * @param apiKey - The API key for accessing the XOXNO API.
15
+ */
16
+ constructor(apiUrl: string = API_URL, apiKey = '') {
17
+ APIClient.init(apiUrl, apiKey);
18
+ this.collection = new CollectionModule();
19
+ }
20
+ }
@@ -0,0 +1,92 @@
1
+ import { SCInteraction } from '../index';
2
+ import { APIClient } from '../../utils/api';
3
+
4
+ describe('SCInteraction', () => {
5
+ let sc: SCInteraction;
6
+ beforeAll(async () => {
7
+ APIClient.init();
8
+ sc = await SCInteraction.create();
9
+ });
10
+
11
+ it('should return the XOXNO marketplace cut fees from SC', async () => {
12
+ const fees = await sc.getMarketplaceFees();
13
+ expect(fees).toBeDefined();
14
+ expect(fees).toEqual(100);
15
+ });
16
+
17
+ it('should return the XOXNO marketplace accepted payment tokens', async () => {
18
+ const tokens = await sc.getAcceptedPaymentTokens();
19
+ expect(tokens).toBeDefined();
20
+ expect(tokens).toContain('EGLD');
21
+ });
22
+
23
+ it('should return the XOXNO marketplace global offers unique IDs', async () => {
24
+ const global_offer_ids = await sc.getGlobalOfferIDs();
25
+ expect(global_offer_ids).toBeDefined();
26
+ expect(global_offer_ids.length).toBeGreaterThan(1);
27
+ });
28
+
29
+ it('should return the XOXNO global offer body for an ID', async () => {
30
+ const global_offer_ids = await sc.getGlobalOfferIDs();
31
+ expect(global_offer_ids).toBeDefined();
32
+ expect(global_offer_ids.length).toBeGreaterThan(1);
33
+ const offer = await sc.getGlobalOfferData(global_offer_ids[0]);
34
+ expect(offer).toBeDefined();
35
+ const lastOffer = await sc.getGlobalOfferData(
36
+ global_offer_ids[global_offer_ids.length - 1]
37
+ );
38
+ expect(lastOffer).toBeDefined();
39
+ });
40
+
41
+ it('should return the XOXNO listings count', async () => {
42
+ const listings = await sc.getListingsCount();
43
+ expect(listings).toBeDefined();
44
+ expect(listings).toBeGreaterThan(1);
45
+ });
46
+
47
+ it('should return the XOXNO custom offers count', async () => {
48
+ const listings = await sc.getOffersCount();
49
+ expect(listings).toBeDefined();
50
+ expect(listings).toBeGreaterThan(1);
51
+ });
52
+
53
+ it('should return the XOXNO global offers count', async () => {
54
+ const listings = await sc.getGlobalOffersCount();
55
+ expect(listings).toBeDefined();
56
+ expect(listings).toBeGreaterThan(1);
57
+ });
58
+
59
+ it('should return the XOXNO user deposit balance', async () => {
60
+ const balance = await sc.getUserPoolBalance(
61
+ 'erd1fmd662htrgt07xxd8me09newa9s0euzvpz3wp0c4pz78f83grt9qm6pn57',
62
+ 'EGLD',
63
+ 0
64
+ );
65
+ expect(balance).toBeDefined();
66
+ expect(balance).toBeGreaterThan(0);
67
+ });
68
+
69
+ it('should return the XOXNO unique listed collections', async () => {
70
+ const listings = await sc.getCollectionsCount();
71
+ expect(listings).toBeDefined();
72
+ expect(listings).toBeGreaterThan(1);
73
+ });
74
+
75
+ it('should return the XOXNO unique auction IDs of a collection', async () => {
76
+ const IDs = await sc.getAuctionIDsForCollection('COW-cd463d');
77
+ expect(IDs).toBeDefined();
78
+ expect(IDs.length).toBeGreaterThan(1);
79
+ });
80
+
81
+ it('should return the XOXNO on sale NFT count of a collection', async () => {
82
+ const count = await sc.getCollectionNFTsOnSaleCount('COW-cd463d');
83
+ expect(count).toBeDefined();
84
+ expect(count).toBeGreaterThan(10);
85
+ });
86
+
87
+ it('should return if the collection is listed on XOXNO', async () => {
88
+ const isListed = await sc.isCollectionListed('COW-cd463d');
89
+ expect(isListed).toBeDefined();
90
+ expect(isListed).toEqual(true);
91
+ });
92
+ });
@@ -0,0 +1,228 @@
1
+ import {
2
+ BigUIntValue,
3
+ Interaction,
4
+ SmartContract,
5
+ } from '@multiversx/sdk-core/out';
6
+ import { Address } from '@multiversx/sdk-core/out/address';
7
+ import { GlobalOffer } from '../types/collection';
8
+ import { APIClient } from '../utils/api';
9
+ import { ContractQueryRunner } from '../utils/scCalls';
10
+ import { SmartContractAbis } from '../utils/SmartContractAbis';
11
+ import { getSmartContract } from '../utils/SmartContractService';
12
+
13
+ export class SCInteraction {
14
+ private xo: SmartContract;
15
+ private call: ContractQueryRunner;
16
+ constructor(marketAbiXOXNO: SmartContract) {
17
+ this.xo = marketAbiXOXNO;
18
+ this.call = new ContractQueryRunner();
19
+ }
20
+
21
+ static async create() {
22
+ const config = APIClient.getClient().config;
23
+ const marketAbiXOXNO = await SmartContractAbis.getMarket();
24
+ const xo_abi = getSmartContract(
25
+ marketAbiXOXNO,
26
+ new Address(config.XO_SC),
27
+ 'XOXNOProtocol'
28
+ );
29
+
30
+ return new SCInteraction(xo_abi);
31
+ }
32
+
33
+ private async getResult(interaction: Interaction) {
34
+ return await this.call.runQuery(this.xo, interaction);
35
+ }
36
+
37
+ /**
38
+ * Gets the percentage of each transaction that will be paid to the marketplace.
39
+ *
40
+ * @returns The percentage of each transaction that will be paid to the marketplace.
41
+ */
42
+ public getMarketplaceFees = async (): Promise<number> => {
43
+ const interaction = this.xo.methods.getMarketplaceCutPercentage();
44
+ const result = await this.getResult(interaction);
45
+ return parseInt(result.firstValue?.valueOf());
46
+ };
47
+
48
+ /**
49
+ * Retrieves the list of accepted payment tokens.
50
+ * @returns {string[]} A list of accepted payment tokens.
51
+ */
52
+ public getAcceptedPaymentTokens = async (): Promise<string[]> => {
53
+ const interaction = this.xo.methods.getAcceptedTokens();
54
+ const result = await this.getResult(interaction);
55
+ return result.firstValue?.valueOf();
56
+ };
57
+
58
+ /**
59
+ * This function returns a list of IDs of global offers.
60
+ * @returns {number[]} a list of IDs of global offers.
61
+ */
62
+
63
+ public getGlobalOfferIDs = async (): Promise<number[]> => {
64
+ const interaction = this.xo.methods.getGlobalOffers();
65
+ const result = await this.getResult(interaction);
66
+ return result.firstValue?.valueOf().map((id: string) => parseInt(id));
67
+ };
68
+
69
+ /**
70
+ * Gets the balance of a user in a token of a specific pool.
71
+ * @param address The address of the user.
72
+ * @param token The token address.
73
+ * @param nonce The nonce of the pool.
74
+ * @returns {number} The balance of the user in the token of the pool.
75
+ */
76
+ async getUserPoolBalance(
77
+ address: string,
78
+ token: string,
79
+ nonce: number
80
+ ): Promise<number> {
81
+ const result = await this.getResult(
82
+ this.xo.methods.userDeposit([address, token, nonce])
83
+ );
84
+
85
+ if (!result?.firstValue) {
86
+ return 0;
87
+ }
88
+ return new BigUIntValue(result.firstValue.valueOf().amount)
89
+ .valueOf()
90
+ .shiftedBy(-18)
91
+ .toNumber();
92
+ }
93
+
94
+ // function to determine if the offer is active
95
+ // based on the offer price and user balance
96
+ private isOfferActive(offer_price: number, user_balance: number): boolean {
97
+ return offer_price <= user_balance;
98
+ }
99
+
100
+ /**
101
+ * Returns the global offer data for the offer with the given id.
102
+ *
103
+ * @param global_offer_id The id of the global offer for which to return the data.
104
+ *
105
+ * @returns An object containing the global offer data for the offer with the given id. If the global offer id is invalid, the return value will be null.
106
+ */
107
+
108
+ public getGlobalOfferData = async (
109
+ global_offer_id: number
110
+ ): Promise<GlobalOffer> => {
111
+ const interaction = this.xo.methods.getGlobalOffer([global_offer_id]);
112
+ const result = await this.getResult(interaction);
113
+ const body = result.firstValue?.valueOf();
114
+ body.offer_id = parseInt(body.offer_id.valueOf());
115
+ body.marketplace = 'XO';
116
+ body.short_price = parseFloat(
117
+ new BigUIntValue(body.price).valueOf().shiftedBy(-18).toString()
118
+ );
119
+ body.new_version = Boolean(body.new_version);
120
+ if (!body.new_version) {
121
+ body.isActive = this.isOfferActive(
122
+ body.short_price,
123
+ await this.getUserPoolBalance(
124
+ body.owner,
125
+ body.payment_token,
126
+ body.payment_nonce
127
+ )
128
+ );
129
+ } else {
130
+ body.isActive = true;
131
+ }
132
+ body.quantity = parseInt(body.quantity.valueOf());
133
+ body.payment_nonce = parseInt(body.payment_nonce.valueOf());
134
+ body.price = body.price.valueOf();
135
+
136
+ body.timestamp = parseInt(body.timestamp.valueOf());
137
+ body.owner = body.owner.valueOf().toString();
138
+ if (body.attributes) {
139
+ body.attributes = JSON.parse(
140
+ Buffer.from(body.attributes.valueOf().toString(), 'base64').toString(
141
+ 'ascii'
142
+ )
143
+ );
144
+ }
145
+ return body as GlobalOffer;
146
+ };
147
+
148
+ /** Gets the number of listings.
149
+ * @returns {number} The number of listings.
150
+ * */
151
+ public async getListingsCount(): Promise<number> {
152
+ const result = await this.getResult(this.xo.methods.getListingsCount());
153
+ const count = parseInt(result.firstValue?.valueOf());
154
+ return count;
155
+ }
156
+
157
+ /** Gets the number of custom offers.
158
+ * @returns {number} The number of custom offers.
159
+ * */
160
+ public async getOffersCount(): Promise<number> {
161
+ const result = await this.getResult(this.xo.methods.getOffersCount());
162
+ const count = parseInt(result.firstValue?.valueOf());
163
+ return count;
164
+ }
165
+
166
+ /** Gets the number of global offers.
167
+ * @returns {number} The number of global offers.
168
+ * */
169
+ public async getGlobalOffersCount(): Promise<number> {
170
+ const result = await this.getResult(this.xo.methods.getGlobalOffersCount());
171
+ const count = parseInt(result.firstValue?.valueOf());
172
+ return count;
173
+ }
174
+
175
+ /** Gets the number of collections listed.
176
+ * @returns {number} The number of collections listed.
177
+ * */
178
+ public async getCollectionsCount(): Promise<number> {
179
+ const result = await this.getResult(this.xo.methods.getCollectionsCount());
180
+ const count = parseInt(result.firstValue?.valueOf());
181
+ return count;
182
+ }
183
+
184
+ /**
185
+ * Checks whether a collection is listed with at least 1 NFT.
186
+ *
187
+ * @param collection name of the collection
188
+ * @return true if the collection is listed, false otherwise
189
+ */
190
+ public async isCollectionListed(collection: string): Promise<boolean> {
191
+ const result = await this.getResult(
192
+ this.xo.methods.isCollectionListed([collection])
193
+ );
194
+ return Boolean(result.firstValue?.valueOf());
195
+ }
196
+
197
+ /** Gets the on sale NFT count of the collection.
198
+ *
199
+ * @param collection The collection identifier for which one wants to get the on sale NFT count.
200
+ *
201
+ * @returns {number} The on sale NFT count of the collection.
202
+ * */
203
+ public async getCollectionNFTsOnSaleCount(
204
+ collection: string
205
+ ): Promise<number> {
206
+ const result = await this.getResult(
207
+ this.xo.methods.getTokenItemsForSaleCount([collection])
208
+ );
209
+ return parseInt(result.firstValue?.valueOf());
210
+ }
211
+
212
+ /** Gets the active unique auction IDs of collection.
213
+ *
214
+ * @param collection The collection identifier for which one wants to get the active unique auction IDs.
215
+ *
216
+ * @returns {number[]} The active unique auction IDs of collection.
217
+ * */
218
+
219
+ public async getAuctionIDsForCollection(
220
+ collection: string
221
+ ): Promise<number[]> {
222
+ const result = await this.getResult(
223
+ this.xo.methods.getAuctionsForTicker([collection])
224
+ );
225
+ const ids = result.firstValue?.valueOf().map((id: string) => parseInt(id));
226
+ return ids;
227
+ }
228
+ }