@explorins/pers-sdk 1.0.0-alpha.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/config/domains.js +22 -0
  2. package/explorins-pers-sdk-1.0.0-alpha.1.tgz +0 -0
  3. package/package.json +116 -23
  4. package/rollup.config.js +50 -54
  5. package/scripts/copy-declarations.js +147 -0
  6. package/src/analytics/api/analytics-api.ts +24 -0
  7. package/src/analytics/index.ts +52 -0
  8. package/src/analytics/models/index.ts +74 -0
  9. package/src/analytics/services/analytics-service.ts +28 -0
  10. package/src/auth-admin/api/auth-admin-api.ts +42 -0
  11. package/src/auth-admin/index.ts +47 -0
  12. package/src/auth-admin/services/auth-admin-service.ts +36 -0
  13. package/src/business/api/business-api.ts +181 -19
  14. package/src/business/index.ts +4 -3
  15. package/src/business/models/index.ts +4 -4
  16. package/src/business/services/business-service.ts +1 -1
  17. package/src/campaign/api/campaign-api.ts +376 -0
  18. package/src/campaign/index.ts +67 -0
  19. package/src/campaign/services/campaign-service.ts +164 -0
  20. package/src/core/abstractions/http-client.ts +1 -0
  21. package/src/core/auth/auth-provider.interface.ts +2 -2
  22. package/src/core/auth/create-auth-provider.ts +6 -6
  23. package/src/core/index.ts +33 -0
  24. package/src/core/pers-api-client.ts +211 -19
  25. package/src/core/pers-config.ts +34 -7
  26. package/src/core/utils/jwt.function.ts +24 -0
  27. package/src/donation/api/donation-api.ts +24 -0
  28. package/src/donation/index.ts +47 -0
  29. package/src/donation/models/index.ts +11 -0
  30. package/src/donation/services/donation-service.ts +25 -0
  31. package/src/index.ts +40 -1
  32. package/src/payment/api/payment-api.ts +185 -0
  33. package/src/payment/index.ts +64 -0
  34. package/src/payment/models/index.ts +29 -0
  35. package/src/payment/services/payment-service.ts +70 -0
  36. package/src/redemption/api/redemption-api.ts +241 -0
  37. package/src/redemption/index.ts +60 -0
  38. package/src/redemption/models/index.ts +17 -0
  39. package/src/redemption/services/redemption-service.ts +103 -0
  40. package/src/shared/interfaces/pers-shared-lib.interfaces.ts +99 -0
  41. package/src/tenant/api/tenant-api.ts +92 -0
  42. package/src/tenant/index.ts +61 -0
  43. package/src/tenant/models/index.ts +20 -0
  44. package/src/tenant/services/tenant-service.ts +78 -0
  45. package/src/token/api/token-api.ts +129 -0
  46. package/src/token/base/base-token-service.ts +167 -0
  47. package/src/token/index.ts +38 -0
  48. package/src/token/models/index.ts +30 -0
  49. package/src/token/services/token-service.ts +125 -0
  50. package/src/token/token-sdk.ts +231 -0
  51. package/src/transaction/api/transaction-api.ts +296 -0
  52. package/src/transaction/index.ts +65 -0
  53. package/src/transaction/models/index.ts +60 -0
  54. package/src/transaction/services/transaction-service.ts +104 -0
  55. package/src/user/api/user-api.ts +98 -0
  56. package/src/user/index.ts +62 -0
  57. package/src/user/models/index.ts +10 -0
  58. package/src/user/services/user-service.ts +75 -0
  59. package/src/user-status/api/user-status-api.ts +78 -0
  60. package/src/user-status/index.ts +55 -0
  61. package/src/user-status/models/index.ts +11 -0
  62. package/src/user-status/services/user-status-service.ts +51 -0
  63. package/src/web3/api/web3-api.ts +68 -0
  64. package/src/web3/index.ts +38 -0
  65. package/src/web3/models/index.ts +150 -0
  66. package/src/web3/services/web3-service.ts +338 -0
  67. package/src/web3-chain/api/web3-chain-api.ts +42 -0
  68. package/src/web3-chain/index.ts +27 -0
  69. package/src/web3-chain/models/index.ts +45 -0
  70. package/src/web3-chain/services/getWeb3FCD.service.ts +47 -0
  71. package/src/web3-chain/services/provider.service.ts +123 -0
  72. package/src/web3-chain/services/public-http-provider.service.ts +26 -0
  73. package/src/web3-chain/services/web3-chain-service.ts +131 -0
  74. package/src/business/business/tsconfig.json +0 -18
  75. package/src/core/abstractions/core-interfaces.ts +0 -56
  76. package/src/core/core.ts +0 -30
  77. package/src/core.ts +0 -30
