@explorins/pers-sdk 1.2.3 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth-admin/api/auth-admin-api.d.ts +3 -2
- package/dist/auth-admin/api/auth-admin-api.d.ts.map +1 -1
- package/dist/auth-admin.cjs +7 -3
- package/dist/auth-admin.cjs.map +1 -1
- package/dist/auth-admin.js +7 -3
- package/dist/auth-admin.js.map +1 -1
- package/dist/business/api/business-api.d.ts +17 -32
- package/dist/business/api/business-api.d.ts.map +1 -1
- package/dist/business.cjs +26 -50
- package/dist/business.cjs.map +1 -1
- package/dist/business.js +26 -50
- package/dist/business.js.map +1 -1
- package/dist/campaign/api/campaign-api.d.ts +47 -30
- package/dist/campaign/api/campaign-api.d.ts.map +1 -1
- package/dist/campaign/index.d.ts +5 -5
- package/dist/campaign/services/campaign-service.d.ts +6 -6
- package/dist/campaign/services/campaign-service.d.ts.map +1 -1
- package/dist/campaign.cjs +62 -41
- package/dist/campaign.cjs.map +1 -1
- package/dist/campaign.js +62 -41
- package/dist/campaign.js.map +1 -1
- package/dist/index.cjs +719 -439
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +718 -440
- package/dist/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/redemption/api/redemption-api.d.ts +58 -14
- package/dist/redemption/api/redemption-api.d.ts.map +1 -1
- package/dist/redemption/index.d.ts +2 -2
- package/dist/redemption/models/index.d.ts +1 -1
- package/dist/redemption/models/index.d.ts.map +1 -1
- package/dist/redemption/services/redemption-service.d.ts +3 -3
- package/dist/redemption/services/redemption-service.d.ts.map +1 -1
- package/dist/redemption.cjs +89 -15
- package/dist/redemption.cjs.map +1 -1
- package/dist/redemption.js +89 -15
- package/dist/redemption.js.map +1 -1
- package/dist/shared/interfaces/pers-shared-lib.interfaces.d.ts +3 -3
- package/dist/shared/interfaces/pers-shared-lib.interfaces.d.ts.map +1 -1
- package/dist/transaction/api/transaction-api.d.ts +23 -19
- package/dist/transaction/api/transaction-api.d.ts.map +1 -1
- package/dist/transaction/index.d.ts +3 -7
- package/dist/transaction/index.d.ts.map +1 -1
- package/dist/transaction/models/index.d.ts +0 -1
- package/dist/transaction/models/index.d.ts.map +1 -1
- package/dist/transaction/services/transaction-service.d.ts +5 -7
- package/dist/transaction/services/transaction-service.d.ts.map +1 -1
- package/dist/transaction.cjs +85 -50
- package/dist/transaction.cjs.map +1 -1
- package/dist/transaction.js +85 -50
- package/dist/transaction.js.map +1 -1
- package/dist/web3/application/index.d.ts +6 -0
- package/dist/web3/application/index.d.ts.map +1 -0
- package/dist/web3/application/web3-application.service.d.ts +53 -0
- package/dist/web3/application/web3-application.service.d.ts.map +1 -0
- package/dist/web3/domain/models/index.d.ts +58 -0
- package/dist/web3/domain/models/index.d.ts.map +1 -0
- package/dist/web3/domain/services/contract-domain.service.d.ts +20 -0
- package/dist/web3/domain/services/contract-domain.service.d.ts.map +1 -0
- package/dist/web3/domain/services/index.d.ts +8 -0
- package/dist/web3/domain/services/index.d.ts.map +1 -0
- package/dist/web3/domain/services/metadata-domain.service.d.ts +12 -0
- package/dist/web3/domain/services/metadata-domain.service.d.ts.map +1 -0
- package/dist/web3/domain/services/token-domain.service.d.ts +48 -0
- package/dist/web3/domain/services/token-domain.service.d.ts.map +1 -0
- package/dist/web3/index.d.ts +10 -11
- package/dist/web3/index.d.ts.map +1 -1
- package/dist/web3/infrastructure/api/index.d.ts +6 -0
- package/dist/web3/infrastructure/api/index.d.ts.map +1 -0
- package/dist/web3/infrastructure/api/ipfs-api.d.ts +15 -0
- package/dist/web3/infrastructure/api/ipfs-api.d.ts.map +1 -0
- package/dist/web3/{api → infrastructure/api}/web3-api.d.ts +6 -2
- package/dist/web3/infrastructure/api/web3-api.d.ts.map +1 -0
- package/dist/web3/infrastructure/index.d.ts +2 -0
- package/dist/web3/infrastructure/index.d.ts.map +1 -0
- package/dist/web3.cjs +509 -336
- package/dist/web3.cjs.map +1 -1
- package/dist/web3.js +507 -336
- package/dist/web3.js.map +1 -1
- package/package.json +1 -1
- package/dist/web3/api/web3-api.d.ts.map +0 -1
- package/dist/web3/models/index.d.ts +0 -92
- package/dist/web3/models/index.d.ts.map +0 -1
- package/dist/web3/services/web3-service.d.ts +0 -21
- package/dist/web3/services/web3-service.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { TransactionRole, AccountOwnerType } from '@explorins/pers-shared';
|
|
1
2
|
import { jwtDecode } from 'jwt-decode';
|
|
2
3
|
import Web3 from 'web3';
|
|
3
4
|
import { FetchRequest, JsonRpcProvider } from 'ethers';
|
|
4
|
-
import { getSmartContractInstance,
|
|
5
|
+
import { getSmartContractInstance, getAccountTokenBalance, getTokenUri, getTokenOfOwnerByIndex } from '@explorins/web3-ts';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* PERS SDK Configuration interfaces
|
|
@@ -501,13 +502,15 @@ function createPersSDK(httpClient, config) {
|
|
|
501
502
|
/**
|
|
502
503
|
* Platform-Agnostic Business API Client
|
|
503
504
|
*
|
|
504
|
-
* Updated to match the
|
|
505
|
-
*
|
|
505
|
+
* Updated to match the actual RESTful endpoints:
|
|
506
|
+
* - /businesses for business operations
|
|
507
|
+
* - /business-types for business type operations (separate controller)
|
|
506
508
|
*/
|
|
507
509
|
class BusinessApi {
|
|
508
510
|
constructor(apiClient) {
|
|
509
511
|
this.apiClient = apiClient;
|
|
510
512
|
this.basePath = '/businesses';
|
|
513
|
+
this.businessTypesPath = '/business-types'; // ✅ FIX: Separate controller
|
|
511
514
|
}
|
|
512
515
|
// ==========================================
|
|
513
516
|
// 🌐 BUSINESS TYPES MANAGEMENT
|
|
@@ -515,38 +518,38 @@ class BusinessApi {
|
|
|
515
518
|
/**
|
|
516
519
|
* Get all business types (project key required)
|
|
517
520
|
*
|
|
518
|
-
* Endpoint: GET /
|
|
521
|
+
* Endpoint: GET /business-types
|
|
519
522
|
* Auth: @ApiSecurity('projectKey')
|
|
520
523
|
*/
|
|
521
524
|
async getAllBusinessTypes() {
|
|
522
|
-
return this.apiClient.get(
|
|
525
|
+
return this.apiClient.get(this.businessTypesPath); // ✅ FIX: Correct path
|
|
523
526
|
}
|
|
524
527
|
/**
|
|
525
528
|
* ADMIN: Create business type
|
|
526
529
|
*
|
|
527
|
-
* Endpoint: POST /
|
|
530
|
+
* Endpoint: POST /business-types
|
|
528
531
|
* Auth: @TenantAdmin()
|
|
529
532
|
*/
|
|
530
533
|
async createBusinessType(dto) {
|
|
531
|
-
return this.apiClient.post(
|
|
534
|
+
return this.apiClient.post(this.businessTypesPath, dto); // ✅ FIX: Correct path
|
|
532
535
|
}
|
|
533
536
|
/**
|
|
534
537
|
* ADMIN: Update business type
|
|
535
538
|
*
|
|
536
|
-
* Endpoint: PUT /
|
|
539
|
+
* Endpoint: PUT /business-types
|
|
537
540
|
* Auth: @TenantAdmin()
|
|
538
541
|
*/
|
|
539
542
|
async updateBusinessType(dto) {
|
|
540
|
-
return this.apiClient.put(
|
|
543
|
+
return this.apiClient.put(this.businessTypesPath, dto); // ✅ FIX: Correct path
|
|
541
544
|
}
|
|
542
545
|
/**
|
|
543
546
|
* ADMIN: Delete business type
|
|
544
547
|
*
|
|
545
|
-
* Endpoint: DELETE /
|
|
548
|
+
* Endpoint: DELETE /business-types/{id}
|
|
546
549
|
* Auth: @TenantAdmin()
|
|
547
550
|
*/
|
|
548
551
|
async deleteBusinessType(id) {
|
|
549
|
-
return this.apiClient.delete(`${this.
|
|
552
|
+
return this.apiClient.delete(`${this.businessTypesPath}/${id}`); // ✅ FIX: Correct path
|
|
550
553
|
}
|
|
551
554
|
// ==========================================
|
|
552
555
|
// 🏢 BUSINESS MANAGEMENT
|
|
@@ -561,20 +564,13 @@ class BusinessApi {
|
|
|
561
564
|
return this.apiClient.get(`${this.basePath}/me`);
|
|
562
565
|
}
|
|
563
566
|
/**
|
|
564
|
-
* Get all
|
|
565
|
-
*
|
|
566
|
-
* Endpoint: GET /businesses
|
|
567
|
-
* Auth: @ApiSecurity('projectKey')
|
|
568
|
-
* Note: Regular users automatically get active businesses only
|
|
569
|
-
*/
|
|
570
|
-
async getActiveBusinesses() {
|
|
571
|
-
return this.apiClient.get(`${this.basePath}`);
|
|
572
|
-
}
|
|
573
|
-
/**
|
|
574
|
-
* Get all businesses with filtering (admin users can access inactive)
|
|
567
|
+
* Get all businesses with role-based filtering
|
|
575
568
|
*
|
|
576
569
|
* Endpoint: GET /businesses?active={boolean}&sanitize={mode}
|
|
577
570
|
* Auth: @ApiSecurity('projectKey') (enhanced with role-based filtering)
|
|
571
|
+
* Note:
|
|
572
|
+
* - Project API Key users: Active businesses only (automatically filtered)
|
|
573
|
+
* - Admin JWT users: Full access with all query parameters
|
|
578
574
|
*/
|
|
579
575
|
async getAllBusinesses(options) {
|
|
580
576
|
const params = new URLSearchParams();
|
|
@@ -589,23 +585,16 @@ class BusinessApi {
|
|
|
589
585
|
return this.apiClient.get(url);
|
|
590
586
|
}
|
|
591
587
|
/**
|
|
592
|
-
*
|
|
588
|
+
* Get all active businesses (convenience method)
|
|
593
589
|
*
|
|
594
|
-
* Endpoint: GET /businesses
|
|
595
|
-
* Auth: @
|
|
590
|
+
* Endpoint: GET /businesses
|
|
591
|
+
* Auth: @ApiSecurity('projectKey')
|
|
596
592
|
*/
|
|
597
|
-
async
|
|
598
|
-
|
|
599
|
-
if (options?.active !== undefined) {
|
|
600
|
-
params.append('active', String(options.active));
|
|
601
|
-
}
|
|
602
|
-
if (options?.sanitize) {
|
|
603
|
-
params.append('sanitize', options.sanitize);
|
|
604
|
-
}
|
|
605
|
-
const queryString = params.toString();
|
|
606
|
-
const url = queryString ? `${this.basePath}?${queryString}` : this.basePath;
|
|
607
|
-
return this.apiClient.get(url);
|
|
593
|
+
async getActiveBusinesses() {
|
|
594
|
+
return this.apiClient.get(this.basePath);
|
|
608
595
|
}
|
|
596
|
+
// ✅ REMOVED: getAllBusinessesAdmin() - No separate /admin endpoint exists
|
|
597
|
+
// The unified endpoint handles role-based access automatically
|
|
609
598
|
/**
|
|
610
599
|
* Get business by ID
|
|
611
600
|
*
|
|
@@ -635,18 +624,15 @@ class BusinessApi {
|
|
|
635
624
|
* Returns: BusinessApiKeyDTO | BusinessTokenBalancesDTO
|
|
636
625
|
*/
|
|
637
626
|
async createBusiness(dto) {
|
|
638
|
-
return this.apiClient.post(
|
|
627
|
+
return this.apiClient.post(this.basePath, dto);
|
|
639
628
|
}
|
|
640
629
|
/**
|
|
641
630
|
* ADMIN: Create business by display name (convenience method)
|
|
642
|
-
*
|
|
643
|
-
* This is a convenience wrapper that creates the proper DTO structure
|
|
644
631
|
*/
|
|
645
632
|
async createBusinessByDisplayName(displayName) {
|
|
646
633
|
const dto = {
|
|
647
634
|
displayName,
|
|
648
635
|
// Add other required fields based on BusinessCreateRequestDTO structure
|
|
649
|
-
// You may need to check the DTO definition for required fields
|
|
650
636
|
};
|
|
651
637
|
return this.createBusiness(dto);
|
|
652
638
|
}
|
|
@@ -671,21 +657,12 @@ class BusinessApi {
|
|
|
671
657
|
/**
|
|
672
658
|
* ADMIN: Toggle business active status
|
|
673
659
|
*
|
|
674
|
-
* Endpoint: PUT /businesses/{id}/
|
|
660
|
+
* Endpoint: PUT /businesses/{id}/status
|
|
675
661
|
* Auth: @TenantAdmin()
|
|
676
662
|
*/
|
|
677
663
|
async toggleBusinessActive(id, isActive) {
|
|
678
664
|
const dto = { isActive };
|
|
679
|
-
return this.apiClient.put(`${this.basePath}/${id}/status`, dto);
|
|
680
|
-
}
|
|
681
|
-
/**
|
|
682
|
-
* ADMIN: Generate new business API key
|
|
683
|
-
*
|
|
684
|
-
* Endpoint: PUT /businesses/{id}/api-key
|
|
685
|
-
* Auth: @TenantAdmin()
|
|
686
|
-
*/
|
|
687
|
-
async generateNewBusinessApiKey(id) {
|
|
688
|
-
return this.apiClient.put(`${this.basePath}/${id}/api-key`, {});
|
|
665
|
+
return this.apiClient.put(`${this.basePath}/${id}/status`, dto); // ✅ FIX: Correct endpoint
|
|
689
666
|
}
|
|
690
667
|
}
|
|
691
668
|
|
|
@@ -821,6 +798,15 @@ class TransactionApi {
|
|
|
821
798
|
async getTransactionById(transactionId) {
|
|
822
799
|
return this.apiClient.get(`${this.basePath}/${transactionId}`);
|
|
823
800
|
}
|
|
801
|
+
/**
|
|
802
|
+
* Unique method to create a transaction
|
|
803
|
+
* @param request
|
|
804
|
+
* @returns
|
|
805
|
+
*/
|
|
806
|
+
async createTransaction(request) {
|
|
807
|
+
return this.apiClient.post(`${this.basePath}`, request);
|
|
808
|
+
// return this.apiClient.post<TransactionDTO>(`${this.basePath}/system`, request);
|
|
809
|
+
}
|
|
824
810
|
// ==========================================
|
|
825
811
|
// AUTHENTICATED USER OPERATIONS
|
|
826
812
|
// ==========================================
|
|
@@ -829,9 +815,9 @@ class TransactionApi {
|
|
|
829
815
|
*
|
|
830
816
|
* UPDATED: /transaction/auth/transaction → /transactions/user
|
|
831
817
|
*/
|
|
832
|
-
async createAuthTransaction(request) {
|
|
833
|
-
|
|
834
|
-
}
|
|
818
|
+
/* async createAuthTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
|
|
819
|
+
return this.apiClient.post<TransactionRequestResponseDTO>(`${this.basePath}`, request);
|
|
820
|
+
} */
|
|
835
821
|
/**
|
|
836
822
|
* AUTH: Get user's sent transactions
|
|
837
823
|
*
|
|
@@ -876,14 +862,6 @@ class TransactionApi {
|
|
|
876
862
|
return this.apiClient.get(`${this.basePath}/me/sent?${params.toString()}`);
|
|
877
863
|
}
|
|
878
864
|
}
|
|
879
|
-
/**
|
|
880
|
-
* AUTH: Prepare client signed transaction
|
|
881
|
-
*
|
|
882
|
-
* UPDATED: /transaction/auth/prepare-signing → /transactions/prepare
|
|
883
|
-
*/
|
|
884
|
-
async prepareClientSignedTransaction(request) {
|
|
885
|
-
return this.apiClient.post(`${this.basePath}/prepare`, request);
|
|
886
|
-
}
|
|
887
865
|
/**
|
|
888
866
|
* AUTH: Prepare existing transaction for client-side signing
|
|
889
867
|
*
|
|
@@ -897,8 +875,8 @@ class TransactionApi {
|
|
|
897
875
|
*
|
|
898
876
|
* NEW ENDPOINT: POST /transactions/{id}/submit
|
|
899
877
|
*/
|
|
900
|
-
async submitSignedTransaction(
|
|
901
|
-
return this.apiClient.post(`${this.basePath}
|
|
878
|
+
async submitSignedTransaction(signedTxData) {
|
|
879
|
+
return this.apiClient.post(`${this.basePath}/submit`, signedTxData);
|
|
902
880
|
}
|
|
903
881
|
/**
|
|
904
882
|
* AUTH: Burn user tokens
|
|
@@ -906,14 +884,15 @@ class TransactionApi {
|
|
|
906
884
|
* UPDATED: Uses new user transaction endpoint with burn-specific parameters
|
|
907
885
|
* Note: This might need backend confirmation on burn functionality implementation
|
|
908
886
|
*/
|
|
909
|
-
async burnUserTokens(request) {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
887
|
+
/* async burnUserTokens(request: UserBurnTokenRequestDTO): Promise<TransactionRequestResponseDTO> {
|
|
888
|
+
// Map burn request to TransactionRequestDTO format for new endpoint
|
|
889
|
+
const transactionRequest: TransactionRequestDTO = {
|
|
890
|
+
...request,
|
|
891
|
+
// Add any specific burn transaction parameters here
|
|
892
|
+
} as any;
|
|
893
|
+
|
|
894
|
+
return this.apiClient.post<TransactionRequestResponseDTO>(`${this.basePath}`, transactionRequest);
|
|
895
|
+
} */
|
|
917
896
|
// ==========================================
|
|
918
897
|
// BUSINESS OPERATIONS
|
|
919
898
|
// ==========================================
|
|
@@ -922,9 +901,9 @@ class TransactionApi {
|
|
|
922
901
|
*
|
|
923
902
|
* UPDATED: /transaction/business/transaction → /transactions/business
|
|
924
903
|
*/
|
|
925
|
-
async createBusinessTransaction(request) {
|
|
926
|
-
|
|
927
|
-
}
|
|
904
|
+
/* async createBusinessTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
|
|
905
|
+
return this.apiClient.post<TransactionRequestResponseDTO>(`${this.basePath}`, request);
|
|
906
|
+
} */
|
|
928
907
|
// ==========================================
|
|
929
908
|
// ADMIN OPERATIONS
|
|
930
909
|
// ==========================================
|
|
@@ -933,8 +912,17 @@ class TransactionApi {
|
|
|
933
912
|
*
|
|
934
913
|
* UPDATED: /transaction/admin/transaction → /transactions/admin
|
|
935
914
|
*/
|
|
936
|
-
async createAdminTransaction(request) {
|
|
937
|
-
|
|
915
|
+
/* async createAdminTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
|
|
916
|
+
// return this.apiClient.post<TransactionRequestResponseDTO>(`${this.basePath}`, request);
|
|
917
|
+
return this.apiClient.post<TransactionDTO>(`${this.basePath}/system`, request);
|
|
918
|
+
} */
|
|
919
|
+
/**
|
|
920
|
+
* AUTH: Prepare client signed transaction
|
|
921
|
+
*
|
|
922
|
+
* UPDATED: /transaction/auth/prepare-signing → /transactions/prepare
|
|
923
|
+
*/
|
|
924
|
+
async prepareClientSignedTransaction(request) {
|
|
925
|
+
return this.apiClient.post(`${this.basePath}`, request);
|
|
938
926
|
}
|
|
939
927
|
/**
|
|
940
928
|
* ADMIN: Get all tenant transactions
|
|
@@ -1013,16 +1001,31 @@ class TransactionApi {
|
|
|
1013
1001
|
*
|
|
1014
1002
|
* NEW ENDPOINT: POST /transactions/query-sender
|
|
1015
1003
|
*/
|
|
1004
|
+
/**
|
|
1005
|
+
* Query transactions by sender using unified endpoint
|
|
1006
|
+
*/
|
|
1016
1007
|
async queryTransactionsBySender(accountSelector) {
|
|
1017
|
-
|
|
1008
|
+
// Build query parameters safely
|
|
1009
|
+
const queryParams = {};
|
|
1010
|
+
if (accountSelector.accountId) {
|
|
1011
|
+
queryParams['participantId'] = accountSelector.accountId;
|
|
1012
|
+
}
|
|
1013
|
+
queryParams['role'] = TransactionRole.SENDER.toString();
|
|
1014
|
+
const params = new URLSearchParams(queryParams);
|
|
1015
|
+
return this.apiClient.get(`${this.basePath}?${params.toString()}`).then(response => response); // Extract items from paginated response
|
|
1018
1016
|
}
|
|
1019
1017
|
/**
|
|
1020
|
-
*
|
|
1021
|
-
*
|
|
1022
|
-
* NEW ENDPOINT: POST /transactions/query-recipient
|
|
1018
|
+
* Query transactions by recipient using unified endpoint
|
|
1023
1019
|
*/
|
|
1024
1020
|
async queryTransactionsByRecipient(accountSelector) {
|
|
1025
|
-
|
|
1021
|
+
// Build query parameters safely
|
|
1022
|
+
const queryParams = {};
|
|
1023
|
+
if (accountSelector.accountId) {
|
|
1024
|
+
queryParams['participantId'] = accountSelector.accountId;
|
|
1025
|
+
}
|
|
1026
|
+
queryParams['role'] = TransactionRole.RECIPIENT.toString();
|
|
1027
|
+
const params = new URLSearchParams(queryParams);
|
|
1028
|
+
return this.apiClient.get(`${this.basePath}?${params.toString()}`).then(response => response); // Extract items from paginated response
|
|
1026
1029
|
}
|
|
1027
1030
|
/**
|
|
1028
1031
|
* ADMIN: Get transaction analytics
|
|
@@ -1073,8 +1076,14 @@ class TransactionService {
|
|
|
1073
1076
|
/**
|
|
1074
1077
|
* AUTH: Create authenticated transaction
|
|
1075
1078
|
*/
|
|
1076
|
-
async createAuthTransaction(request) {
|
|
1077
|
-
|
|
1079
|
+
/* async createAuthTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
|
|
1080
|
+
return this.transactionApi.createAuthTransaction(request);
|
|
1081
|
+
} */
|
|
1082
|
+
async createTransaction(request) {
|
|
1083
|
+
return this.transactionApi.createTransaction(request);
|
|
1084
|
+
}
|
|
1085
|
+
async submitSignedTransaction(signedTxData) {
|
|
1086
|
+
return this.transactionApi.submitSignedTransaction(signedTxData);
|
|
1078
1087
|
}
|
|
1079
1088
|
/**
|
|
1080
1089
|
* AUTH: Get user transaction history by type
|
|
@@ -1085,33 +1094,33 @@ class TransactionService {
|
|
|
1085
1094
|
/**
|
|
1086
1095
|
* AUTH: Prepare client signed transaction
|
|
1087
1096
|
*/
|
|
1088
|
-
async prepareClientSignedTransaction(request) {
|
|
1089
|
-
|
|
1090
|
-
}
|
|
1097
|
+
/* async prepareClientSignedTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
|
|
1098
|
+
return this.transactionApi.prepareClientSignedTransaction(request);
|
|
1099
|
+
} */
|
|
1091
1100
|
/**
|
|
1092
1101
|
* AUTH: Burn user tokens
|
|
1093
1102
|
*/
|
|
1094
|
-
async burnUserTokens(request) {
|
|
1095
|
-
|
|
1096
|
-
}
|
|
1103
|
+
/* async burnUserTokens(request: UserBurnTokenRequestDTO): Promise<TransactionRequestResponseDTO> {
|
|
1104
|
+
return this.transactionApi.burnUserTokens(request);
|
|
1105
|
+
} */
|
|
1097
1106
|
// ==========================================
|
|
1098
1107
|
// BUSINESS OPERATIONS
|
|
1099
1108
|
// ==========================================
|
|
1100
1109
|
/**
|
|
1101
1110
|
* BUSINESS: Create business transaction
|
|
1102
1111
|
*/
|
|
1103
|
-
async createBusinessTransaction(request) {
|
|
1104
|
-
|
|
1105
|
-
}
|
|
1112
|
+
/* async createBusinessTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
|
|
1113
|
+
return this.transactionApi.createBusinessTransaction(request);
|
|
1114
|
+
} */
|
|
1106
1115
|
// ==========================================
|
|
1107
1116
|
// ADMIN OPERATIONS
|
|
1108
1117
|
// ==========================================
|
|
1109
1118
|
/**
|
|
1110
1119
|
* ADMIN: Create admin transaction
|
|
1111
1120
|
*/
|
|
1112
|
-
async createAdminTransaction(request) {
|
|
1113
|
-
|
|
1114
|
-
}
|
|
1121
|
+
/* async createAdminTransaction(request: TransactionRequestDTO): Promise<TransactionRequestResponseDTO> {
|
|
1122
|
+
return this.transactionApi.createAdminTransaction(request);
|
|
1123
|
+
} */
|
|
1115
1124
|
/**
|
|
1116
1125
|
* ADMIN: Get all tenant transactions
|
|
1117
1126
|
*/
|
|
@@ -1165,15 +1174,16 @@ function createTransactionSDK(apiClient) {
|
|
|
1165
1174
|
// Direct access to service methods (primary interface)
|
|
1166
1175
|
// Public methods
|
|
1167
1176
|
getTransactionById: (transactionId) => transactionService.getTransactionById(transactionId),
|
|
1177
|
+
createTransaction: (request) => transactionService.createTransaction(request),
|
|
1168
1178
|
// Auth methods
|
|
1169
|
-
createAuthTransaction: (request) => transactionService.createAuthTransaction(request),
|
|
1179
|
+
// createAuthTransaction: (request: TransactionRequestDTO) => transactionService.createAuthTransaction(request),
|
|
1170
1180
|
getUserTransactionHistory: (type) => transactionService.getUserTransactionHistory(type),
|
|
1171
|
-
prepareClientSignedTransaction: (request) => transactionService.prepareClientSignedTransaction(request),
|
|
1172
|
-
burnUserTokens: (request) => transactionService.burnUserTokens(request),
|
|
1181
|
+
//prepareClientSignedTransaction: (request: TransactionRequestDTO) => transactionService.prepareClientSignedTransaction(request),
|
|
1182
|
+
// burnUserTokens: (request: UserBurnTokenRequestDTO) => transactionService.burnUserTokens(request),
|
|
1173
1183
|
// Business methods
|
|
1174
|
-
createBusinessTransaction: (request) => transactionService.createBusinessTransaction(request),
|
|
1184
|
+
// createBusinessTransaction: (request: TransactionRequestDTO) => transactionService.createBusinessTransaction(request),
|
|
1175
1185
|
// Admin methods
|
|
1176
|
-
createAdminTransaction: (request) => transactionService.createAdminTransaction(request),
|
|
1186
|
+
// createAdminTransaction: (request: TransactionRequestDTO) => transactionService.createAdminTransaction(request),
|
|
1177
1187
|
getTenantTransactions: () => transactionService.getTenantTransactions(),
|
|
1178
1188
|
getPaginatedTransactions: (params) => transactionService.getPaginatedTransactions(params),
|
|
1179
1189
|
exportTransactionsCSV: () => transactionService.exportTransactionsCSV(),
|
|
@@ -1275,9 +1285,11 @@ class AuthAdminApi {
|
|
|
1275
1285
|
* Note: JWT handling and auth bypass headers may need special implementation
|
|
1276
1286
|
*/
|
|
1277
1287
|
async loginTenantAdmin(jwt) {
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1288
|
+
const body = {
|
|
1289
|
+
authToken: jwt,
|
|
1290
|
+
authType: AccountOwnerType.TENANT
|
|
1291
|
+
};
|
|
1292
|
+
return this.apiClient.post(`${this.basePath}/token`, body);
|
|
1281
1293
|
}
|
|
1282
1294
|
/**
|
|
1283
1295
|
* ADMIN: Refresh access token
|
|
@@ -1586,81 +1598,102 @@ class CampaignApi {
|
|
|
1586
1598
|
* NEW: POST /campaign-claims/user
|
|
1587
1599
|
*/
|
|
1588
1600
|
async claimCampaign(request) {
|
|
1589
|
-
return this.apiClient.post('/campaign-claims
|
|
1601
|
+
return this.apiClient.post('/campaign-claims', request);
|
|
1590
1602
|
}
|
|
1591
1603
|
/**
|
|
1592
1604
|
* USER: Get claims for logged user
|
|
1593
1605
|
* NEW: GET /campaign-claims/users/me
|
|
1594
1606
|
*/
|
|
1595
1607
|
async getClaimsForLoggedUser() {
|
|
1596
|
-
return this.apiClient.get('/campaign-claims/
|
|
1608
|
+
return this.apiClient.get('/campaign-claims/me');
|
|
1597
1609
|
}
|
|
1598
1610
|
/**
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
async
|
|
1603
|
-
|
|
1611
|
+
* ADMIN: Get all campaign claims
|
|
1612
|
+
* Updated to use unified endpoint
|
|
1613
|
+
*/
|
|
1614
|
+
async getCampaignClaims() {
|
|
1615
|
+
// Admin context - no parameters needed for all claims
|
|
1616
|
+
return this.apiClient.get('/campaign-claims');
|
|
1604
1617
|
}
|
|
1605
1618
|
/**
|
|
1606
|
-
*
|
|
1607
|
-
*
|
|
1619
|
+
* ADMIN: Get campaign claims by campaign ID
|
|
1620
|
+
* Updated to use query parameters
|
|
1608
1621
|
*/
|
|
1609
|
-
async
|
|
1610
|
-
return this.apiClient.
|
|
1622
|
+
async getCampaignClaimsByCampaignId(campaignId) {
|
|
1623
|
+
return this.apiClient.get(`/campaign-claims?campaignId=${campaignId}`);
|
|
1611
1624
|
}
|
|
1612
1625
|
/**
|
|
1613
|
-
* ADMIN:
|
|
1614
|
-
*
|
|
1626
|
+
* ADMIN: Get campaign claims by user ID
|
|
1627
|
+
* Updated to use query parameters
|
|
1615
1628
|
*/
|
|
1616
|
-
async
|
|
1617
|
-
return this.apiClient.
|
|
1629
|
+
async getCampaignClaimsByUserId(userId) {
|
|
1630
|
+
return this.apiClient.get(`/campaign-claims?userId=${userId}`);
|
|
1618
1631
|
}
|
|
1619
1632
|
/**
|
|
1620
|
-
* ADMIN: Get
|
|
1621
|
-
*
|
|
1633
|
+
* ADMIN: Get campaign claims by business ID
|
|
1634
|
+
* Updated to use query parameters
|
|
1622
1635
|
*/
|
|
1623
|
-
async
|
|
1624
|
-
return this.apiClient.get(
|
|
1636
|
+
async getCampaignClaimsByBusinessId(businessId) {
|
|
1637
|
+
return this.apiClient.get(`/campaign-claims?businessId=${businessId}`);
|
|
1625
1638
|
}
|
|
1626
1639
|
/**
|
|
1627
|
-
* ADMIN: Get campaign claims by
|
|
1628
|
-
*
|
|
1640
|
+
* ADMIN: Get campaign claims by user ID for specific campaign
|
|
1641
|
+
* Combined filtering using query parameters
|
|
1629
1642
|
*/
|
|
1630
|
-
async
|
|
1631
|
-
return this.apiClient.get(`/campaign-claims
|
|
1643
|
+
async getCampaignClaimsByUserAndCampaign(userId, campaignId) {
|
|
1644
|
+
return this.apiClient.get(`/campaign-claims?userId=${userId}&campaignId=${campaignId}`);
|
|
1632
1645
|
}
|
|
1633
1646
|
/**
|
|
1634
|
-
* ADMIN: Get campaign claims by
|
|
1635
|
-
*
|
|
1647
|
+
* ADMIN: Get campaign claims by business ID for specific campaign
|
|
1648
|
+
* Combined filtering using query parameters
|
|
1636
1649
|
*/
|
|
1637
|
-
async
|
|
1638
|
-
return this.apiClient.get(`/campaign-claims
|
|
1650
|
+
async getCampaignClaimsByBusinessAndCampaign(businessId, campaignId) {
|
|
1651
|
+
return this.apiClient.get(`/campaign-claims?businessId=${businessId}&campaignId=${campaignId}`);
|
|
1639
1652
|
}
|
|
1640
1653
|
/**
|
|
1641
|
-
*
|
|
1642
|
-
*
|
|
1654
|
+
* USER: Get user's own claims (all campaigns)
|
|
1655
|
+
* Use convenience endpoint
|
|
1643
1656
|
*/
|
|
1644
|
-
async
|
|
1645
|
-
return this.apiClient.get(
|
|
1657
|
+
async getUserClaims() {
|
|
1658
|
+
return this.apiClient.get('/campaign-claims/me');
|
|
1646
1659
|
}
|
|
1647
1660
|
/**
|
|
1648
1661
|
* USER: Get user's claims for specific campaign
|
|
1649
|
-
*
|
|
1662
|
+
* Use convenience endpoint with query parameter
|
|
1650
1663
|
*/
|
|
1651
1664
|
async getUserClaimsForCampaign(campaignId) {
|
|
1652
|
-
return this.apiClient.get(`/campaign-claims/
|
|
1665
|
+
return this.apiClient.get(`/campaign-claims/me?campaignId=${campaignId}`);
|
|
1666
|
+
}
|
|
1667
|
+
/**
|
|
1668
|
+
* BUSINESS: Get business claims (all campaigns)
|
|
1669
|
+
* Uses unified endpoint with business context
|
|
1670
|
+
*/
|
|
1671
|
+
async getBusinessClaims() {
|
|
1672
|
+
return this.apiClient.get('/campaign-claims');
|
|
1673
|
+
}
|
|
1674
|
+
/**
|
|
1675
|
+
* BUSINESS: Get business claims for specific campaign
|
|
1676
|
+
* Uses unified endpoint with business context and campaign filter
|
|
1677
|
+
*/
|
|
1678
|
+
async getBusinessClaimsForCampaign(campaignId) {
|
|
1679
|
+
return this.apiClient.get(`/campaign-claims?campaignId=${campaignId}`);
|
|
1680
|
+
}
|
|
1681
|
+
/**
|
|
1682
|
+
* Helper: Build query string from parameters
|
|
1683
|
+
*/
|
|
1684
|
+
buildQueryString(params) {
|
|
1685
|
+
const validParams = Object.entries(params)
|
|
1686
|
+
.filter(([_, value]) => value !== undefined)
|
|
1687
|
+
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
|
|
1688
|
+
.join('&');
|
|
1689
|
+
return validParams ? `?${validParams}` : '';
|
|
1653
1690
|
}
|
|
1654
|
-
// ==========================================
|
|
1655
|
-
// BACKWARD COMPATIBILITY (DEPRECATED)
|
|
1656
|
-
// ==========================================
|
|
1657
1691
|
/**
|
|
1658
|
-
*
|
|
1659
|
-
* LEGACY: Get campaigns with active filter
|
|
1692
|
+
* Flexible admin claims query with multiple filters
|
|
1660
1693
|
*/
|
|
1661
|
-
async
|
|
1662
|
-
|
|
1663
|
-
return this.
|
|
1694
|
+
async getAdminClaims(filters) {
|
|
1695
|
+
const queryString = this.buildQueryString(filters || {});
|
|
1696
|
+
return this.apiClient.get(`/campaign-claims${queryString}`);
|
|
1664
1697
|
}
|
|
1665
1698
|
}
|
|
1666
1699
|
|
|
@@ -2171,20 +2204,21 @@ function createPaymentSDK(apiClient) {
|
|
|
2171
2204
|
/**
|
|
2172
2205
|
* Platform-Agnostic Redemption API Client (UPDATED - RESTful Design)
|
|
2173
2206
|
*
|
|
2174
|
-
* Updated to work with the new RESTful /redemptions endpoints.
|
|
2207
|
+
* Updated to work with the new RESTful /redemptions and /redemption-redeems endpoints.
|
|
2175
2208
|
* Handles redemption operations using the PERS backend with intelligent access detection.
|
|
2176
2209
|
* Uses @explorins/pers-shared DTOs for consistency with backend.
|
|
2177
2210
|
*
|
|
2178
|
-
* Migration Update: Updated all endpoints
|
|
2211
|
+
* Migration Update: Updated all endpoints for unified controller pattern
|
|
2179
2212
|
* - Removed role revelation from URLs (no more /admin, /auth paths)
|
|
2180
2213
|
* - Added intelligent access detection for unified endpoints
|
|
2181
|
-
* -
|
|
2182
|
-
* - Enhanced redemption process with
|
|
2214
|
+
* - Added new /redemption-redeems endpoints for redeem processing
|
|
2215
|
+
* - Enhanced redemption process with role-based access control
|
|
2183
2216
|
*/
|
|
2184
2217
|
class RedemptionApi {
|
|
2185
2218
|
constructor(apiClient) {
|
|
2186
2219
|
this.apiClient = apiClient;
|
|
2187
2220
|
this.basePath = '/redemptions';
|
|
2221
|
+
this.redeemsPath = '/redemption-redeems';
|
|
2188
2222
|
}
|
|
2189
2223
|
// ==========================================
|
|
2190
2224
|
// PUBLIC OPERATIONS (Project Key)
|
|
@@ -2219,7 +2253,7 @@ class RedemptionApi {
|
|
|
2219
2253
|
* Updated: /redemption/type → /redemptions/types
|
|
2220
2254
|
*/
|
|
2221
2255
|
async getRedemptionTypes() {
|
|
2222
|
-
return this.apiClient.get(
|
|
2256
|
+
return this.apiClient.get(`/redemption-types`);
|
|
2223
2257
|
}
|
|
2224
2258
|
/**
|
|
2225
2259
|
* PUBLIC: Get redemption by ID
|
|
@@ -2232,33 +2266,106 @@ class RedemptionApi {
|
|
|
2232
2266
|
/**
|
|
2233
2267
|
* PUBLIC: Get available supply for redemption
|
|
2234
2268
|
*
|
|
2235
|
-
* Updated: /redemption/:id/available-supply → /redemptions/:id/
|
|
2269
|
+
* Updated: /redemption/:id/available-supply → /redemptions/:id/supply
|
|
2236
2270
|
*/
|
|
2237
2271
|
async getRedemptionAvailableSupply(id) {
|
|
2238
|
-
return this.apiClient.get(`${this.basePath}/${id}/
|
|
2272
|
+
return this.apiClient.get(`${this.basePath}/${id}/supply`);
|
|
2239
2273
|
}
|
|
2240
2274
|
// ==========================================
|
|
2241
|
-
//
|
|
2275
|
+
// REDEMPTION EXECUTION (NEW UNIFIED ENDPOINT)
|
|
2242
2276
|
// ==========================================
|
|
2243
2277
|
/**
|
|
2244
|
-
*
|
|
2278
|
+
* Execute redemption (unified endpoint)
|
|
2245
2279
|
*
|
|
2246
|
-
*
|
|
2247
|
-
*
|
|
2280
|
+
* NEW: POST /redemption-redeems - Role-based processing
|
|
2281
|
+
* - USER: Direct user redemption processing
|
|
2282
|
+
* - ADMIN: Can process redemptions for any account type
|
|
2283
|
+
* - BUSINESS: Process redemptions for customers
|
|
2248
2284
|
*/
|
|
2249
2285
|
async redeemRedemption(redemptionId) {
|
|
2250
2286
|
const body = {
|
|
2251
2287
|
redemptionId: redemptionId,
|
|
2252
2288
|
};
|
|
2253
|
-
return this.apiClient.post(
|
|
2289
|
+
return this.apiClient.post(this.redeemsPath, body);
|
|
2290
|
+
}
|
|
2291
|
+
// ==========================================
|
|
2292
|
+
// REDEMPTION REDEEMS QUERIES (NEW ENDPOINTS)
|
|
2293
|
+
// ==========================================
|
|
2294
|
+
/**
|
|
2295
|
+
* Get redemption redeems with filtering (unified endpoint)
|
|
2296
|
+
*
|
|
2297
|
+
* NEW: GET /redemption-redeems with query parameters
|
|
2298
|
+
* Role-based access: Users see only their own, admins can filter by userId/businessId
|
|
2299
|
+
*/
|
|
2300
|
+
async getRedemptionRedeems(filters) {
|
|
2301
|
+
let url = this.redeemsPath;
|
|
2302
|
+
const params = new URLSearchParams();
|
|
2303
|
+
if (filters?.redemptionId)
|
|
2304
|
+
params.append('redemptionId', filters.redemptionId);
|
|
2305
|
+
if (filters?.userId)
|
|
2306
|
+
params.append('userId', filters.userId);
|
|
2307
|
+
if (filters?.businessId)
|
|
2308
|
+
params.append('businessId', filters.businessId);
|
|
2309
|
+
const queryString = params.toString();
|
|
2310
|
+
if (queryString) {
|
|
2311
|
+
url += `?${queryString}`;
|
|
2312
|
+
}
|
|
2313
|
+
return this.apiClient.get(url);
|
|
2314
|
+
}
|
|
2315
|
+
/**
|
|
2316
|
+
* Get specific redemption redeem by ID
|
|
2317
|
+
*
|
|
2318
|
+
* NEW: GET /redemption-redeems/:id
|
|
2319
|
+
*/
|
|
2320
|
+
async getRedemptionRedeemById(id) {
|
|
2321
|
+
return this.apiClient.get(`${this.redeemsPath}/${id}`);
|
|
2322
|
+
}
|
|
2323
|
+
/**
|
|
2324
|
+
* USER: Get my redemption redeems (convenience endpoint)
|
|
2325
|
+
*
|
|
2326
|
+
* NEW: GET /redemption-redeems/me with optional filtering
|
|
2327
|
+
*/
|
|
2328
|
+
async getMyRedemptionRedeems(redemptionId) {
|
|
2329
|
+
let url = `${this.redeemsPath}/me`;
|
|
2330
|
+
if (redemptionId) {
|
|
2331
|
+
url += `?redemptionId=${redemptionId}`;
|
|
2332
|
+
}
|
|
2333
|
+
return this.apiClient.get(url);
|
|
2334
|
+
}
|
|
2335
|
+
/**
|
|
2336
|
+
* ADMIN: Get redemption redeems by user ID
|
|
2337
|
+
*
|
|
2338
|
+
* NEW: GET /redemption-redeems?userId=X
|
|
2339
|
+
*/
|
|
2340
|
+
async getRedemptionRedeemsByUserId(userId, redemptionId) {
|
|
2341
|
+
return this.getRedemptionRedeems({ userId, redemptionId });
|
|
2342
|
+
}
|
|
2343
|
+
/**
|
|
2344
|
+
* ADMIN: Get redemption redeems by business ID
|
|
2345
|
+
*
|
|
2346
|
+
* NEW: GET /redemption-redeems?businessId=X
|
|
2347
|
+
*/
|
|
2348
|
+
async getRedemptionRedeemsByBusinessId(businessId, redemptionId) {
|
|
2349
|
+
return this.getRedemptionRedeems({ businessId, redemptionId });
|
|
2254
2350
|
}
|
|
2351
|
+
/**
|
|
2352
|
+
* ADMIN: Get redemption redeems by redemption ID
|
|
2353
|
+
*
|
|
2354
|
+
* NEW: GET /redemption-redeems?redemptionId=X
|
|
2355
|
+
*/
|
|
2356
|
+
async getRedemptionRedeemsByRedemptionId(redemptionId) {
|
|
2357
|
+
return this.getRedemptionRedeems({ redemptionId });
|
|
2358
|
+
}
|
|
2359
|
+
// ==========================================
|
|
2360
|
+
// USER OPERATIONS (JWT + Project Key)
|
|
2361
|
+
// ==========================================
|
|
2255
2362
|
/**
|
|
2256
2363
|
* USER: Get user redemption history
|
|
2257
2364
|
*
|
|
2258
|
-
* Updated:
|
|
2365
|
+
* Updated: Uses new convenience endpoint /redemption-redeems/me
|
|
2259
2366
|
*/
|
|
2260
2367
|
async getUserRedemptionHistory() {
|
|
2261
|
-
return this.
|
|
2368
|
+
return this.getMyRedemptionRedeems();
|
|
2262
2369
|
}
|
|
2263
2370
|
/**
|
|
2264
2371
|
* USER: Get user redemptions (backward compatibility)
|
|
@@ -2327,7 +2434,7 @@ class RedemptionApi {
|
|
|
2327
2434
|
* Updated: /redemption/admin/type → /redemptions/types
|
|
2328
2435
|
*/
|
|
2329
2436
|
async createRedemptionType(redemptionType) {
|
|
2330
|
-
return this.apiClient.post(`${this.basePath}/types`, redemptionType);
|
|
2437
|
+
return this.apiClient.post(`${this.basePath}/redemption-types`, redemptionType);
|
|
2331
2438
|
}
|
|
2332
2439
|
// ==========================================
|
|
2333
2440
|
// TOKEN UNIT MANAGEMENT (Admin)
|
|
@@ -4062,311 +4169,445 @@ function createWeb3ChainSDK(apiClient, providerService) {
|
|
|
4062
4169
|
};
|
|
4063
4170
|
}
|
|
4064
4171
|
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4172
|
+
/**
|
|
4173
|
+
* TokenDomainService - Domain service for token operations
|
|
4174
|
+
* Implements business logic for token balance, metadata, and collection operations
|
|
4175
|
+
*/
|
|
4176
|
+
class TokenDomainService {
|
|
4177
|
+
constructor(web3Api, metadataService, contractService) {
|
|
4178
|
+
this.web3Api = web3Api;
|
|
4179
|
+
this.metadataService = metadataService;
|
|
4180
|
+
this.contractService = contractService;
|
|
4068
4181
|
}
|
|
4069
4182
|
async getTokenBalance(request) {
|
|
4070
|
-
const
|
|
4071
|
-
const tokenContract = getSmartContractInstance(request.contractAddress, request.abi, web3);
|
|
4072
|
-
const balance = await getAddressTokenBalanceByContract(tokenContract, request.accountAddress, request.tokenId);
|
|
4073
|
-
return Number(balance);
|
|
4074
|
-
}
|
|
4075
|
-
async getTokenUri(request) {
|
|
4076
|
-
const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
|
|
4077
|
-
// ✅ DIRECT: Use web3-ts functions directly
|
|
4078
|
-
const tokenContract = getSmartContractInstance(request.contractAddress, request.abi, web3);
|
|
4079
|
-
const tokenId = Number(request.tokenId);
|
|
4080
|
-
const tokenUri = await getTokenUri(tokenContract, tokenId);
|
|
4081
|
-
return String(tokenUri);
|
|
4082
|
-
}
|
|
4083
|
-
async getTokenOfOwnerByIndex(request) {
|
|
4084
|
-
const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
|
|
4085
|
-
// ✅ DIRECT: Use web3-ts functions directly
|
|
4086
|
-
const tokenContract = getSmartContractInstance(request.contractAddress, request.abi, web3);
|
|
4087
|
-
const tokenId = await getTokenOfOwnerByIndex(tokenContract, request.accountAddress, request.tokenIndex);
|
|
4088
|
-
return String(tokenId);
|
|
4089
|
-
}
|
|
4090
|
-
}
|
|
4091
|
-
|
|
4092
|
-
class SimpleCache {
|
|
4093
|
-
constructor() {
|
|
4094
|
-
this.storage = {};
|
|
4095
|
-
this.defaultTTL = 10 * 1000; // 10 seconds
|
|
4096
|
-
}
|
|
4097
|
-
set(key, data, ttl) {
|
|
4098
|
-
this.storage[key] = {
|
|
4099
|
-
data,
|
|
4100
|
-
timestamp: Date.now(),
|
|
4101
|
-
ttl: ttl ?? this.defaultTTL
|
|
4102
|
-
};
|
|
4103
|
-
}
|
|
4104
|
-
get(key) {
|
|
4105
|
-
const entry = this.storage[key];
|
|
4106
|
-
if (!entry) {
|
|
4107
|
-
return null;
|
|
4108
|
-
}
|
|
4109
|
-
const now = Date.now();
|
|
4110
|
-
const isExpired = (now - entry.timestamp) > entry.ttl;
|
|
4111
|
-
if (isExpired) {
|
|
4112
|
-
delete this.storage[key];
|
|
4113
|
-
return null;
|
|
4114
|
-
}
|
|
4115
|
-
return entry.data;
|
|
4116
|
-
}
|
|
4117
|
-
clear() {
|
|
4118
|
-
this.storage = {};
|
|
4119
|
-
}
|
|
4120
|
-
cleanup() {
|
|
4121
|
-
const now = Date.now();
|
|
4122
|
-
Object.keys(this.storage).forEach(key => {
|
|
4123
|
-
const entry = this.storage[key];
|
|
4124
|
-
if ((now - entry.timestamp) > entry.ttl) {
|
|
4125
|
-
delete this.storage[key];
|
|
4126
|
-
}
|
|
4127
|
-
});
|
|
4128
|
-
}
|
|
4129
|
-
}
|
|
4130
|
-
|
|
4131
|
-
class Web3Service {
|
|
4132
|
-
constructor(web3Api, web3ChainService) {
|
|
4133
|
-
this.web3Api = web3Api;
|
|
4134
|
-
this.web3ChainService = web3ChainService;
|
|
4135
|
-
//temporary fix, remove when the backend supports custom gateways
|
|
4136
|
-
this.defaultIpfsGatewayDomain = 'pers.mypinata.cloud';
|
|
4137
|
-
// ✅ CACHE: Simple 10-second cache instance
|
|
4138
|
-
this.cache = new SimpleCache();
|
|
4139
|
-
this.cleanupInterval = null;
|
|
4140
|
-
this.cleanupInterval = setInterval(() => {
|
|
4141
|
-
this.cache.cleanup();
|
|
4142
|
-
}, 30 * 1000);
|
|
4143
|
-
}
|
|
4144
|
-
destroy() {
|
|
4145
|
-
if (this.cleanupInterval) {
|
|
4146
|
-
clearInterval(this.cleanupInterval);
|
|
4147
|
-
this.cleanupInterval = null;
|
|
4148
|
-
}
|
|
4149
|
-
this.cache.clear();
|
|
4150
|
-
}
|
|
4151
|
-
async getERC20Balance(request) {
|
|
4152
|
-
const cacheKey = `erc20_balance_${request.accountAddress}_${request.token.contractAddress}_${request.token.chainId}`;
|
|
4153
|
-
// ✅ CACHE CHECK: Try to get from cache first
|
|
4154
|
-
const cached = this.cache.get(cacheKey);
|
|
4155
|
-
if (cached) {
|
|
4156
|
-
console.debug(`💾 [Web3Service] Using cached ERC20 balance for ${request.token.symbol}`);
|
|
4157
|
-
return cached;
|
|
4158
|
-
}
|
|
4159
|
-
console.debug(`🔄 [Web3Service] Fetching fresh ERC20 balance for ${request.token.symbol}`);
|
|
4160
|
-
const rawBalance = await this.web3Api.getTokenBalance({
|
|
4183
|
+
const balance = await this.web3Api.getTokenBalance({
|
|
4161
4184
|
accountAddress: request.accountAddress,
|
|
4162
|
-
contractAddress: request.
|
|
4163
|
-
abi: request.
|
|
4164
|
-
tokenId:
|
|
4165
|
-
chainId: request.
|
|
4185
|
+
contractAddress: request.contractAddress,
|
|
4186
|
+
abi: request.abi,
|
|
4187
|
+
tokenId: request.tokenId,
|
|
4188
|
+
chainId: request.chainId
|
|
4166
4189
|
});
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
decimals,
|
|
4173
|
-
symbol,
|
|
4174
|
-
hasBalance: rawBalance > 0
|
|
4190
|
+
return {
|
|
4191
|
+
tokenId: request.tokenId,
|
|
4192
|
+
balance,
|
|
4193
|
+
hasBalance: balance > 0,
|
|
4194
|
+
metadata: null
|
|
4175
4195
|
};
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
try {
|
|
4197
|
-
const rawBalance = await this.web3Api.getTokenBalance({
|
|
4198
|
-
accountAddress: request.accountAddress,
|
|
4199
|
-
contractAddress: token.contractAddress,
|
|
4200
|
-
abi: token.abi,
|
|
4201
|
-
tokenId,
|
|
4202
|
-
chainId: token.chainId
|
|
4203
|
-
});
|
|
4204
|
-
const decimals = token.decimals ?? 0; // ERC1155 usually no decimals
|
|
4205
|
-
return {
|
|
4206
|
-
tokenId,
|
|
4207
|
-
balance: rawBalance,
|
|
4208
|
-
formattedBalance: this.formatBalance(rawBalance, decimals),
|
|
4209
|
-
hasBalance: rawBalance > 0,
|
|
4210
|
-
// ✅ FIXED: Convert null to undefined for findMetadata
|
|
4211
|
-
metadata: this.findMetadata(token.metadata ?? undefined, tokenId)
|
|
4212
|
-
};
|
|
4213
|
-
}
|
|
4214
|
-
catch (error) {
|
|
4215
|
-
console.warn(`Failed to get balance for token ${token.contractAddress}:${tokenId}`, error);
|
|
4216
|
-
return null; // Skip failed tokens
|
|
4217
|
-
}
|
|
4218
|
-
}));
|
|
4219
|
-
// Filter successful results with balance > 0
|
|
4220
|
-
const successfulResults = [];
|
|
4221
|
-
for (const result of balanceResults) {
|
|
4222
|
-
if (result.status === 'fulfilled' && result.value !== null && result.value.hasBalance) {
|
|
4223
|
-
successfulResults.push(result.value);
|
|
4196
|
+
}
|
|
4197
|
+
async getTokenWithMetadata(params) {
|
|
4198
|
+
try {
|
|
4199
|
+
const balance = await this.web3Api.getTokenBalance({
|
|
4200
|
+
accountAddress: params.accountAddress,
|
|
4201
|
+
contractAddress: params.contractAddress,
|
|
4202
|
+
abi: params.abi,
|
|
4203
|
+
tokenId: params.tokenId,
|
|
4204
|
+
chainId: params.chainId
|
|
4205
|
+
});
|
|
4206
|
+
let metadata = null;
|
|
4207
|
+
if (balance > 0) {
|
|
4208
|
+
const tokenUri = await this.web3Api.getTokenUri({
|
|
4209
|
+
contractAddress: params.contractAddress,
|
|
4210
|
+
abi: params.abi,
|
|
4211
|
+
tokenId: params.tokenId,
|
|
4212
|
+
chainId: params.chainId
|
|
4213
|
+
});
|
|
4214
|
+
if (tokenUri) {
|
|
4215
|
+
metadata = await this.metadataService.fetchAndProcessMetadata(tokenUri, params.chainId);
|
|
4224
4216
|
}
|
|
4225
4217
|
}
|
|
4226
4218
|
return {
|
|
4227
|
-
|
|
4228
|
-
|
|
4219
|
+
tokenId: params.tokenId,
|
|
4220
|
+
balance,
|
|
4221
|
+
hasBalance: balance > 0,
|
|
4222
|
+
metadata
|
|
4229
4223
|
};
|
|
4230
|
-
}));
|
|
4231
|
-
const response = {
|
|
4232
|
-
accountAddress: request.accountAddress,
|
|
4233
|
-
tokens: tokenResults.filter(t => t.results.length > 0)
|
|
4234
|
-
};
|
|
4235
|
-
// ✅ CACHE SET: Store complete collection result
|
|
4236
|
-
this.cache.set(cacheKey, response);
|
|
4237
|
-
return response;
|
|
4238
|
-
}
|
|
4239
|
-
async getERC721Collection(request) {
|
|
4240
|
-
// ✅ CACHE KEY: Create unique cache key for NFT collection
|
|
4241
|
-
const contractAddresses = request.nftContracts.map(t => t.contractAddress).sort().join(',');
|
|
4242
|
-
const maxNFTs = request.maxNFTsPerContract || 50;
|
|
4243
|
-
const cacheKey = `erc721_collection_${request.accountAddress}_${contractAddresses}_${maxNFTs}`;
|
|
4244
|
-
// ✅ CACHE CHECK: Try to get from cache first
|
|
4245
|
-
const cached = this.cache.get(cacheKey);
|
|
4246
|
-
if (cached) {
|
|
4247
|
-
console.debug(`💾 [Web3Service] Using cached ERC721 collection for ${request.accountAddress}`);
|
|
4248
|
-
return cached;
|
|
4249
4224
|
}
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4225
|
+
catch (error) {
|
|
4226
|
+
console.error('Error getting token with metadata:', error);
|
|
4227
|
+
return {
|
|
4228
|
+
tokenId: params.tokenId,
|
|
4229
|
+
balance: 0,
|
|
4230
|
+
hasBalance: false,
|
|
4231
|
+
metadata: null
|
|
4232
|
+
};
|
|
4233
|
+
}
|
|
4234
|
+
}
|
|
4235
|
+
async getTokenCollection(params) {
|
|
4236
|
+
try {
|
|
4237
|
+
const contractAnalysis = this.contractService.analyzeContract(params.abi);
|
|
4238
|
+
const tokens = [];
|
|
4239
|
+
if (!contractAnalysis.hasEnumeration && !contractAnalysis.isERC1155) {
|
|
4240
|
+
console.warn('Contract does not support enumeration, cannot retrieve full collection');
|
|
4241
|
+
return {
|
|
4242
|
+
accountAddress: params.accountAddress,
|
|
4243
|
+
contractAddress: params.contractAddress,
|
|
4244
|
+
totalBalance: 0,
|
|
4245
|
+
tokensRetrieved: 0,
|
|
4246
|
+
tokens: [],
|
|
4247
|
+
note: 'Contract does not support enumeration'
|
|
4248
|
+
};
|
|
4249
|
+
}
|
|
4250
|
+
else if (contractAnalysis.isERC1155) {
|
|
4251
|
+
const tokenIdsToProcess = params.tokenIds || [];
|
|
4252
|
+
if (tokenIdsToProcess.length > 0) {
|
|
4253
|
+
for (const tokenId of tokenIdsToProcess) {
|
|
4254
|
+
const tokenBalance = await this.getTokenWithMetadata({
|
|
4255
|
+
accountAddress: params.accountAddress,
|
|
4256
|
+
contractAddress: params.contractAddress,
|
|
4257
|
+
abi: params.abi,
|
|
4258
|
+
tokenId,
|
|
4259
|
+
chainId: params.chainId
|
|
4260
|
+
});
|
|
4261
|
+
tokens.push(tokenBalance);
|
|
4262
|
+
}
|
|
4263
|
+
}
|
|
4264
|
+
console.log('ERC-1155 User balances:', tokens);
|
|
4265
|
+
// ERC-1155: Cannot enumerate without knowing token IDs
|
|
4266
|
+
// Would need to use events or provide specific token IDs
|
|
4267
|
+
console.warn('ERC-1155 collection retrieval requires specific token IDs or event analysis');
|
|
4268
|
+
return {
|
|
4269
|
+
accountAddress: params.accountAddress,
|
|
4270
|
+
contractAddress: params.contractAddress,
|
|
4271
|
+
totalBalance: 0,
|
|
4272
|
+
tokensRetrieved: 0,
|
|
4273
|
+
tokens: tokens,
|
|
4274
|
+
note: 'ERC-1155 collection retrieval requires specific token IDs. Use getTokenWithMetadata() for individual tokens.'
|
|
4275
|
+
};
|
|
4276
|
+
}
|
|
4277
|
+
// Handle different token standards
|
|
4278
|
+
if (contractAnalysis.isERC721) {
|
|
4279
|
+
// ERC-721: Get user's total balance and enumerate through tokens
|
|
4280
|
+
const userBalance = await this.web3Api.getTokenBalance({
|
|
4281
|
+
accountAddress: params.accountAddress,
|
|
4282
|
+
contractAddress: params.contractAddress,
|
|
4283
|
+
abi: params.abi,
|
|
4284
|
+
tokenId: null, // null for ERC-721 total balance
|
|
4285
|
+
chainId: params.chainId
|
|
4260
4286
|
});
|
|
4261
|
-
|
|
4287
|
+
console.log(`ERC-721 User balance for ${params.accountAddress}:`, userBalance);
|
|
4288
|
+
if (userBalance === 0) {
|
|
4262
4289
|
return {
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4290
|
+
accountAddress: params.accountAddress,
|
|
4291
|
+
contractAddress: params.contractAddress,
|
|
4292
|
+
totalBalance: 0,
|
|
4293
|
+
tokensRetrieved: 0,
|
|
4294
|
+
tokens: []
|
|
4267
4295
|
};
|
|
4268
4296
|
}
|
|
4269
|
-
|
|
4270
|
-
const
|
|
4297
|
+
// Enumerate through user's tokens
|
|
4298
|
+
const maxTokens = params.maxTokens || userBalance;
|
|
4299
|
+
const tokensToRetrieve = Math.min(maxTokens, userBalance);
|
|
4300
|
+
for (let i = 0; i < tokensToRetrieve; i++) {
|
|
4271
4301
|
try {
|
|
4272
4302
|
const tokenId = await this.web3Api.getTokenOfOwnerByIndex({
|
|
4273
|
-
contractAddress:
|
|
4274
|
-
abi:
|
|
4275
|
-
accountAddress:
|
|
4276
|
-
tokenIndex:
|
|
4277
|
-
chainId:
|
|
4303
|
+
contractAddress: params.contractAddress,
|
|
4304
|
+
abi: params.abi,
|
|
4305
|
+
accountAddress: params.accountAddress,
|
|
4306
|
+
tokenIndex: i,
|
|
4307
|
+
chainId: params.chainId
|
|
4278
4308
|
});
|
|
4279
|
-
const
|
|
4280
|
-
|
|
4281
|
-
|
|
4309
|
+
const tokenWithMetadata = await this.getTokenWithMetadata({
|
|
4310
|
+
accountAddress: params.accountAddress,
|
|
4311
|
+
contractAddress: params.contractAddress,
|
|
4312
|
+
abi: params.abi,
|
|
4282
4313
|
tokenId,
|
|
4283
|
-
chainId:
|
|
4314
|
+
chainId: params.chainId
|
|
4284
4315
|
});
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
name: metadata?.name || `Token #${tokenId}`,
|
|
4289
|
-
description: metadata?.description || '',
|
|
4290
|
-
imageUrl: await this.resolveIPFSUrl(metadata?.image || '', token.chainId),
|
|
4291
|
-
rawBalance: 1,
|
|
4292
|
-
formattedBalance: '1',
|
|
4293
|
-
hasBalance: true,
|
|
4294
|
-
metadata,
|
|
4295
|
-
tokenIndex: index
|
|
4296
|
-
};
|
|
4297
|
-
return nftItem;
|
|
4316
|
+
if (tokenWithMetadata.hasBalance) {
|
|
4317
|
+
tokens.push(tokenWithMetadata);
|
|
4318
|
+
}
|
|
4298
4319
|
}
|
|
4299
4320
|
catch (error) {
|
|
4300
|
-
console.warn(`
|
|
4301
|
-
|
|
4321
|
+
console.warn(`Error retrieving ERC-721 token at index ${i}:`, error);
|
|
4322
|
+
continue;
|
|
4302
4323
|
}
|
|
4303
|
-
}
|
|
4304
|
-
// ✅ FIXED: Usar tipo específico NFTItem
|
|
4305
|
-
const successfulNFTs = nftResults
|
|
4306
|
-
.filter((result) => result.status === 'fulfilled' && result.value !== null)
|
|
4307
|
-
.map(result => result.value);
|
|
4308
|
-
return {
|
|
4309
|
-
token,
|
|
4310
|
-
totalNFTs: totalBalance,
|
|
4311
|
-
nfts: successfulNFTs,
|
|
4312
|
-
hasMore: totalBalance > maxNFTs
|
|
4313
|
-
};
|
|
4324
|
+
}
|
|
4314
4325
|
}
|
|
4315
|
-
|
|
4316
|
-
|
|
4326
|
+
else {
|
|
4327
|
+
// Unknown standard
|
|
4317
4328
|
return {
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4329
|
+
accountAddress: params.accountAddress,
|
|
4330
|
+
contractAddress: params.contractAddress,
|
|
4331
|
+
totalBalance: 0,
|
|
4332
|
+
tokensRetrieved: 0,
|
|
4333
|
+
tokens: [],
|
|
4334
|
+
note: 'Unsupported token standard for collection retrieval'
|
|
4322
4335
|
};
|
|
4323
4336
|
}
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4337
|
+
// Calculate total balance based on retrieved tokens
|
|
4338
|
+
let totalBalance = 0;
|
|
4339
|
+
if (contractAnalysis.isERC721) {
|
|
4340
|
+
// For ERC-721, total balance is the number of unique tokens owned
|
|
4341
|
+
totalBalance = tokens.length;
|
|
4342
|
+
}
|
|
4343
|
+
else {
|
|
4344
|
+
// For other standards, sum up individual token balances
|
|
4345
|
+
totalBalance = tokens.reduce((sum, token) => sum + token.balance, 0);
|
|
4346
|
+
}
|
|
4347
|
+
return {
|
|
4348
|
+
accountAddress: params.accountAddress,
|
|
4349
|
+
contractAddress: params.contractAddress,
|
|
4350
|
+
totalBalance,
|
|
4351
|
+
tokensRetrieved: tokens.length,
|
|
4352
|
+
tokens
|
|
4353
|
+
};
|
|
4354
|
+
}
|
|
4355
|
+
catch (error) {
|
|
4356
|
+
console.error('Error getting token collection:', error);
|
|
4357
|
+
return {
|
|
4358
|
+
accountAddress: params.accountAddress,
|
|
4359
|
+
contractAddress: params.contractAddress,
|
|
4360
|
+
totalBalance: 0,
|
|
4361
|
+
tokensRetrieved: 0,
|
|
4362
|
+
tokens: [],
|
|
4363
|
+
note: 'Error retrieving collection'
|
|
4364
|
+
};
|
|
4365
|
+
}
|
|
4366
|
+
}
|
|
4367
|
+
async getTokenMetadata(params) {
|
|
4368
|
+
try {
|
|
4369
|
+
const tokenUri = await this.web3Api.getTokenUri({
|
|
4370
|
+
contractAddress: params.contractAddress,
|
|
4371
|
+
abi: params.abi,
|
|
4372
|
+
tokenId: params.tokenId,
|
|
4373
|
+
chainId: params.chainId
|
|
4374
|
+
});
|
|
4375
|
+
let metadata = null;
|
|
4376
|
+
if (tokenUri) {
|
|
4377
|
+
metadata = await this.metadataService.fetchAndProcessMetadata(tokenUri, params.chainId);
|
|
4334
4378
|
}
|
|
4379
|
+
return {
|
|
4380
|
+
tokenId: params.tokenId,
|
|
4381
|
+
tokenUri,
|
|
4382
|
+
metadata
|
|
4383
|
+
};
|
|
4384
|
+
}
|
|
4385
|
+
catch (error) {
|
|
4386
|
+
console.error('Error getting token metadata:', error);
|
|
4387
|
+
return {
|
|
4388
|
+
tokenId: params.tokenId,
|
|
4389
|
+
tokenUri: null,
|
|
4390
|
+
metadata: null
|
|
4391
|
+
};
|
|
4392
|
+
}
|
|
4393
|
+
}
|
|
4394
|
+
}
|
|
4395
|
+
|
|
4396
|
+
/**
|
|
4397
|
+
* MetadataDomainService - Clean IPFS metadata resolution
|
|
4398
|
+
*/
|
|
4399
|
+
class MetadataDomainService {
|
|
4400
|
+
constructor(ipfsApi) {
|
|
4401
|
+
this.ipfsApi = ipfsApi;
|
|
4402
|
+
}
|
|
4403
|
+
async fetchAndProcessMetadata(tokenUri, chainId) {
|
|
4404
|
+
return this.ipfsApi.fetchAndProcessMetadata(tokenUri, chainId);
|
|
4405
|
+
}
|
|
4406
|
+
async resolveIPFSUrl(url, chainId) {
|
|
4407
|
+
return this.ipfsApi.resolveIPFSUrl(url, chainId);
|
|
4408
|
+
}
|
|
4409
|
+
}
|
|
4410
|
+
|
|
4411
|
+
/**
|
|
4412
|
+
* ContractDomainService - Clean contract analysis without external dependencies
|
|
4413
|
+
*/
|
|
4414
|
+
class ContractDomainService {
|
|
4415
|
+
constructor() { }
|
|
4416
|
+
analyzeContract(abi) {
|
|
4417
|
+
const methods = abi.filter(item => item.type === 'function').map(item => item.name);
|
|
4418
|
+
// ERC-721 detection
|
|
4419
|
+
const hasOwnerOf = methods.includes('ownerOf');
|
|
4420
|
+
const hasTokenURI = methods.includes('tokenURI');
|
|
4421
|
+
const hasTransferFrom = methods.includes('transferFrom');
|
|
4422
|
+
const isERC721 = hasOwnerOf && hasTokenURI && hasTransferFrom;
|
|
4423
|
+
// ERC-1155 detection
|
|
4424
|
+
const hasBalanceOfBatch = methods.includes('balanceOfBatch');
|
|
4425
|
+
const hasSafeBatchTransferFrom = methods.includes('safeBatchTransferFrom');
|
|
4426
|
+
const hasURI = methods.includes('uri');
|
|
4427
|
+
const isERC1155 = hasBalanceOfBatch && hasSafeBatchTransferFrom && hasURI;
|
|
4428
|
+
return {
|
|
4429
|
+
hasEnumeration: methods.includes('tokenByIndex') && methods.includes('totalSupply'),
|
|
4430
|
+
hasOwnerOf,
|
|
4431
|
+
hasBalanceOf: methods.includes('balanceOf'),
|
|
4432
|
+
hasTokenURI,
|
|
4433
|
+
hasTransfer: methods.includes('transfer') || methods.includes('transferFrom'),
|
|
4434
|
+
hasApprove: methods.includes('approve'),
|
|
4435
|
+
isERC721,
|
|
4436
|
+
isERC1155
|
|
4335
4437
|
};
|
|
4336
|
-
// ✅ CACHE SET: Store complete collection response
|
|
4337
|
-
this.cache.set(cacheKey, response);
|
|
4338
|
-
return response;
|
|
4339
4438
|
}
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
const
|
|
4345
|
-
return
|
|
4346
|
-
|
|
4347
|
-
|
|
4439
|
+
supportsEnumeration(abi) {
|
|
4440
|
+
return this.analyzeContract(abi).hasEnumeration;
|
|
4441
|
+
}
|
|
4442
|
+
supportsMethod(abi, methodName) {
|
|
4443
|
+
const methods = abi.filter(item => item.type === 'function').map(item => item.name);
|
|
4444
|
+
return methods.includes(methodName);
|
|
4445
|
+
}
|
|
4446
|
+
}
|
|
4447
|
+
|
|
4448
|
+
/**
|
|
4449
|
+
* Web3ApplicationService - Application layer entrance point
|
|
4450
|
+
* Orchestrates domain services and provides clean public interface
|
|
4451
|
+
* Simplified architecture with concrete classes
|
|
4452
|
+
*/
|
|
4453
|
+
class Web3ApplicationService {
|
|
4454
|
+
constructor(web3Api, ipfsApi) {
|
|
4455
|
+
// Type-safe metadata conversion methods for ERC-721/ERC-1155 standards
|
|
4456
|
+
this.metadataMapper = {
|
|
4457
|
+
fromERCStandard: (ercMetadata) => ({
|
|
4458
|
+
name: ercMetadata.name || '',
|
|
4459
|
+
description: ercMetadata.description || '',
|
|
4460
|
+
imageUrl: ercMetadata.image || '',
|
|
4461
|
+
externalUrl: ercMetadata.external_url,
|
|
4462
|
+
animationUrl: ercMetadata.animation_url,
|
|
4463
|
+
animationUrlConverted: undefined, // Will be set by IPFS conversion
|
|
4464
|
+
attributes: ercMetadata.attributes || [],
|
|
4465
|
+
...ercMetadata
|
|
4466
|
+
}),
|
|
4467
|
+
toERCStandard: (metadata) => ({
|
|
4468
|
+
name: metadata.name,
|
|
4469
|
+
description: metadata.description,
|
|
4470
|
+
image: metadata.imageUrl,
|
|
4471
|
+
animation_url: metadata.animationUrl,
|
|
4472
|
+
external_url: metadata.externalUrl,
|
|
4473
|
+
attributes: metadata.attributes,
|
|
4474
|
+
...Object.fromEntries(Object.entries(metadata).filter(([key]) => !['name', 'description', 'imageUrl', 'animationUrl', 'externalUrl', 'attributes', 'animationUrlConverted'].includes(key)))
|
|
4475
|
+
})
|
|
4476
|
+
};
|
|
4477
|
+
// Create domain services with injected infrastructure dependencies
|
|
4478
|
+
this.contractDomainService = new ContractDomainService();
|
|
4479
|
+
this.metadataDomainService = new MetadataDomainService(ipfsApi);
|
|
4480
|
+
this.tokenDomainService = new TokenDomainService(web3Api, this.metadataDomainService, this.contractDomainService);
|
|
4481
|
+
}
|
|
4482
|
+
/**
|
|
4483
|
+
* Get balance and metadata for a specific token
|
|
4484
|
+
*/
|
|
4485
|
+
async getSpecificTokenBalance(request) {
|
|
4486
|
+
if (!request.tokenId) {
|
|
4487
|
+
return this.tokenDomainService.getTokenBalance({
|
|
4488
|
+
accountAddress: request.accountAddress || '',
|
|
4489
|
+
contractAddress: request.contractAddress,
|
|
4490
|
+
abi: request.abi,
|
|
4491
|
+
tokenId: '',
|
|
4492
|
+
chainId: request.chainId
|
|
4493
|
+
});
|
|
4494
|
+
}
|
|
4495
|
+
return this.tokenDomainService.getTokenWithMetadata({
|
|
4496
|
+
accountAddress: request.accountAddress || '',
|
|
4497
|
+
contractAddress: request.contractAddress,
|
|
4498
|
+
abi: request.abi,
|
|
4499
|
+
tokenId: request.tokenId || '',
|
|
4500
|
+
chainId: request.chainId
|
|
4501
|
+
});
|
|
4502
|
+
}
|
|
4503
|
+
/**
|
|
4504
|
+
* Get metadata for a specific token from on-chain
|
|
4505
|
+
*/
|
|
4506
|
+
async getTokenMetadata(request) {
|
|
4507
|
+
const domainResult = await this.tokenDomainService.getTokenMetadata({
|
|
4508
|
+
contractAddress: request.contractAddress,
|
|
4509
|
+
abi: request.abi,
|
|
4510
|
+
tokenId: request.tokenId || '',
|
|
4511
|
+
chainId: request.chainId
|
|
4512
|
+
});
|
|
4513
|
+
return domainResult.metadata;
|
|
4514
|
+
}
|
|
4515
|
+
/**
|
|
4516
|
+
* Retrieve entire collection of tokens with balance and metadata
|
|
4517
|
+
*/
|
|
4518
|
+
async getTokenCollection(request) {
|
|
4519
|
+
return this.tokenDomainService.getTokenCollection({
|
|
4520
|
+
accountAddress: request.accountAddress || '',
|
|
4521
|
+
contractAddress: request.contractAddress,
|
|
4522
|
+
abi: request.abi,
|
|
4523
|
+
chainId: request.chainId,
|
|
4524
|
+
maxTokens: request.maxTokens,
|
|
4525
|
+
tokenIds: request.tokenIds
|
|
4348
4526
|
});
|
|
4349
4527
|
}
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4528
|
+
/**
|
|
4529
|
+
* Resolve IPFS URLs to HTTPS if needed
|
|
4530
|
+
*/
|
|
4531
|
+
async resolveIPFSUrl(url, chainId) {
|
|
4532
|
+
return this.metadataDomainService.resolveIPFSUrl(url, chainId);
|
|
4533
|
+
}
|
|
4534
|
+
/**
|
|
4535
|
+
* Fetch and process metadata from URI with IPFS conversion
|
|
4536
|
+
*/
|
|
4537
|
+
async fetchAndProcessMetadata(tokenUri, chainId) {
|
|
4538
|
+
const domainMetadata = await this.metadataDomainService.fetchAndProcessMetadata(tokenUri, chainId);
|
|
4539
|
+
if (!domainMetadata)
|
|
4353
4540
|
return null;
|
|
4354
|
-
|
|
4541
|
+
// Convert from ERC token standard to our clean interface
|
|
4542
|
+
const cleanMetadata = this.metadataMapper.fromERCStandard(domainMetadata);
|
|
4543
|
+
// Add IPFS conversion if needed
|
|
4544
|
+
if (cleanMetadata.animationUrl?.startsWith('ipfs://')) {
|
|
4545
|
+
return {
|
|
4546
|
+
...cleanMetadata,
|
|
4547
|
+
animationUrlConverted: await this.resolveIPFSUrl(cleanMetadata.animationUrl, chainId)
|
|
4548
|
+
};
|
|
4549
|
+
}
|
|
4550
|
+
return cleanMetadata;
|
|
4355
4551
|
}
|
|
4356
|
-
|
|
4552
|
+
}
|
|
4553
|
+
|
|
4554
|
+
/**
|
|
4555
|
+
* Web3InfrastructureApi - Infrastructure implementation for blockchain operations
|
|
4556
|
+
* Uses @explorins/web3-ts for Web3 interactions
|
|
4557
|
+
*/
|
|
4558
|
+
class Web3InfrastructureApi {
|
|
4559
|
+
constructor(web3ChainService) {
|
|
4560
|
+
this.web3ChainService = web3ChainService;
|
|
4561
|
+
}
|
|
4562
|
+
async getTokenBalance(request) {
|
|
4357
4563
|
try {
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
return await response.json();
|
|
4564
|
+
if (request.tokenId !== null)
|
|
4565
|
+
request.tokenId = request.tokenId.toString();
|
|
4566
|
+
const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
|
|
4567
|
+
const contract = getSmartContractInstance(request.contractAddress, request.abi, web3);
|
|
4568
|
+
return await getAccountTokenBalance(contract, request.accountAddress, request.tokenId);
|
|
4364
4569
|
}
|
|
4365
4570
|
catch (error) {
|
|
4366
|
-
console.
|
|
4367
|
-
return
|
|
4571
|
+
console.error(`Failed to get token balance for ${request.accountAddress} for ${request.contractAddress} and tokenId ${request.tokenId}, return 0 instead:`, error);
|
|
4572
|
+
return 0;
|
|
4368
4573
|
}
|
|
4369
4574
|
}
|
|
4575
|
+
async getTokenUri(request) {
|
|
4576
|
+
try {
|
|
4577
|
+
const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
|
|
4578
|
+
const contract = getSmartContractInstance(request.contractAddress, request.abi, web3);
|
|
4579
|
+
const tokenId = Number(request.tokenId);
|
|
4580
|
+
const tokenUri = await getTokenUri(contract, tokenId);
|
|
4581
|
+
return String(tokenUri);
|
|
4582
|
+
}
|
|
4583
|
+
catch (error) {
|
|
4584
|
+
console.error(`Failed to get token URI for tokenId ${request.tokenId}:`, error);
|
|
4585
|
+
throw error;
|
|
4586
|
+
}
|
|
4587
|
+
}
|
|
4588
|
+
async getTokenOfOwnerByIndex(request) {
|
|
4589
|
+
try {
|
|
4590
|
+
const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
|
|
4591
|
+
const tokenContract = getSmartContractInstance(request.contractAddress, request.abi, web3);
|
|
4592
|
+
const tokenId = await getTokenOfOwnerByIndex(tokenContract, request.accountAddress, request.tokenIndex);
|
|
4593
|
+
return String(tokenId);
|
|
4594
|
+
}
|
|
4595
|
+
catch (error) {
|
|
4596
|
+
console.error(`Failed to get token by index ${request.tokenIndex} for ${request.accountAddress}:`, error);
|
|
4597
|
+
throw error;
|
|
4598
|
+
}
|
|
4599
|
+
}
|
|
4600
|
+
}
|
|
4601
|
+
|
|
4602
|
+
/**
|
|
4603
|
+
* IPFSInfrastructureApi - Infrastructure implementation for IPFS operations
|
|
4604
|
+
* Uses Web3ChainService for IPFS gateway resolution
|
|
4605
|
+
*/
|
|
4606
|
+
class IPFSInfrastructureApi {
|
|
4607
|
+
constructor(web3ChainService) {
|
|
4608
|
+
this.web3ChainService = web3ChainService;
|
|
4609
|
+
this.defaultIpfsGatewayDomain = 'pers.mypinata.cloud';
|
|
4610
|
+
}
|
|
4370
4611
|
async getIpfsGatewayDomain(chainId) {
|
|
4371
4612
|
try {
|
|
4372
4613
|
const chainData = await this.web3ChainService.getChainDataWithCache(chainId);
|
|
@@ -4378,31 +4619,68 @@ class Web3Service {
|
|
|
4378
4619
|
}
|
|
4379
4620
|
}
|
|
4380
4621
|
async resolveIPFSUrl(url, chainId) {
|
|
4381
|
-
if (!url)
|
|
4382
|
-
return '';
|
|
4383
4622
|
if (url.startsWith('ipfs://')) {
|
|
4384
|
-
const
|
|
4385
|
-
return `https://${
|
|
4623
|
+
const gateway = await this.getIpfsGatewayDomain(chainId);
|
|
4624
|
+
return url.replace('ipfs://', `https://${gateway}/ipfs/`);
|
|
4386
4625
|
}
|
|
4387
4626
|
return url;
|
|
4388
4627
|
}
|
|
4628
|
+
async fetchAndProcessMetadata(tokenUri, chainId) {
|
|
4629
|
+
try {
|
|
4630
|
+
const resolvedUri = await this.resolveIPFSUrl(tokenUri, chainId);
|
|
4631
|
+
const response = await fetch(resolvedUri);
|
|
4632
|
+
if (!response.ok) {
|
|
4633
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
4634
|
+
}
|
|
4635
|
+
const metadata = await response.json();
|
|
4636
|
+
// Process and return clean metadata
|
|
4637
|
+
return {
|
|
4638
|
+
name: metadata.name || '',
|
|
4639
|
+
description: metadata.description || '',
|
|
4640
|
+
image: metadata.image ? await this.resolveIPFSUrl(metadata.image, chainId) : '',
|
|
4641
|
+
attributes: metadata.attributes || [],
|
|
4642
|
+
animation_url: metadata.animation_url ? await this.resolveIPFSUrl(metadata.animation_url, chainId) : undefined,
|
|
4643
|
+
external_url: metadata.external_url || undefined
|
|
4644
|
+
};
|
|
4645
|
+
}
|
|
4646
|
+
catch (error) {
|
|
4647
|
+
console.error('Error fetching metadata:', error);
|
|
4648
|
+
return null;
|
|
4649
|
+
}
|
|
4650
|
+
}
|
|
4651
|
+
async fetchFromUrl(url) {
|
|
4652
|
+
try {
|
|
4653
|
+
const response = await fetch(url);
|
|
4654
|
+
if (!response.ok) {
|
|
4655
|
+
throw new Error(`Failed to fetch from ${url}: ${response.statusText}`);
|
|
4656
|
+
}
|
|
4657
|
+
return await response.json();
|
|
4658
|
+
}
|
|
4659
|
+
catch (error) {
|
|
4660
|
+
console.error(`Error fetching from URL ${url}:`, error);
|
|
4661
|
+
throw error;
|
|
4662
|
+
}
|
|
4663
|
+
}
|
|
4389
4664
|
}
|
|
4390
4665
|
|
|
4391
|
-
//import { PublicHttpProviderService } from '../web3-chain/services/public-http-provider.service';
|
|
4392
4666
|
function createWeb3SDK(apiClient) {
|
|
4393
4667
|
// TODO: FIX LATER - TEMPORARY CONSTRUCTION
|
|
4394
4668
|
const web3ProviderService = new Web3ProviderService();
|
|
4395
4669
|
const web3ChainSDK = createWeb3ChainSDK(apiClient, web3ProviderService);
|
|
4396
|
-
|
|
4397
|
-
const
|
|
4670
|
+
// Create Web3ApplicationService - main entry point for all Web3 operations
|
|
4671
|
+
const web3InfrastructureApi = new Web3InfrastructureApi(web3ChainSDK.service);
|
|
4672
|
+
const ipfsInfrastructureApi = new IPFSInfrastructureApi(web3ChainSDK.service);
|
|
4673
|
+
const web3ApplicationService = new Web3ApplicationService(web3InfrastructureApi, ipfsInfrastructureApi);
|
|
4674
|
+
// Clean SDK - all functions route through Web3ApplicationService
|
|
4398
4675
|
return {
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4676
|
+
getTokenBalance: (request) => web3ApplicationService.getSpecificTokenBalance(request),
|
|
4677
|
+
getTokenMetadata: (request) => web3ApplicationService.getTokenMetadata(request),
|
|
4678
|
+
getTokenCollection: (request) => web3ApplicationService.getTokenCollection(request),
|
|
4679
|
+
resolveIPFSUrl: (url, chainId) => web3ApplicationService.resolveIPFSUrl(url, chainId),
|
|
4680
|
+
fetchAndProcessMetadata: (tokenUri, chainId) => web3ApplicationService.fetchAndProcessMetadata(tokenUri, chainId),
|
|
4681
|
+
applicationService: web3ApplicationService
|
|
4404
4682
|
};
|
|
4405
4683
|
}
|
|
4406
4684
|
|
|
4407
|
-
export { AnalyticsApi, AnalyticsService, AuthAdminApi, AuthAdminService, BaseTokenService, BusinessApi, BusinessService, CampaignApi, CampaignService, ChainTypes, DEFAULT_PERS_CONFIG, DonationApi, DonationService, PurchaseApi as PaymentApi, PaymentService, PersApiClient, PersApiError, PersSDK, RedemptionApi, RedemptionService,
|
|
4685
|
+
export { AnalyticsApi, AnalyticsService, AuthAdminApi, AuthAdminService, BaseTokenService, BusinessApi, BusinessService, CampaignApi, CampaignService, ChainTypes, DEFAULT_PERS_CONFIG, DonationApi, DonationService, IPFSInfrastructureApi, PurchaseApi as PaymentApi, PaymentService, PersApiClient, PersApiError, PersSDK, RedemptionApi, RedemptionService, TenantApi, TenantService, TokenApi, TokenSDK, TokenService, TransactionAccountType, TransactionApi, TransactionService, UserApi, UserService, UserStatusApi, UserStatusService, Web3ApplicationService, Web3ChainApi, Web3ChainService, Web3InfrastructureApi, Web3ProviderService, buildApiRoot, createAnalyticsSDK, createAuthAdminSDK, createAuthProvider, createBusinessSDK, createCampaignSDK, createDonationSDK, createPaymentSDK, createPersSDK, createRedemptionSDK, createTenantSDK, createTransactionSDK, createUserSDK, createUserStatusSDK, createWeb3ChainSDK, createWeb3SDK, mergeWithDefaults };
|
|
4408
4686
|
//# sourceMappingURL=index.js.map
|