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