@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.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,18 @@ 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);
|
|
1293
|
+
}
|
|
1294
|
+
async loginUser(jwt) {
|
|
1295
|
+
const body = {
|
|
1296
|
+
authToken: jwt,
|
|
1297
|
+
authType: AccountOwnerType.USER
|
|
1298
|
+
};
|
|
1299
|
+
return this.apiClient.post(`${this.basePath}/token`, body);
|
|
1281
1300
|
}
|
|
1282
1301
|
/**
|
|
1283
1302
|
* ADMIN: Refresh access token
|
|
@@ -1309,6 +1328,12 @@ class AuthAdminService {
|
|
|
1309
1328
|
async loginTenantAdmin(jwt) {
|
|
1310
1329
|
return this.authAdminApi.loginTenantAdmin(jwt);
|
|
1311
1330
|
}
|
|
1331
|
+
/**
|
|
1332
|
+
* ADMIN: Login user with JWT
|
|
1333
|
+
*/
|
|
1334
|
+
async loginUser(jwt) {
|
|
1335
|
+
return this.authAdminApi.loginUser(jwt);
|
|
1336
|
+
}
|
|
1312
1337
|
/**
|
|
1313
1338
|
* ADMIN: Refresh access token
|
|
1314
1339
|
*/
|
|
@@ -1337,6 +1362,7 @@ function createAuthAdminSDK(apiClient) {
|
|
|
1337
1362
|
// Direct access to service methods (primary interface)
|
|
1338
1363
|
// Admin authentication methods
|
|
1339
1364
|
loginTenantAdmin: (jwt) => authAdminService.loginTenantAdmin(jwt),
|
|
1365
|
+
loginUser: (jwt) => authAdminService.loginUser(jwt),
|
|
1340
1366
|
refreshAccessToken: (refreshToken) => authAdminService.refreshAccessToken(refreshToken),
|
|
1341
1367
|
// Advanced access for edge cases
|
|
1342
1368
|
api: authAdminApi,
|
|
@@ -1586,81 +1612,102 @@ class CampaignApi {
|
|
|
1586
1612
|
* NEW: POST /campaign-claims/user
|
|
1587
1613
|
*/
|
|
1588
1614
|
async claimCampaign(request) {
|
|
1589
|
-
return this.apiClient.post('/campaign-claims
|
|
1615
|
+
return this.apiClient.post('/campaign-claims', request);
|
|
1590
1616
|
}
|
|
1591
1617
|
/**
|
|
1592
1618
|
* USER: Get claims for logged user
|
|
1593
1619
|
* NEW: GET /campaign-claims/users/me
|
|
1594
1620
|
*/
|
|
1595
1621
|
async getClaimsForLoggedUser() {
|
|
1596
|
-
return this.apiClient.get('/campaign-claims/
|
|
1622
|
+
return this.apiClient.get('/campaign-claims/me');
|
|
1597
1623
|
}
|
|
1598
1624
|
/**
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
async
|
|
1603
|
-
|
|
1625
|
+
* ADMIN: Get all campaign claims
|
|
1626
|
+
* Updated to use unified endpoint
|
|
1627
|
+
*/
|
|
1628
|
+
async getCampaignClaims() {
|
|
1629
|
+
// Admin context - no parameters needed for all claims
|
|
1630
|
+
return this.apiClient.get('/campaign-claims');
|
|
1604
1631
|
}
|
|
1605
1632
|
/**
|
|
1606
|
-
*
|
|
1607
|
-
*
|
|
1633
|
+
* ADMIN: Get campaign claims by campaign ID
|
|
1634
|
+
* Updated to use query parameters
|
|
1608
1635
|
*/
|
|
1609
|
-
async
|
|
1610
|
-
return this.apiClient.
|
|
1636
|
+
async getCampaignClaimsByCampaignId(campaignId) {
|
|
1637
|
+
return this.apiClient.get(`/campaign-claims?campaignId=${campaignId}`);
|
|
1611
1638
|
}
|
|
1612
1639
|
/**
|
|
1613
|
-
* ADMIN:
|
|
1614
|
-
*
|
|
1640
|
+
* ADMIN: Get campaign claims by user ID
|
|
1641
|
+
* Updated to use query parameters
|
|
1615
1642
|
*/
|
|
1616
|
-
async
|
|
1617
|
-
return this.apiClient.
|
|
1643
|
+
async getCampaignClaimsByUserId(userId) {
|
|
1644
|
+
return this.apiClient.get(`/campaign-claims?userId=${userId}`);
|
|
1618
1645
|
}
|
|
1619
1646
|
/**
|
|
1620
|
-
* ADMIN: Get
|
|
1621
|
-
*
|
|
1647
|
+
* ADMIN: Get campaign claims by business ID
|
|
1648
|
+
* Updated to use query parameters
|
|
1622
1649
|
*/
|
|
1623
|
-
async
|
|
1624
|
-
return this.apiClient.get(
|
|
1650
|
+
async getCampaignClaimsByBusinessId(businessId) {
|
|
1651
|
+
return this.apiClient.get(`/campaign-claims?businessId=${businessId}`);
|
|
1625
1652
|
}
|
|
1626
1653
|
/**
|
|
1627
|
-
* ADMIN: Get campaign claims by
|
|
1628
|
-
*
|
|
1654
|
+
* ADMIN: Get campaign claims by user ID for specific campaign
|
|
1655
|
+
* Combined filtering using query parameters
|
|
1629
1656
|
*/
|
|
1630
|
-
async
|
|
1631
|
-
return this.apiClient.get(`/campaign-claims
|
|
1657
|
+
async getCampaignClaimsByUserAndCampaign(userId, campaignId) {
|
|
1658
|
+
return this.apiClient.get(`/campaign-claims?userId=${userId}&campaignId=${campaignId}`);
|
|
1632
1659
|
}
|
|
1633
1660
|
/**
|
|
1634
|
-
* ADMIN: Get campaign claims by
|
|
1635
|
-
*
|
|
1661
|
+
* ADMIN: Get campaign claims by business ID for specific campaign
|
|
1662
|
+
* Combined filtering using query parameters
|
|
1636
1663
|
*/
|
|
1637
|
-
async
|
|
1638
|
-
return this.apiClient.get(`/campaign-claims
|
|
1664
|
+
async getCampaignClaimsByBusinessAndCampaign(businessId, campaignId) {
|
|
1665
|
+
return this.apiClient.get(`/campaign-claims?businessId=${businessId}&campaignId=${campaignId}`);
|
|
1639
1666
|
}
|
|
1640
1667
|
/**
|
|
1641
|
-
*
|
|
1642
|
-
*
|
|
1668
|
+
* USER: Get user's own claims (all campaigns)
|
|
1669
|
+
* Use convenience endpoint
|
|
1643
1670
|
*/
|
|
1644
|
-
async
|
|
1645
|
-
return this.apiClient.get(
|
|
1671
|
+
async getUserClaims() {
|
|
1672
|
+
return this.apiClient.get('/campaign-claims/me');
|
|
1646
1673
|
}
|
|
1647
1674
|
/**
|
|
1648
1675
|
* USER: Get user's claims for specific campaign
|
|
1649
|
-
*
|
|
1676
|
+
* Use convenience endpoint with query parameter
|
|
1650
1677
|
*/
|
|
1651
1678
|
async getUserClaimsForCampaign(campaignId) {
|
|
1652
|
-
return this.apiClient.get(`/campaign-claims/
|
|
1679
|
+
return this.apiClient.get(`/campaign-claims/me?campaignId=${campaignId}`);
|
|
1680
|
+
}
|
|
1681
|
+
/**
|
|
1682
|
+
* BUSINESS: Get business claims (all campaigns)
|
|
1683
|
+
* Uses unified endpoint with business context
|
|
1684
|
+
*/
|
|
1685
|
+
async getBusinessClaims() {
|
|
1686
|
+
return this.apiClient.get('/campaign-claims');
|
|
1653
1687
|
}
|
|
1654
|
-
// ==========================================
|
|
1655
|
-
// BACKWARD COMPATIBILITY (DEPRECATED)
|
|
1656
|
-
// ==========================================
|
|
1657
1688
|
/**
|
|
1658
|
-
*
|
|
1659
|
-
*
|
|
1689
|
+
* BUSINESS: Get business claims for specific campaign
|
|
1690
|
+
* Uses unified endpoint with business context and campaign filter
|
|
1660
1691
|
*/
|
|
1661
|
-
async
|
|
1662
|
-
|
|
1663
|
-
|
|
1692
|
+
async getBusinessClaimsForCampaign(campaignId) {
|
|
1693
|
+
return this.apiClient.get(`/campaign-claims?campaignId=${campaignId}`);
|
|
1694
|
+
}
|
|
1695
|
+
/**
|
|
1696
|
+
* Helper: Build query string from parameters
|
|
1697
|
+
*/
|
|
1698
|
+
buildQueryString(params) {
|
|
1699
|
+
const validParams = Object.entries(params)
|
|
1700
|
+
.filter(([_, value]) => value !== undefined)
|
|
1701
|
+
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
|
|
1702
|
+
.join('&');
|
|
1703
|
+
return validParams ? `?${validParams}` : '';
|
|
1704
|
+
}
|
|
1705
|
+
/**
|
|
1706
|
+
* Flexible admin claims query with multiple filters
|
|
1707
|
+
*/
|
|
1708
|
+
async getAdminClaims(filters) {
|
|
1709
|
+
const queryString = this.buildQueryString(filters || {});
|
|
1710
|
+
return this.apiClient.get(`/campaign-claims${queryString}`);
|
|
1664
1711
|
}
|
|
1665
1712
|
}
|
|
1666
1713
|
|
|
@@ -2171,20 +2218,21 @@ function createPaymentSDK(apiClient) {
|
|
|
2171
2218
|
/**
|
|
2172
2219
|
* Platform-Agnostic Redemption API Client (UPDATED - RESTful Design)
|
|
2173
2220
|
*
|
|
2174
|
-
* Updated to work with the new RESTful /redemptions endpoints.
|
|
2221
|
+
* Updated to work with the new RESTful /redemptions and /redemption-redeems endpoints.
|
|
2175
2222
|
* Handles redemption operations using the PERS backend with intelligent access detection.
|
|
2176
2223
|
* Uses @explorins/pers-shared DTOs for consistency with backend.
|
|
2177
2224
|
*
|
|
2178
|
-
* Migration Update: Updated all endpoints
|
|
2225
|
+
* Migration Update: Updated all endpoints for unified controller pattern
|
|
2179
2226
|
* - Removed role revelation from URLs (no more /admin, /auth paths)
|
|
2180
2227
|
* - Added intelligent access detection for unified endpoints
|
|
2181
|
-
* -
|
|
2182
|
-
* - Enhanced redemption process with
|
|
2228
|
+
* - Added new /redemption-redeems endpoints for redeem processing
|
|
2229
|
+
* - Enhanced redemption process with role-based access control
|
|
2183
2230
|
*/
|
|
2184
2231
|
class RedemptionApi {
|
|
2185
2232
|
constructor(apiClient) {
|
|
2186
2233
|
this.apiClient = apiClient;
|
|
2187
2234
|
this.basePath = '/redemptions';
|
|
2235
|
+
this.redeemsPath = '/redemption-redeems';
|
|
2188
2236
|
}
|
|
2189
2237
|
// ==========================================
|
|
2190
2238
|
// PUBLIC OPERATIONS (Project Key)
|
|
@@ -2219,7 +2267,7 @@ class RedemptionApi {
|
|
|
2219
2267
|
* Updated: /redemption/type → /redemptions/types
|
|
2220
2268
|
*/
|
|
2221
2269
|
async getRedemptionTypes() {
|
|
2222
|
-
return this.apiClient.get(
|
|
2270
|
+
return this.apiClient.get(`/redemption-types`);
|
|
2223
2271
|
}
|
|
2224
2272
|
/**
|
|
2225
2273
|
* PUBLIC: Get redemption by ID
|
|
@@ -2232,33 +2280,106 @@ class RedemptionApi {
|
|
|
2232
2280
|
/**
|
|
2233
2281
|
* PUBLIC: Get available supply for redemption
|
|
2234
2282
|
*
|
|
2235
|
-
* Updated: /redemption/:id/available-supply → /redemptions/:id/
|
|
2283
|
+
* Updated: /redemption/:id/available-supply → /redemptions/:id/supply
|
|
2236
2284
|
*/
|
|
2237
2285
|
async getRedemptionAvailableSupply(id) {
|
|
2238
|
-
return this.apiClient.get(`${this.basePath}/${id}/
|
|
2286
|
+
return this.apiClient.get(`${this.basePath}/${id}/supply`);
|
|
2239
2287
|
}
|
|
2240
2288
|
// ==========================================
|
|
2241
|
-
//
|
|
2289
|
+
// REDEMPTION EXECUTION (NEW UNIFIED ENDPOINT)
|
|
2242
2290
|
// ==========================================
|
|
2243
2291
|
/**
|
|
2244
|
-
*
|
|
2292
|
+
* Execute redemption (unified endpoint)
|
|
2245
2293
|
*
|
|
2246
|
-
*
|
|
2247
|
-
*
|
|
2294
|
+
* NEW: POST /redemption-redeems - Role-based processing
|
|
2295
|
+
* - USER: Direct user redemption processing
|
|
2296
|
+
* - ADMIN: Can process redemptions for any account type
|
|
2297
|
+
* - BUSINESS: Process redemptions for customers
|
|
2248
2298
|
*/
|
|
2249
2299
|
async redeemRedemption(redemptionId) {
|
|
2250
2300
|
const body = {
|
|
2251
2301
|
redemptionId: redemptionId,
|
|
2252
2302
|
};
|
|
2253
|
-
return this.apiClient.post(
|
|
2303
|
+
return this.apiClient.post(this.redeemsPath, body);
|
|
2304
|
+
}
|
|
2305
|
+
// ==========================================
|
|
2306
|
+
// REDEMPTION REDEEMS QUERIES (NEW ENDPOINTS)
|
|
2307
|
+
// ==========================================
|
|
2308
|
+
/**
|
|
2309
|
+
* Get redemption redeems with filtering (unified endpoint)
|
|
2310
|
+
*
|
|
2311
|
+
* NEW: GET /redemption-redeems with query parameters
|
|
2312
|
+
* Role-based access: Users see only their own, admins can filter by userId/businessId
|
|
2313
|
+
*/
|
|
2314
|
+
async getRedemptionRedeems(filters) {
|
|
2315
|
+
let url = this.redeemsPath;
|
|
2316
|
+
const params = new URLSearchParams();
|
|
2317
|
+
if (filters?.redemptionId)
|
|
2318
|
+
params.append('redemptionId', filters.redemptionId);
|
|
2319
|
+
if (filters?.userId)
|
|
2320
|
+
params.append('userId', filters.userId);
|
|
2321
|
+
if (filters?.businessId)
|
|
2322
|
+
params.append('businessId', filters.businessId);
|
|
2323
|
+
const queryString = params.toString();
|
|
2324
|
+
if (queryString) {
|
|
2325
|
+
url += `?${queryString}`;
|
|
2326
|
+
}
|
|
2327
|
+
return this.apiClient.get(url);
|
|
2328
|
+
}
|
|
2329
|
+
/**
|
|
2330
|
+
* Get specific redemption redeem by ID
|
|
2331
|
+
*
|
|
2332
|
+
* NEW: GET /redemption-redeems/:id
|
|
2333
|
+
*/
|
|
2334
|
+
async getRedemptionRedeemById(id) {
|
|
2335
|
+
return this.apiClient.get(`${this.redeemsPath}/${id}`);
|
|
2336
|
+
}
|
|
2337
|
+
/**
|
|
2338
|
+
* USER: Get my redemption redeems (convenience endpoint)
|
|
2339
|
+
*
|
|
2340
|
+
* NEW: GET /redemption-redeems/me with optional filtering
|
|
2341
|
+
*/
|
|
2342
|
+
async getMyRedemptionRedeems(redemptionId) {
|
|
2343
|
+
let url = `${this.redeemsPath}/me`;
|
|
2344
|
+
if (redemptionId) {
|
|
2345
|
+
url += `?redemptionId=${redemptionId}`;
|
|
2346
|
+
}
|
|
2347
|
+
return this.apiClient.get(url);
|
|
2254
2348
|
}
|
|
2349
|
+
/**
|
|
2350
|
+
* ADMIN: Get redemption redeems by user ID
|
|
2351
|
+
*
|
|
2352
|
+
* NEW: GET /redemption-redeems?userId=X
|
|
2353
|
+
*/
|
|
2354
|
+
async getRedemptionRedeemsByUserId(userId, redemptionId) {
|
|
2355
|
+
return this.getRedemptionRedeems({ userId, redemptionId });
|
|
2356
|
+
}
|
|
2357
|
+
/**
|
|
2358
|
+
* ADMIN: Get redemption redeems by business ID
|
|
2359
|
+
*
|
|
2360
|
+
* NEW: GET /redemption-redeems?businessId=X
|
|
2361
|
+
*/
|
|
2362
|
+
async getRedemptionRedeemsByBusinessId(businessId, redemptionId) {
|
|
2363
|
+
return this.getRedemptionRedeems({ businessId, redemptionId });
|
|
2364
|
+
}
|
|
2365
|
+
/**
|
|
2366
|
+
* ADMIN: Get redemption redeems by redemption ID
|
|
2367
|
+
*
|
|
2368
|
+
* NEW: GET /redemption-redeems?redemptionId=X
|
|
2369
|
+
*/
|
|
2370
|
+
async getRedemptionRedeemsByRedemptionId(redemptionId) {
|
|
2371
|
+
return this.getRedemptionRedeems({ redemptionId });
|
|
2372
|
+
}
|
|
2373
|
+
// ==========================================
|
|
2374
|
+
// USER OPERATIONS (JWT + Project Key)
|
|
2375
|
+
// ==========================================
|
|
2255
2376
|
/**
|
|
2256
2377
|
* USER: Get user redemption history
|
|
2257
2378
|
*
|
|
2258
|
-
* Updated:
|
|
2379
|
+
* Updated: Uses new convenience endpoint /redemption-redeems/me
|
|
2259
2380
|
*/
|
|
2260
2381
|
async getUserRedemptionHistory() {
|
|
2261
|
-
return this.
|
|
2382
|
+
return this.getMyRedemptionRedeems();
|
|
2262
2383
|
}
|
|
2263
2384
|
/**
|
|
2264
2385
|
* USER: Get user redemptions (backward compatibility)
|
|
@@ -2327,7 +2448,7 @@ class RedemptionApi {
|
|
|
2327
2448
|
* Updated: /redemption/admin/type → /redemptions/types
|
|
2328
2449
|
*/
|
|
2329
2450
|
async createRedemptionType(redemptionType) {
|
|
2330
|
-
return this.apiClient.post(`${this.basePath}/types`, redemptionType);
|
|
2451
|
+
return this.apiClient.post(`${this.basePath}/redemption-types`, redemptionType);
|
|
2331
2452
|
}
|
|
2332
2453
|
// ==========================================
|
|
2333
2454
|
// TOKEN UNIT MANAGEMENT (Admin)
|
|
@@ -4062,311 +4183,445 @@ function createWeb3ChainSDK(apiClient, providerService) {
|
|
|
4062
4183
|
};
|
|
4063
4184
|
}
|
|
4064
4185
|
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4186
|
+
/**
|
|
4187
|
+
* TokenDomainService - Domain service for token operations
|
|
4188
|
+
* Implements business logic for token balance, metadata, and collection operations
|
|
4189
|
+
*/
|
|
4190
|
+
class TokenDomainService {
|
|
4191
|
+
constructor(web3Api, metadataService, contractService) {
|
|
4192
|
+
this.web3Api = web3Api;
|
|
4193
|
+
this.metadataService = metadataService;
|
|
4194
|
+
this.contractService = contractService;
|
|
4068
4195
|
}
|
|
4069
4196
|
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({
|
|
4197
|
+
const balance = await this.web3Api.getTokenBalance({
|
|
4161
4198
|
accountAddress: request.accountAddress,
|
|
4162
|
-
contractAddress: request.
|
|
4163
|
-
abi: request.
|
|
4164
|
-
tokenId:
|
|
4165
|
-
chainId: request.
|
|
4199
|
+
contractAddress: request.contractAddress,
|
|
4200
|
+
abi: request.abi,
|
|
4201
|
+
tokenId: request.tokenId,
|
|
4202
|
+
chainId: request.chainId
|
|
4166
4203
|
});
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
decimals,
|
|
4173
|
-
symbol,
|
|
4174
|
-
hasBalance: rawBalance > 0
|
|
4204
|
+
return {
|
|
4205
|
+
tokenId: request.tokenId,
|
|
4206
|
+
balance,
|
|
4207
|
+
hasBalance: balance > 0,
|
|
4208
|
+
metadata: null
|
|
4175
4209
|
};
|
|
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);
|
|
4210
|
+
}
|
|
4211
|
+
async getTokenWithMetadata(params) {
|
|
4212
|
+
try {
|
|
4213
|
+
const balance = await this.web3Api.getTokenBalance({
|
|
4214
|
+
accountAddress: params.accountAddress,
|
|
4215
|
+
contractAddress: params.contractAddress,
|
|
4216
|
+
abi: params.abi,
|
|
4217
|
+
tokenId: params.tokenId,
|
|
4218
|
+
chainId: params.chainId
|
|
4219
|
+
});
|
|
4220
|
+
let metadata = null;
|
|
4221
|
+
if (balance > 0) {
|
|
4222
|
+
const tokenUri = await this.web3Api.getTokenUri({
|
|
4223
|
+
contractAddress: params.contractAddress,
|
|
4224
|
+
abi: params.abi,
|
|
4225
|
+
tokenId: params.tokenId,
|
|
4226
|
+
chainId: params.chainId
|
|
4227
|
+
});
|
|
4228
|
+
if (tokenUri) {
|
|
4229
|
+
metadata = await this.metadataService.fetchAndProcessMetadata(tokenUri, params.chainId);
|
|
4224
4230
|
}
|
|
4225
4231
|
}
|
|
4226
4232
|
return {
|
|
4227
|
-
|
|
4228
|
-
|
|
4233
|
+
tokenId: params.tokenId,
|
|
4234
|
+
balance,
|
|
4235
|
+
hasBalance: balance > 0,
|
|
4236
|
+
metadata
|
|
4229
4237
|
};
|
|
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
4238
|
}
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4239
|
+
catch (error) {
|
|
4240
|
+
console.error('Error getting token with metadata:', error);
|
|
4241
|
+
return {
|
|
4242
|
+
tokenId: params.tokenId,
|
|
4243
|
+
balance: 0,
|
|
4244
|
+
hasBalance: false,
|
|
4245
|
+
metadata: null
|
|
4246
|
+
};
|
|
4247
|
+
}
|
|
4248
|
+
}
|
|
4249
|
+
async getTokenCollection(params) {
|
|
4250
|
+
try {
|
|
4251
|
+
const contractAnalysis = this.contractService.analyzeContract(params.abi);
|
|
4252
|
+
const tokens = [];
|
|
4253
|
+
if (!contractAnalysis.hasEnumeration && !contractAnalysis.isERC1155) {
|
|
4254
|
+
console.warn('Contract does not support enumeration, cannot retrieve full collection');
|
|
4255
|
+
return {
|
|
4256
|
+
accountAddress: params.accountAddress,
|
|
4257
|
+
contractAddress: params.contractAddress,
|
|
4258
|
+
totalBalance: 0,
|
|
4259
|
+
tokensRetrieved: 0,
|
|
4260
|
+
tokens: [],
|
|
4261
|
+
note: 'Contract does not support enumeration'
|
|
4262
|
+
};
|
|
4263
|
+
}
|
|
4264
|
+
else if (contractAnalysis.isERC1155) {
|
|
4265
|
+
const tokenIdsToProcess = params.tokenIds || [];
|
|
4266
|
+
if (tokenIdsToProcess.length > 0) {
|
|
4267
|
+
for (const tokenId of tokenIdsToProcess) {
|
|
4268
|
+
const tokenBalance = await this.getTokenWithMetadata({
|
|
4269
|
+
accountAddress: params.accountAddress,
|
|
4270
|
+
contractAddress: params.contractAddress,
|
|
4271
|
+
abi: params.abi,
|
|
4272
|
+
tokenId,
|
|
4273
|
+
chainId: params.chainId
|
|
4274
|
+
});
|
|
4275
|
+
tokens.push(tokenBalance);
|
|
4276
|
+
}
|
|
4277
|
+
}
|
|
4278
|
+
console.log('ERC-1155 User balances:', tokens);
|
|
4279
|
+
// ERC-1155: Cannot enumerate without knowing token IDs
|
|
4280
|
+
// Would need to use events or provide specific token IDs
|
|
4281
|
+
console.warn('ERC-1155 collection retrieval requires specific token IDs or event analysis');
|
|
4282
|
+
return {
|
|
4283
|
+
accountAddress: params.accountAddress,
|
|
4284
|
+
contractAddress: params.contractAddress,
|
|
4285
|
+
totalBalance: 0,
|
|
4286
|
+
tokensRetrieved: 0,
|
|
4287
|
+
tokens: tokens,
|
|
4288
|
+
note: 'ERC-1155 collection retrieval requires specific token IDs. Use getTokenWithMetadata() for individual tokens.'
|
|
4289
|
+
};
|
|
4290
|
+
}
|
|
4291
|
+
// Handle different token standards
|
|
4292
|
+
if (contractAnalysis.isERC721) {
|
|
4293
|
+
// ERC-721: Get user's total balance and enumerate through tokens
|
|
4294
|
+
const userBalance = await this.web3Api.getTokenBalance({
|
|
4295
|
+
accountAddress: params.accountAddress,
|
|
4296
|
+
contractAddress: params.contractAddress,
|
|
4297
|
+
abi: params.abi,
|
|
4298
|
+
tokenId: null, // null for ERC-721 total balance
|
|
4299
|
+
chainId: params.chainId
|
|
4260
4300
|
});
|
|
4261
|
-
|
|
4301
|
+
console.log(`ERC-721 User balance for ${params.accountAddress}:`, userBalance);
|
|
4302
|
+
if (userBalance === 0) {
|
|
4262
4303
|
return {
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4304
|
+
accountAddress: params.accountAddress,
|
|
4305
|
+
contractAddress: params.contractAddress,
|
|
4306
|
+
totalBalance: 0,
|
|
4307
|
+
tokensRetrieved: 0,
|
|
4308
|
+
tokens: []
|
|
4267
4309
|
};
|
|
4268
4310
|
}
|
|
4269
|
-
|
|
4270
|
-
const
|
|
4311
|
+
// Enumerate through user's tokens
|
|
4312
|
+
const maxTokens = params.maxTokens || userBalance;
|
|
4313
|
+
const tokensToRetrieve = Math.min(maxTokens, userBalance);
|
|
4314
|
+
for (let i = 0; i < tokensToRetrieve; i++) {
|
|
4271
4315
|
try {
|
|
4272
4316
|
const tokenId = await this.web3Api.getTokenOfOwnerByIndex({
|
|
4273
|
-
contractAddress:
|
|
4274
|
-
abi:
|
|
4275
|
-
accountAddress:
|
|
4276
|
-
tokenIndex:
|
|
4277
|
-
chainId:
|
|
4317
|
+
contractAddress: params.contractAddress,
|
|
4318
|
+
abi: params.abi,
|
|
4319
|
+
accountAddress: params.accountAddress,
|
|
4320
|
+
tokenIndex: i,
|
|
4321
|
+
chainId: params.chainId
|
|
4278
4322
|
});
|
|
4279
|
-
const
|
|
4280
|
-
|
|
4281
|
-
|
|
4323
|
+
const tokenWithMetadata = await this.getTokenWithMetadata({
|
|
4324
|
+
accountAddress: params.accountAddress,
|
|
4325
|
+
contractAddress: params.contractAddress,
|
|
4326
|
+
abi: params.abi,
|
|
4282
4327
|
tokenId,
|
|
4283
|
-
chainId:
|
|
4328
|
+
chainId: params.chainId
|
|
4284
4329
|
});
|
|
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;
|
|
4330
|
+
if (tokenWithMetadata.hasBalance) {
|
|
4331
|
+
tokens.push(tokenWithMetadata);
|
|
4332
|
+
}
|
|
4298
4333
|
}
|
|
4299
4334
|
catch (error) {
|
|
4300
|
-
console.warn(`
|
|
4301
|
-
|
|
4335
|
+
console.warn(`Error retrieving ERC-721 token at index ${i}:`, error);
|
|
4336
|
+
continue;
|
|
4302
4337
|
}
|
|
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
|
-
};
|
|
4338
|
+
}
|
|
4314
4339
|
}
|
|
4315
|
-
|
|
4316
|
-
|
|
4340
|
+
else {
|
|
4341
|
+
// Unknown standard
|
|
4317
4342
|
return {
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4343
|
+
accountAddress: params.accountAddress,
|
|
4344
|
+
contractAddress: params.contractAddress,
|
|
4345
|
+
totalBalance: 0,
|
|
4346
|
+
tokensRetrieved: 0,
|
|
4347
|
+
tokens: [],
|
|
4348
|
+
note: 'Unsupported token standard for collection retrieval'
|
|
4322
4349
|
};
|
|
4323
4350
|
}
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4351
|
+
// Calculate total balance based on retrieved tokens
|
|
4352
|
+
let totalBalance = 0;
|
|
4353
|
+
if (contractAnalysis.isERC721) {
|
|
4354
|
+
// For ERC-721, total balance is the number of unique tokens owned
|
|
4355
|
+
totalBalance = tokens.length;
|
|
4356
|
+
}
|
|
4357
|
+
else {
|
|
4358
|
+
// For other standards, sum up individual token balances
|
|
4359
|
+
totalBalance = tokens.reduce((sum, token) => sum + token.balance, 0);
|
|
4360
|
+
}
|
|
4361
|
+
return {
|
|
4362
|
+
accountAddress: params.accountAddress,
|
|
4363
|
+
contractAddress: params.contractAddress,
|
|
4364
|
+
totalBalance,
|
|
4365
|
+
tokensRetrieved: tokens.length,
|
|
4366
|
+
tokens
|
|
4367
|
+
};
|
|
4368
|
+
}
|
|
4369
|
+
catch (error) {
|
|
4370
|
+
console.error('Error getting token collection:', error);
|
|
4371
|
+
return {
|
|
4372
|
+
accountAddress: params.accountAddress,
|
|
4373
|
+
contractAddress: params.contractAddress,
|
|
4374
|
+
totalBalance: 0,
|
|
4375
|
+
tokensRetrieved: 0,
|
|
4376
|
+
tokens: [],
|
|
4377
|
+
note: 'Error retrieving collection'
|
|
4378
|
+
};
|
|
4379
|
+
}
|
|
4380
|
+
}
|
|
4381
|
+
async getTokenMetadata(params) {
|
|
4382
|
+
try {
|
|
4383
|
+
const tokenUri = await this.web3Api.getTokenUri({
|
|
4384
|
+
contractAddress: params.contractAddress,
|
|
4385
|
+
abi: params.abi,
|
|
4386
|
+
tokenId: params.tokenId,
|
|
4387
|
+
chainId: params.chainId
|
|
4388
|
+
});
|
|
4389
|
+
let metadata = null;
|
|
4390
|
+
if (tokenUri) {
|
|
4391
|
+
metadata = await this.metadataService.fetchAndProcessMetadata(tokenUri, params.chainId);
|
|
4334
4392
|
}
|
|
4393
|
+
return {
|
|
4394
|
+
tokenId: params.tokenId,
|
|
4395
|
+
tokenUri,
|
|
4396
|
+
metadata
|
|
4397
|
+
};
|
|
4398
|
+
}
|
|
4399
|
+
catch (error) {
|
|
4400
|
+
console.error('Error getting token metadata:', error);
|
|
4401
|
+
return {
|
|
4402
|
+
tokenId: params.tokenId,
|
|
4403
|
+
tokenUri: null,
|
|
4404
|
+
metadata: null
|
|
4405
|
+
};
|
|
4406
|
+
}
|
|
4407
|
+
}
|
|
4408
|
+
}
|
|
4409
|
+
|
|
4410
|
+
/**
|
|
4411
|
+
* MetadataDomainService - Clean IPFS metadata resolution
|
|
4412
|
+
*/
|
|
4413
|
+
class MetadataDomainService {
|
|
4414
|
+
constructor(ipfsApi) {
|
|
4415
|
+
this.ipfsApi = ipfsApi;
|
|
4416
|
+
}
|
|
4417
|
+
async fetchAndProcessMetadata(tokenUri, chainId) {
|
|
4418
|
+
return this.ipfsApi.fetchAndProcessMetadata(tokenUri, chainId);
|
|
4419
|
+
}
|
|
4420
|
+
async resolveIPFSUrl(url, chainId) {
|
|
4421
|
+
return this.ipfsApi.resolveIPFSUrl(url, chainId);
|
|
4422
|
+
}
|
|
4423
|
+
}
|
|
4424
|
+
|
|
4425
|
+
/**
|
|
4426
|
+
* ContractDomainService - Clean contract analysis without external dependencies
|
|
4427
|
+
*/
|
|
4428
|
+
class ContractDomainService {
|
|
4429
|
+
constructor() { }
|
|
4430
|
+
analyzeContract(abi) {
|
|
4431
|
+
const methods = abi.filter(item => item.type === 'function').map(item => item.name);
|
|
4432
|
+
// ERC-721 detection
|
|
4433
|
+
const hasOwnerOf = methods.includes('ownerOf');
|
|
4434
|
+
const hasTokenURI = methods.includes('tokenURI');
|
|
4435
|
+
const hasTransferFrom = methods.includes('transferFrom');
|
|
4436
|
+
const isERC721 = hasOwnerOf && hasTokenURI && hasTransferFrom;
|
|
4437
|
+
// ERC-1155 detection
|
|
4438
|
+
const hasBalanceOfBatch = methods.includes('balanceOfBatch');
|
|
4439
|
+
const hasSafeBatchTransferFrom = methods.includes('safeBatchTransferFrom');
|
|
4440
|
+
const hasURI = methods.includes('uri');
|
|
4441
|
+
const isERC1155 = hasBalanceOfBatch && hasSafeBatchTransferFrom && hasURI;
|
|
4442
|
+
return {
|
|
4443
|
+
hasEnumeration: methods.includes('tokenByIndex') && methods.includes('totalSupply'),
|
|
4444
|
+
hasOwnerOf,
|
|
4445
|
+
hasBalanceOf: methods.includes('balanceOf'),
|
|
4446
|
+
hasTokenURI,
|
|
4447
|
+
hasTransfer: methods.includes('transfer') || methods.includes('transferFrom'),
|
|
4448
|
+
hasApprove: methods.includes('approve'),
|
|
4449
|
+
isERC721,
|
|
4450
|
+
isERC1155
|
|
4335
4451
|
};
|
|
4336
|
-
// ✅ CACHE SET: Store complete collection response
|
|
4337
|
-
this.cache.set(cacheKey, response);
|
|
4338
|
-
return response;
|
|
4339
4452
|
}
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
const
|
|
4345
|
-
return
|
|
4346
|
-
|
|
4347
|
-
|
|
4453
|
+
supportsEnumeration(abi) {
|
|
4454
|
+
return this.analyzeContract(abi).hasEnumeration;
|
|
4455
|
+
}
|
|
4456
|
+
supportsMethod(abi, methodName) {
|
|
4457
|
+
const methods = abi.filter(item => item.type === 'function').map(item => item.name);
|
|
4458
|
+
return methods.includes(methodName);
|
|
4459
|
+
}
|
|
4460
|
+
}
|
|
4461
|
+
|
|
4462
|
+
/**
|
|
4463
|
+
* Web3ApplicationService - Application layer entrance point
|
|
4464
|
+
* Orchestrates domain services and provides clean public interface
|
|
4465
|
+
* Simplified architecture with concrete classes
|
|
4466
|
+
*/
|
|
4467
|
+
class Web3ApplicationService {
|
|
4468
|
+
constructor(web3Api, ipfsApi) {
|
|
4469
|
+
// Type-safe metadata conversion methods for ERC-721/ERC-1155 standards
|
|
4470
|
+
this.metadataMapper = {
|
|
4471
|
+
fromERCStandard: (ercMetadata) => ({
|
|
4472
|
+
name: ercMetadata.name || '',
|
|
4473
|
+
description: ercMetadata.description || '',
|
|
4474
|
+
imageUrl: ercMetadata.image || '',
|
|
4475
|
+
externalUrl: ercMetadata.external_url,
|
|
4476
|
+
animationUrl: ercMetadata.animation_url,
|
|
4477
|
+
animationUrlConverted: undefined, // Will be set by IPFS conversion
|
|
4478
|
+
attributes: ercMetadata.attributes || [],
|
|
4479
|
+
...ercMetadata
|
|
4480
|
+
}),
|
|
4481
|
+
toERCStandard: (metadata) => ({
|
|
4482
|
+
name: metadata.name,
|
|
4483
|
+
description: metadata.description,
|
|
4484
|
+
image: metadata.imageUrl,
|
|
4485
|
+
animation_url: metadata.animationUrl,
|
|
4486
|
+
external_url: metadata.externalUrl,
|
|
4487
|
+
attributes: metadata.attributes,
|
|
4488
|
+
...Object.fromEntries(Object.entries(metadata).filter(([key]) => !['name', 'description', 'imageUrl', 'animationUrl', 'externalUrl', 'attributes', 'animationUrlConverted'].includes(key)))
|
|
4489
|
+
})
|
|
4490
|
+
};
|
|
4491
|
+
// Create domain services with injected infrastructure dependencies
|
|
4492
|
+
this.contractDomainService = new ContractDomainService();
|
|
4493
|
+
this.metadataDomainService = new MetadataDomainService(ipfsApi);
|
|
4494
|
+
this.tokenDomainService = new TokenDomainService(web3Api, this.metadataDomainService, this.contractDomainService);
|
|
4495
|
+
}
|
|
4496
|
+
/**
|
|
4497
|
+
* Get balance and metadata for a specific token
|
|
4498
|
+
*/
|
|
4499
|
+
async getSpecificTokenBalance(request) {
|
|
4500
|
+
if (!request.tokenId) {
|
|
4501
|
+
return this.tokenDomainService.getTokenBalance({
|
|
4502
|
+
accountAddress: request.accountAddress || '',
|
|
4503
|
+
contractAddress: request.contractAddress,
|
|
4504
|
+
abi: request.abi,
|
|
4505
|
+
tokenId: '',
|
|
4506
|
+
chainId: request.chainId
|
|
4507
|
+
});
|
|
4508
|
+
}
|
|
4509
|
+
return this.tokenDomainService.getTokenWithMetadata({
|
|
4510
|
+
accountAddress: request.accountAddress || '',
|
|
4511
|
+
contractAddress: request.contractAddress,
|
|
4512
|
+
abi: request.abi,
|
|
4513
|
+
tokenId: request.tokenId || '',
|
|
4514
|
+
chainId: request.chainId
|
|
4515
|
+
});
|
|
4516
|
+
}
|
|
4517
|
+
/**
|
|
4518
|
+
* Get metadata for a specific token from on-chain
|
|
4519
|
+
*/
|
|
4520
|
+
async getTokenMetadata(request) {
|
|
4521
|
+
const domainResult = await this.tokenDomainService.getTokenMetadata({
|
|
4522
|
+
contractAddress: request.contractAddress,
|
|
4523
|
+
abi: request.abi,
|
|
4524
|
+
tokenId: request.tokenId || '',
|
|
4525
|
+
chainId: request.chainId
|
|
4526
|
+
});
|
|
4527
|
+
return domainResult.metadata;
|
|
4528
|
+
}
|
|
4529
|
+
/**
|
|
4530
|
+
* Retrieve entire collection of tokens with balance and metadata
|
|
4531
|
+
*/
|
|
4532
|
+
async getTokenCollection(request) {
|
|
4533
|
+
return this.tokenDomainService.getTokenCollection({
|
|
4534
|
+
accountAddress: request.accountAddress || '',
|
|
4535
|
+
contractAddress: request.contractAddress,
|
|
4536
|
+
abi: request.abi,
|
|
4537
|
+
chainId: request.chainId,
|
|
4538
|
+
maxTokens: request.maxTokens,
|
|
4539
|
+
tokenIds: request.tokenIds
|
|
4348
4540
|
});
|
|
4349
4541
|
}
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4542
|
+
/**
|
|
4543
|
+
* Resolve IPFS URLs to HTTPS if needed
|
|
4544
|
+
*/
|
|
4545
|
+
async resolveIPFSUrl(url, chainId) {
|
|
4546
|
+
return this.metadataDomainService.resolveIPFSUrl(url, chainId);
|
|
4547
|
+
}
|
|
4548
|
+
/**
|
|
4549
|
+
* Fetch and process metadata from URI with IPFS conversion
|
|
4550
|
+
*/
|
|
4551
|
+
async fetchAndProcessMetadata(tokenUri, chainId) {
|
|
4552
|
+
const domainMetadata = await this.metadataDomainService.fetchAndProcessMetadata(tokenUri, chainId);
|
|
4553
|
+
if (!domainMetadata)
|
|
4353
4554
|
return null;
|
|
4354
|
-
|
|
4555
|
+
// Convert from ERC token standard to our clean interface
|
|
4556
|
+
const cleanMetadata = this.metadataMapper.fromERCStandard(domainMetadata);
|
|
4557
|
+
// Add IPFS conversion if needed
|
|
4558
|
+
if (cleanMetadata.animationUrl?.startsWith('ipfs://')) {
|
|
4559
|
+
return {
|
|
4560
|
+
...cleanMetadata,
|
|
4561
|
+
animationUrlConverted: await this.resolveIPFSUrl(cleanMetadata.animationUrl, chainId)
|
|
4562
|
+
};
|
|
4563
|
+
}
|
|
4564
|
+
return cleanMetadata;
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4567
|
+
|
|
4568
|
+
/**
|
|
4569
|
+
* Web3InfrastructureApi - Infrastructure implementation for blockchain operations
|
|
4570
|
+
* Uses @explorins/web3-ts for Web3 interactions
|
|
4571
|
+
*/
|
|
4572
|
+
class Web3InfrastructureApi {
|
|
4573
|
+
constructor(web3ChainService) {
|
|
4574
|
+
this.web3ChainService = web3ChainService;
|
|
4355
4575
|
}
|
|
4356
|
-
async
|
|
4576
|
+
async getTokenBalance(request) {
|
|
4357
4577
|
try {
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
return await response.json();
|
|
4578
|
+
if (request.tokenId !== null)
|
|
4579
|
+
request.tokenId = request.tokenId.toString();
|
|
4580
|
+
const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
|
|
4581
|
+
const contract = getSmartContractInstance(request.contractAddress, request.abi, web3);
|
|
4582
|
+
return await getAccountTokenBalance(contract, request.accountAddress, request.tokenId);
|
|
4364
4583
|
}
|
|
4365
4584
|
catch (error) {
|
|
4366
|
-
console.
|
|
4367
|
-
return
|
|
4585
|
+
console.error(`Failed to get token balance for ${request.accountAddress} for ${request.contractAddress} and tokenId ${request.tokenId}, return 0 instead:`, error);
|
|
4586
|
+
return 0;
|
|
4368
4587
|
}
|
|
4369
4588
|
}
|
|
4589
|
+
async getTokenUri(request) {
|
|
4590
|
+
try {
|
|
4591
|
+
const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
|
|
4592
|
+
const contract = getSmartContractInstance(request.contractAddress, request.abi, web3);
|
|
4593
|
+
const tokenId = Number(request.tokenId);
|
|
4594
|
+
const tokenUri = await getTokenUri(contract, tokenId);
|
|
4595
|
+
return String(tokenUri);
|
|
4596
|
+
}
|
|
4597
|
+
catch (error) {
|
|
4598
|
+
console.error(`Failed to get token URI for tokenId ${request.tokenId}:`, error);
|
|
4599
|
+
throw error;
|
|
4600
|
+
}
|
|
4601
|
+
}
|
|
4602
|
+
async getTokenOfOwnerByIndex(request) {
|
|
4603
|
+
try {
|
|
4604
|
+
const web3 = await this.web3ChainService.getWeb3ByChainId(request.chainId);
|
|
4605
|
+
const tokenContract = getSmartContractInstance(request.contractAddress, request.abi, web3);
|
|
4606
|
+
const tokenId = await getTokenOfOwnerByIndex(tokenContract, request.accountAddress, request.tokenIndex);
|
|
4607
|
+
return String(tokenId);
|
|
4608
|
+
}
|
|
4609
|
+
catch (error) {
|
|
4610
|
+
console.error(`Failed to get token by index ${request.tokenIndex} for ${request.accountAddress}:`, error);
|
|
4611
|
+
throw error;
|
|
4612
|
+
}
|
|
4613
|
+
}
|
|
4614
|
+
}
|
|
4615
|
+
|
|
4616
|
+
/**
|
|
4617
|
+
* IPFSInfrastructureApi - Infrastructure implementation for IPFS operations
|
|
4618
|
+
* Uses Web3ChainService for IPFS gateway resolution
|
|
4619
|
+
*/
|
|
4620
|
+
class IPFSInfrastructureApi {
|
|
4621
|
+
constructor(web3ChainService) {
|
|
4622
|
+
this.web3ChainService = web3ChainService;
|
|
4623
|
+
this.defaultIpfsGatewayDomain = 'pers.mypinata.cloud';
|
|
4624
|
+
}
|
|
4370
4625
|
async getIpfsGatewayDomain(chainId) {
|
|
4371
4626
|
try {
|
|
4372
4627
|
const chainData = await this.web3ChainService.getChainDataWithCache(chainId);
|
|
@@ -4378,31 +4633,68 @@ class Web3Service {
|
|
|
4378
4633
|
}
|
|
4379
4634
|
}
|
|
4380
4635
|
async resolveIPFSUrl(url, chainId) {
|
|
4381
|
-
if (!url)
|
|
4382
|
-
return '';
|
|
4383
4636
|
if (url.startsWith('ipfs://')) {
|
|
4384
|
-
const
|
|
4385
|
-
return `https://${
|
|
4637
|
+
const gateway = await this.getIpfsGatewayDomain(chainId);
|
|
4638
|
+
return url.replace('ipfs://', `https://${gateway}/ipfs/`);
|
|
4386
4639
|
}
|
|
4387
4640
|
return url;
|
|
4388
4641
|
}
|
|
4642
|
+
async fetchAndProcessMetadata(tokenUri, chainId) {
|
|
4643
|
+
try {
|
|
4644
|
+
const resolvedUri = await this.resolveIPFSUrl(tokenUri, chainId);
|
|
4645
|
+
const response = await fetch(resolvedUri);
|
|
4646
|
+
if (!response.ok) {
|
|
4647
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
4648
|
+
}
|
|
4649
|
+
const metadata = await response.json();
|
|
4650
|
+
// Process and return clean metadata
|
|
4651
|
+
return {
|
|
4652
|
+
name: metadata.name || '',
|
|
4653
|
+
description: metadata.description || '',
|
|
4654
|
+
image: metadata.image ? await this.resolveIPFSUrl(metadata.image, chainId) : '',
|
|
4655
|
+
attributes: metadata.attributes || [],
|
|
4656
|
+
animation_url: metadata.animation_url ? await this.resolveIPFSUrl(metadata.animation_url, chainId) : undefined,
|
|
4657
|
+
external_url: metadata.external_url || undefined
|
|
4658
|
+
};
|
|
4659
|
+
}
|
|
4660
|
+
catch (error) {
|
|
4661
|
+
console.error('Error fetching metadata:', error);
|
|
4662
|
+
return null;
|
|
4663
|
+
}
|
|
4664
|
+
}
|
|
4665
|
+
async fetchFromUrl(url) {
|
|
4666
|
+
try {
|
|
4667
|
+
const response = await fetch(url);
|
|
4668
|
+
if (!response.ok) {
|
|
4669
|
+
throw new Error(`Failed to fetch from ${url}: ${response.statusText}`);
|
|
4670
|
+
}
|
|
4671
|
+
return await response.json();
|
|
4672
|
+
}
|
|
4673
|
+
catch (error) {
|
|
4674
|
+
console.error(`Error fetching from URL ${url}:`, error);
|
|
4675
|
+
throw error;
|
|
4676
|
+
}
|
|
4677
|
+
}
|
|
4389
4678
|
}
|
|
4390
4679
|
|
|
4391
|
-
//import { PublicHttpProviderService } from '../web3-chain/services/public-http-provider.service';
|
|
4392
4680
|
function createWeb3SDK(apiClient) {
|
|
4393
4681
|
// TODO: FIX LATER - TEMPORARY CONSTRUCTION
|
|
4394
4682
|
const web3ProviderService = new Web3ProviderService();
|
|
4395
4683
|
const web3ChainSDK = createWeb3ChainSDK(apiClient, web3ProviderService);
|
|
4396
|
-
|
|
4397
|
-
const
|
|
4684
|
+
// Create Web3ApplicationService - main entry point for all Web3 operations
|
|
4685
|
+
const web3InfrastructureApi = new Web3InfrastructureApi(web3ChainSDK.service);
|
|
4686
|
+
const ipfsInfrastructureApi = new IPFSInfrastructureApi(web3ChainSDK.service);
|
|
4687
|
+
const web3ApplicationService = new Web3ApplicationService(web3InfrastructureApi, ipfsInfrastructureApi);
|
|
4688
|
+
// Clean SDK - all functions route through Web3ApplicationService
|
|
4398
4689
|
return {
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4690
|
+
getTokenBalance: (request) => web3ApplicationService.getSpecificTokenBalance(request),
|
|
4691
|
+
getTokenMetadata: (request) => web3ApplicationService.getTokenMetadata(request),
|
|
4692
|
+
getTokenCollection: (request) => web3ApplicationService.getTokenCollection(request),
|
|
4693
|
+
resolveIPFSUrl: (url, chainId) => web3ApplicationService.resolveIPFSUrl(url, chainId),
|
|
4694
|
+
fetchAndProcessMetadata: (tokenUri, chainId) => web3ApplicationService.fetchAndProcessMetadata(tokenUri, chainId),
|
|
4695
|
+
applicationService: web3ApplicationService
|
|
4404
4696
|
};
|
|
4405
4697
|
}
|
|
4406
4698
|
|
|
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,
|
|
4699
|
+
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
4700
|
//# sourceMappingURL=index.js.map
|