@@ -0,0 +1,338 @@
1
+ import { Web3ChainService } from '../../web3-chain';
2
+ import { Web3Api } from '../api/web3-api';
3
+ import {
4
+ ERC20BalanceRequest,
5
+ ERC1155CollectionRequest,
6
+ ERC721CollectionRequest,
7
+ ERC721CollectionResponse,
8
+ NFTItem,
9
+ Web3BalanceResponse,
10
+ Web3TokenListResponse,
11
+ Web3TokenResult,
12
+ SimpleCache
13
+ } from '../models';
14
+
15
+ export class Web3Service {
16
+ //temporary fix, remove when the backend supports custom gateways
17
+ private readonly defaultIpfsGatewayDomain = 'pers.mypinata.cloud';
18
+
19
+ // ✅ CACHE: Simple 10-second cache instance
20
+ private cache = new SimpleCache();
21
+ private cleanupInterval: NodeJS.Timeout | null = null;
22
+
23
+ constructor(
24
+ private web3Api: Web3Api,
25
+ private web3ChainService: Web3ChainService
26
+ ) {
27
+ this.cleanupInterval = setInterval(() => {
28
+ this.cache.cleanup();
29
+ }, 30 * 1000);
30
+ }
31
+
32
+ destroy(): void {
33
+ if (this.cleanupInterval) {
34
+ clearInterval(this.cleanupInterval);
35
+ this.cleanupInterval = null;
36
+ }
37
+ this.cache.clear();
38
+ }
39
+
40
+ async getERC20Balance(request: ERC20BalanceRequest): Promise<Web3BalanceResponse> {
41
+
42
+ const cacheKey = `erc20_balance_${request.accountAddress}_${request.token.contractAddress}_${request.token.chainId}`;
43
+
44
+ // ✅ CACHE CHECK: Try to get from cache first
45
+ const cached = this.cache.get<Web3BalanceResponse>(cacheKey);
46
+ if (cached) {
47
+ console.debug(`💾 [Web3Service] Using cached ERC20 balance for ${request.token.symbol}`);
48
+ return cached;
49
+ }
50
+
51
+ console.debug(`🔄 [Web3Service] Fetching fresh ERC20 balance for ${request.token.symbol}`);
52
+
53
+ const rawBalance = await this.web3Api.getTokenBalance({
54
+ accountAddress: request.accountAddress,
55
+ contractAddress: request.token.contractAddress,
56
+ abi: request.token.abi,
57
+ tokenId: null, // Always null for ERC20
58
+ chainId: request.token.chainId
59
+ });
60
+
61
+ const decimals = request.token.decimals ?? 18;
62
+ const symbol = request.token.symbol ?? 'UNKNOWN';
63
+
64
+ const response: Web3BalanceResponse = {
65
+ rawBalance,
66
+ formattedBalance: this.formatBalance(rawBalance, decimals),
67
+ decimals,
68
+ symbol,
69
+ hasBalance: rawBalance > 0
70
+ };
71
+
72
+ // ✅ CACHE SET: Store result in cache
73
+ this.cache.set(cacheKey, response);
74
+
75
+ return response;
76
+ }
77
+
78
+ async getERC1155Collection(request: ERC1155CollectionRequest): Promise<Web3TokenListResponse> {
79
+
80
+ // ✅ CACHE KEY: Create unique cache key for collection request
81
+ const contractAddresses = request.tokens.map(t => t.contractAddress).sort().join(',');
82
+ const cacheKey = `erc1155_collection_${request.accountAddress}_${contractAddresses}`;
83
+
84
+ // ✅ CACHE CHECK: Try to get from cache first
85
+ const cached = this.cache.get<Web3TokenListResponse>(cacheKey);
86
+ if (cached) {
87
+ console.debug(`💾 [Web3Service] Using cached ERC1155 collection for ${request.accountAddress}`);
88
+ return cached;
89
+ }
90
+
91
+ console.debug(`🔄 [Web3Service] Fetching fresh ERC1155 collection for ${request.accountAddress}`);
92
+
93
+ const tokenResults = await Promise.all(
94
+ request.tokens.map(async (token) => {
95
+ // ✅ FIXED: Handle null metadata properly
96
+ const tokenIds: string[] = token.metadata?.map(m =>
97
+ m.tokenMetadataIncrementalId?.toString()
98
+ ).filter((id): id is string => id !== undefined) ?? [];
99
+
100
+ // Check balance for each known tokenId
101
+ const balanceResults = await Promise.allSettled(
102
+ tokenIds.map(async (tokenId) => {
103
+ try {
104
+ const rawBalance = await this.web3Api.getTokenBalance({
105
+ accountAddress: request.accountAddress,
106
+ contractAddress: token.contractAddress,
107
+ abi: token.abi,
108
+ tokenId,
109
+ chainId: token.chainId
110
+ });
111
+
112
+ const decimals = token.decimals ?? 0; // ERC1155 usually no decimals
113
+
114
+ return {
115
+ tokenId,
116
+ balance: rawBalance,
117
+ formattedBalance: this.formatBalance(rawBalance, decimals),
118
+ hasBalance: rawBalance > 0,
119
+ // ✅ FIXED: Convert null to undefined for findMetadata
120
+ metadata: this.findMetadata(token.metadata ?? undefined, tokenId)
121
+ };
122
+ } catch (error) {
123
+ console.warn(`Failed to get balance for token ${token.contractAddress}:${tokenId}`, error);
124
+ return null; // Skip failed tokens
125
+ }
126
+ })
127
+ );
128
+
129
+ // Filter successful results with balance > 0
130
+ const successfulResults: Web3TokenResult[] = [];
131
+ for (const result of balanceResults) {
132
+ if (result.status === 'fulfilled' && result.value !== null && result.value.hasBalance) {
133
+ successfulResults.push(result.value);
134
+ }
135
+ }
136
+
137
+ return {
138
+ token,
139
+ results: successfulResults
140
+ };
141
+ })
142
+ );
143
+
144
+ const response: Web3TokenListResponse = {
145
+ accountAddress: request.accountAddress,
146
+ tokens: tokenResults.filter(t => t.results.length > 0)
147
+ };
148
+
149
+ // ✅ CACHE SET: Store complete collection result
150
+ this.cache.set(cacheKey, response);
151
+
152
+ return response;
153
+ }
154
+
155
+ async getERC721Collection(request: ERC721CollectionRequest): Promise<ERC721CollectionResponse> {
156
+
157
+ // ✅ CACHE KEY: Create unique cache key for NFT collection
158
+ const contractAddresses = request.nftContracts.map(t => t.contractAddress).sort().join(',');
159
+ const maxNFTs = request.maxNFTsPerContract || 50;
160
+ const cacheKey = `erc721_collection_${request.accountAddress}_${contractAddresses}_${maxNFTs}`;
161
+
162
+ // ✅ CACHE CHECK: Try to get from cache first
163
+ const cached = this.cache.get<ERC721CollectionResponse>(cacheKey);
164
+ if (cached) {
165
+ console.debug(`💾 [Web3Service] Using cached ERC721 collection for ${request.accountAddress}`);
166
+ return cached;
167
+ }
168
+
169
+ console.debug(`🔄 [Web3Service] Fetching fresh ERC721 collection for ${request.accountAddress}`);
170
+
171
+ const startTime = Date.now();
172
+
173
+ const contractResults = await Promise.all(
174
+ request.nftContracts.map(async (token) => {
175
+ try {
176
+ const totalBalance = await this.web3Api.getTokenBalance({
177
+ accountAddress: request.accountAddress,
178
+ contractAddress: token.contractAddress,
179
+ abi: token.abi,
180
+ tokenId: null,
181
+ chainId: token.chainId
182
+ });
183
+
184
+ if (totalBalance === 0) {
185
+ return {
186
+ token,
187
+ totalNFTs: 0,
188
+ nfts: [],
189
+ hasMore: false
190
+ };
191
+ }
192
+
193
+ const nftsToLoad = Math.min(totalBalance, maxNFTs);
194
+
195
+ const nftResults = await Promise.allSettled(
196
+ Array.from({ length: nftsToLoad }, async (_, index): Promise<NFTItem | null> => {
197
+ try {
198
+ const tokenId = await this.web3Api.getTokenOfOwnerByIndex({
199
+ contractAddress: token.contractAddress,
200
+ abi: token.abi,
201
+ accountAddress: request.accountAddress,
202
+ tokenIndex: index,
203
+ chainId: token.chainId
204
+ });
205
+
206
+ const tokenUri = await this.web3Api.getTokenUri({
207
+ contractAddress: token.contractAddress,
208
+ abi: token.abi,
209
+ tokenId,
210
+ chainId: token.chainId
211
+ });
212
+
213
+ const metadata = await this.fetchMetadata(tokenUri, token.chainId);
214
+
215
+ const nftItem: NFTItem = {
216
+ tokenId,
217
+ name: metadata?.name || `Token #${tokenId}`,
218
+ description: metadata?.description || '',
219
+ imageUrl: await this.resolveIPFSUrl(metadata?.image || '', token.chainId),
220
+ rawBalance: 1,
221
+ formattedBalance: '1',
222
+ hasBalance: true,
223
+ metadata,
224
+ tokenIndex: index
225
+ };
226
+
227
+ return nftItem;
228
+
229
+ } catch (error) {
230
+ console.warn(`Failed to load NFT at index ${index} for ${token.symbol}:`, error);
231
+ return null;
232
+ }
233
+ })
234
+ );
235
+
236
+ // ✅ FIXED: Usar tipo específico NFTItem
237
+ const successfulNFTs = nftResults
238
+ .filter((result): result is PromiseFulfilledResult<NFTItem | null> =>
239
+ result.status === 'fulfilled' && result.value !== null
240
+ )
241
+ .map(result => result.value as NFTItem);
242
+
243
+ return {
244
+ token,
245
+ totalNFTs: totalBalance,
246
+ nfts: successfulNFTs,
247
+ hasMore: totalBalance > maxNFTs
248
+ };
249
+
250
+ } catch (error) {
251
+ console.error(`Failed to load NFT collection for ${token.symbol}:`, error);
252
+ return {
253
+ token,
254
+ totalNFTs: 0,
255
+ nfts: [],
256
+ hasMore: false
257
+ };
258
+ }
259
+ })
260
+ );
261
+
262
+ const totalNFTs = contractResults.reduce((sum, contract) => sum + contract.nfts.length, 0);
263
+ const loadingTime = Date.now() - startTime;
264
+
265
+ const response: ERC721CollectionResponse = {
266
+ accountAddress: request.accountAddress,
267
+ contracts: contractResults,
268
+ summary: {
269
+ totalContracts: request.nftContracts.length,
270
+ totalNFTs,
271
+ loadingTime
272
+ }
273
+ };
274
+
275
+ // ✅ CACHE SET: Store complete collection response
276
+ this.cache.set(cacheKey, response);
277
+
278
+ return response;
279
+ }
280
+
281
+ // ==========================================
282
+ // HELPER METHODS
283
+ // ==========================================
284
+
285
+ private formatBalance(rawBalance: number, decimals: number): string {
286
+ const balance = rawBalance / Math.pow(10, decimals);
287
+
288
+ return balance.toLocaleString('en-US', {
289
+ minimumFractionDigits: 0,
290
+ maximumFractionDigits: decimals > 0 ? 2 : 0
291
+ });
292
+ }
293
+
294
+ // ✅ FIXED: Update method signature to handle null properly
295
+ private findMetadata(metadata: any[] | undefined, tokenId: string | null): any | null {
296
+ if (!metadata || tokenId === null) return null;
297
+ return metadata.find(m =>
298
+ m.tokenMetadataIncrementalId?.toString() === tokenId
299
+ ) || null;
300
+ }
301
+
302
+ private async fetchMetadata(uri: string, chainId: number): Promise<any> {
303
+ try {
304
+ const httpUrl = await this.resolveIPFSUrl(uri, chainId);
305
+ const response = await fetch(httpUrl);
306
+
307
+ if (!response.ok) {
308
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
309
+ }
310
+
311
+ return await response.json();
312
+ } catch (error) {
313
+ console.warn('Failed to fetch NFT metadata:', error);
314
+ return null;
315
+ }
316
+ }
317
+
318
+ private async getIpfsGatewayDomain(chainId: number): Promise<string> {
319
+ try {
320
+ const chainData = await this.web3ChainService.getChainDataWithCache(chainId);
321
+ return chainData.ipfsGatewayDomain || this.defaultIpfsGatewayDomain;
322
+ } catch (error) {
323
+ console.warn(`Failed to get chain data for chainId ${chainId}, using default IPFS gateway:`, error);
324
+ return this.defaultIpfsGatewayDomain;
325
+ }
326
+ }
327
+
328
+ private async resolveIPFSUrl(url: string, chainId: number): Promise<string> {
329
+ if (!url) return '';
330
+
331
+ if (url.startsWith('ipfs://')) {
332
+ const gatewayDomain = await this.getIpfsGatewayDomain(chainId);
333
+ return `https://${gatewayDomain}/ipfs/${url.slice(7)}`;
334
+ }
335
+
336
+ return url;
337
+ }
338
+ }
@@ -0,0 +1,42 @@
1
+ import { PersApiClient } from '../../core/pers-api-client';
2
+ import { ChainData } from '../models';
3
+
4
+ /**
5
+ * Platform-Agnostic Web3 Chain API Client
6
+ *
7
+ * Handles blockchain chain operations using the PERS backend.
8
+ * Uses @explorins/web3-ts types for perfect framework compatibility.
9
+ */
10
+ export class Web3ChainApi {
11
+ constructor(private apiClient: PersApiClient) {}
12
+
13
+ private basePath = '/chains';
14
+
15
+ // ==========================================
16
+ // PUBLIC OPERATIONS
17
+ // ==========================================
18
+
19
+ /**
20
+ * PUBLIC: Get chain data by chain ID
21
+ * ✅ Returns ChainData exactly as framework expects from @explorins/web3-ts
22
+ */
23
+ async getChainData(chainId: number): Promise<ChainData> {
24
+ try {
25
+
26
+ console.log('🔍 [Web3ChainApi] Fetching chain data for chainId:', chainId);
27
+ const response = await this.apiClient.get<ChainData>(`${this.basePath}/${chainId}`);
28
+
29
+ if (!response) {
30
+ throw new Error(`No chain data received for chainId: ${chainId}`);
31
+ }
32
+
33
+ return response;
34
+ } catch (error) {
35
+ console.error('❌ [Web3ChainApi] Failed to get chain data:', {
36
+ chainId,
37
+ error: error instanceof Error ? error.message : String(error)
38
+ });
39
+ throw error;
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,27 @@
1
+ import { PersApiClient } from '../core/pers-api-client';
2
+ import { Web3ChainApi } from './api/web3-chain-api';
3
+ import { Web3ProviderService } from './services/provider.service';
4
+
5
+ import { Web3ChainService } from './services/web3-chain-service';
6
+
7
+ export function createWeb3ChainSDK(apiClient: PersApiClient, providerService: Web3ProviderService) {
8
+ const web3ChainApi = new Web3ChainApi(apiClient);
9
+ const web3ChainService = new Web3ChainService(web3ChainApi, providerService); // ✅ DIRECT INJECTION
10
+
11
+ return {
12
+ // ✅ REPLICA: Same methods as framework
13
+ getChainDataById: (chainId: number) => web3ChainService.getChainDataById(chainId),
14
+ getWeb3ByChainId: (chainId: number) => web3ChainService.getWeb3ByChainId(chainId),
15
+
16
+ api: web3ChainApi,
17
+ service: web3ChainService
18
+ };
19
+ }
20
+
21
+ // ✅ EXPORT: All models and service
22
+ export { Web3ChainApi } from './api/web3-chain-api';
23
+ export { Web3ChainService } from './services/web3-chain-service';
24
+ export { Web3ProviderService } from './services/provider.service';
25
+ export * from './models';
26
+ export type { ChainData } from './models';
27
+ export * from '../shared/interfaces/pers-shared-lib.interfaces';
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Web3 Chain Domain Models
3
+ *
4
+ * Minimal interface definitions matching framework usage exactly.
5
+ * Local ChainData interface to avoid external dependency issues.
6
+ */
7
+
8
+ import type { Web3 } from "web3";
9
+
10
+ // ✅ FIXED: Local ChainData interface instead of problematic external import
11
+ export interface ChainData {
12
+ name: string;
13
+ shortName?: string;
14
+ chain?: string;
15
+ network?: string;
16
+ chainId?: number;
17
+ networkId?: number | null;
18
+ rpcUrl: string;
19
+ explorerUrl?: string;
20
+ authHeader?: string;
21
+ nativeCurrency?: any;
22
+ chainType: ChainType;
23
+ ipfsGatewayDomain?: string;
24
+ }
25
+
26
+ export type ChainType = typeof ChainTypes[keyof typeof ChainTypes];
27
+
28
+ export const ChainTypes = {
29
+ PUBLIC: 'PUBLIC',
30
+ PRIVATE: 'PRIVATE'
31
+ } as const;
32
+
33
+ export interface CachedWeb3Instance {
34
+ instance: Web3;
35
+ createdAt: number;
36
+ chainId: number;
37
+ }
38
+
39
+ export interface CachedChainInstance {
40
+ web3Instance: Web3;
41
+ chainData: ChainData;
42
+ createdAt: number;
43
+ chainId: number;
44
+ }
45
+
@@ -0,0 +1,47 @@
1
+
2
+ //IMPORTANT//
3
+ //This function is temporary so we install ethers just to make it work, once we delete this function we must uninstall Ethers
4
+
5
+ import { ChainData } from "@explorins/web3-ts";
6
+ import { FetchRequest, JsonRpcProvider } from "ethers";
7
+
8
+ export const getWeb3ProviderFromChainData = (
9
+ chainData: ChainData,
10
+ timeout = 15000,
11
+ customUserAgentName = '',
12
+ tokenRefresher?: () => Promise<string>
13
+ ) => {
14
+
15
+ // Fixed ethers provider setup for authenticated requests
16
+ let ethersProvider: JsonRpcProvider;
17
+
18
+ if (chainData.authHeader) {
19
+ // For authenticated requests, create a custom FetchRequest
20
+ const fetchRequest = new FetchRequest(chainData.rpcUrl);
21
+ fetchRequest.timeout = timeout;
22
+ fetchRequest.setHeader('Authorization', chainData.authHeader);
23
+ fetchRequest.setHeader('Content-Type', 'application/json');
24
+
25
+ if (customUserAgentName) {
26
+ fetchRequest.setHeader('User-Agent', customUserAgentName);
27
+ }
28
+
29
+ // Create provider with the configured FetchRequest
30
+ ethersProvider = new JsonRpcProvider(fetchRequest, undefined, {
31
+ staticNetwork: false,
32
+ polling: false, // Disable polling for better Lambda performance
33
+ });
34
+ } else {
35
+ // For public chains, use simple URL-based provider
36
+ ethersProvider = new JsonRpcProvider(chainData.rpcUrl, undefined, {
37
+ staticNetwork: false,
38
+ polling: false,
39
+ });
40
+ }
41
+
42
+ return {
43
+ web3Provider: null,
44
+ ethersProvider: ethersProvider,
45
+ isAuthenticated: !!chainData.authHeader,
46
+ };
47
+ };
@@ -0,0 +1,123 @@
1
+ import Web3 from "web3";
2
+ import { ChainData, ChainType, ChainTypes } from "@explorins/web3-ts";
3
+ import { PublicHttpProviderService } from "./public-http-provider.service";
4
+ import { getWeb3ProviderFromChainData } from "./getWeb3FCD.service";
5
+
6
+
7
+ export class Web3ProviderService {
8
+
9
+ private _web3: Web3 | null = null;
10
+ private _currentChainId: number | null = null;
11
+
12
+ constructor(
13
+ private readonly publicHttpProviderService: PublicHttpProviderService,
14
+ ) {
15
+ }
16
+
17
+ public async getWeb3(chainId: number, chainType: ChainType, privateChainData: ChainData | null = null) {
18
+ if (!this._web3 || this._currentChainId !== chainId) {
19
+
20
+ if(!chainId) throw new Error('ChainId not found')
21
+
22
+ try {
23
+ this._currentChainId = chainId;
24
+ const provider = await this.getWeb3ByChainId(chainId, chainType, privateChainData);
25
+ this._web3 = this.convertToWeb3(provider);
26
+ } catch (error) {
27
+ console.error('Error getting web3 connection from chain id ' + chainId , error)
28
+ throw new Error('Error getting web3 connection from chain id ' + chainId)
29
+ }
30
+ }
31
+ return this._web3 as Web3;
32
+ }
33
+
34
+ // Keep return type as 'any' to avoid TypeScript errors while still being adapted later
35
+ private getWeb3ByChainId(chainId: number, chainType: ChainType, privateChainData: ChainData | null = null): any {
36
+ // Rest of the method remains the same
37
+ if(chainType === ChainTypes.PRIVATE && privateChainData) {
38
+ //const privateProvider = this.privateChainProviderService.getProviderFromChainData(privateChainData)
39
+ const privateProvider = getWeb3ProviderFromChainData(privateChainData);
40
+
41
+ if(!privateProvider || privateProvider instanceof Error) throw new Error('Error getting web3 provider');
42
+
43
+
44
+ return privateProvider;
45
+
46
+ } else {
47
+
48
+ const publicProvider = this.publicHttpProviderService.getProvider(chainId)
49
+ if(!publicProvider || publicProvider instanceof Error) throw new Error('Error getting web3 provider');
50
+
51
+ return publicProvider;
52
+ }
53
+ }
54
+
55
+ private convertToWeb3(provider: unknown): Web3 {
56
+ if (provider instanceof Web3) {
57
+ return provider as Web3;
58
+ }
59
+
60
+ if (provider && typeof provider === 'object' && 'web3Provider' in provider) {
61
+ const providerObj = provider as {
62
+ web3Provider?: unknown;
63
+ ethersProvider?: any;
64
+ isAuthenticated?: boolean;
65
+ };
66
+
67
+ // If we want to user the web3Provider directly:
68
+ /*if (providerObj.web3Provider) {
69
+ return new Web3(providerObj.web3Provider as never);
70
+ }*/
71
+
72
+ if (providerObj.ethersProvider) {
73
+
74
+ const url = this.extractUrlFromEthersProvider(providerObj.ethersProvider);
75
+ const headers = this.extractHeadersFromEthersProvider(providerObj.ethersProvider);
76
+
77
+ const web3 = new Web3(url);
78
+ const currentProvider = web3.currentProvider as unknown as Record<string, unknown>;
79
+
80
+ if (currentProvider) {
81
+ currentProvider['url'] = url;
82
+
83
+ if (headers && Object.keys(headers).length > 0) {
84
+ currentProvider['request'] = async (payload: Record<string, unknown>): Promise<Record<string, unknown>> => {
85
+ const response = await fetch(url, {
86
+ method: 'POST',
87
+ headers: {
88
+ 'Content-Type': 'application/json',
89
+ ...headers
90
+ },
91
+ body: JSON.stringify(payload)
92
+ });
93
+
94
+ if (!response.ok) {
95
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
96
+ }
97
+
98
+ return await response.json() as Record<string, unknown>;
99
+ };
100
+ }
101
+ }
102
+
103
+ return web3;
104
+ }
105
+ }
106
+
107
+ return new Web3(provider as never);
108
+ }
109
+
110
+
111
+ private extractUrlFromEthersProvider(ethersProvider: any): string {
112
+ return ethersProvider.connection?.url ||
113
+ ethersProvider._getConnection?.()?.url ||
114
+ ethersProvider.url ||
115
+ '';
116
+ }
117
+
118
+ private extractHeadersFromEthersProvider(ethersProvider: any): Record<string, string> {
119
+ return ethersProvider.connection?.headers ||
120
+ ethersProvider._getConnection?.()?.headers ||
121
+ {};
122
+ }
123
+ }
@@ -0,0 +1,26 @@
1
+ import type { PublicWeb3ProviderData } from "@explorins/web3/types";
2
+ import type Web3 from "web3";
3
+
4
+ import { adaptToWeb3, getPublicWeb3ConnectionFromChainId } from "@explorins/web3-ts";
5
+
6
+ export class PublicHttpProviderService {
7
+ private $providerData: PublicWeb3ProviderData | null;
8
+
9
+ constructor(providerData: PublicWeb3ProviderData | null = null) {
10
+ this.$providerData = providerData;
11
+ }
12
+
13
+ public getProvider(chainId: number): Web3 {
14
+ const providerApiKey = this.$providerData ? this.$providerData?.apiKey || null : null;
15
+ if (!providerApiKey) throw new Error('Provider API key not found');
16
+
17
+ try {
18
+ // Use the adapter function instead of unsafe type casting
19
+ const provider = getPublicWeb3ConnectionFromChainId(chainId, 'infuraHttp', providerApiKey);
20
+ return adaptToWeb3(provider);
21
+ } catch (error) {
22
+ console.error('Error getting web3 connection from chain id ' + chainId, error);
23
+ throw new Error('Error getting web3 connection from chain id ' + chainId);
24
+ }
25
+ }
26
+ }