From f44071fa7659772dea2040e7cf22f173c0f75342 Mon Sep 17 00:00:00 2001 From: Dmytro Vynnyk Date: Thu, 23 Oct 2025 23:29:00 +0200 Subject: [PATCH 1/5] Change `balance` type from `number` to `string` in token and account response models to ensure consistent handling of large values. --- src/data/repositories/accountInfo/types.ts | 2 +- src/data/repositories/tokens/index.ts | 2 +- src/data/repositories/tokens/types.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/data/repositories/accountInfo/types.ts b/src/data/repositories/accountInfo/types.ts index 5ee4539..26dbd12 100644 --- a/src/data/repositories/accountInfo/types.ts +++ b/src/data/repositories/accountInfo/types.ts @@ -2,7 +2,7 @@ import { Maybe } from '../../../typings'; export interface IGetAccountsInfoResponse { account_hash: string; - balance: number; + balance: string; main_purse_uref: string; public_key: string; account_info?: ICloudAccountInfoResult; diff --git a/src/data/repositories/tokens/index.ts b/src/data/repositories/tokens/index.ts index c3a1221..7eb294c 100644 --- a/src/data/repositories/tokens/index.ts +++ b/src/data/repositories/tokens/index.ts @@ -66,7 +66,7 @@ export class TokensRepository implements ITokensRepository { return new CsprBalanceDto(resp?.data); } catch (e) { if (e instanceof HttpClientNotFoundError) { - return new CsprBalanceDto({ balance: 0 }); + return new CsprBalanceDto({ balance: '0' }); } else { this._processError(e, 'getCsprBalance'); } diff --git a/src/data/repositories/tokens/types.ts b/src/data/repositories/tokens/types.ts index 462de13..4848356 100644 --- a/src/data/repositories/tokens/types.ts +++ b/src/data/repositories/tokens/types.ts @@ -2,7 +2,7 @@ import { DataResponse, Network } from '../../../domain'; import { Maybe } from '../../../typings'; export interface IGetCsprBalanceResponse { - balance: number; + balance: string; delegated_balance?: number; undelegating_balance?: number; From 1737d5f0d4549ba9d98e1963dbd61b66f1b7888e Mon Sep 17 00:00:00 2001 From: Dmytro Vynnyk Date: Fri, 24 Oct 2025 00:21:54 +0200 Subject: [PATCH 2/5] Refactor repositories to utilize environment-based and network-based Casper Wallet API URLs; update setup logic for improved configurability and maintainability. --- src/data/repositories/accountInfo/index.ts | 12 +++-- src/data/repositories/appEvents/index.ts | 11 ++-- .../repositories/contractPackage/index.ts | 9 ++-- src/data/repositories/deploys/index.ts | 11 ++-- src/data/repositories/nfts/index.ts | 9 ++-- src/data/repositories/tokens/index.ts | 13 +++-- .../repositories/txSignatureRequest/index.ts | 20 +++++--- src/data/repositories/validators/index.ts | 13 +++-- src/domain/constants/casperNetwork.ts | 5 +- src/domain/tx-signature-request/repository.ts | 2 + src/setup.ts | 50 +++++++++++++++---- 11 files changed, 107 insertions(+), 48 deletions(-) diff --git a/src/data/repositories/accountInfo/index.ts b/src/data/repositories/accountInfo/index.ts index 2050206..9d3f467 100644 --- a/src/data/repositories/accountInfo/index.ts +++ b/src/data/repositories/accountInfo/index.ts @@ -1,7 +1,6 @@ import { LRUCache } from 'lru-cache'; import { CSPR_API_PROXY_HEADERS, - CasperWalletApiUrl, isAccountInfoError, AccountInfoError, IAccountInfoRepository, @@ -23,7 +22,10 @@ import { IGetCsprBalanceResponse } from '../tokens'; export * from './types'; export class AccountInfoRepository implements IAccountInfoRepository { - constructor(private _httpProvider: IHttpDataProvider) {} + constructor( + private _httpProvider: IHttpDataProvider, + private _casperWalletApiUrl: Record, + ) {} private _accountsInfoMapCache = new LRUCache({ max: 100, @@ -45,7 +47,7 @@ export class AccountInfoRepository implements IAccountInfoRepository { ); const resp = await this._httpProvider.post>({ - url: `${CasperWalletApiUrl[network]}/accounts?includes=account_info,centralized_account_info,cspr_name`, + url: `${this._casperWalletApiUrl[network]}/accounts?includes=account_info,centralized_account_info,cspr_name`, data: { account_hashes: accountsHashesForFetch, }, @@ -88,7 +90,7 @@ export class AccountInfoRepository implements IAccountInfoRepository { }: IGetAccountsBalancesParams): Promise> { try { const resp = await this._httpProvider.post>({ - url: `${CasperWalletApiUrl[network]}/accounts${withDelegationBalances ? '?includes=delegated_balance,undelegating_balance' : ''}`, + url: `${this._casperWalletApiUrl[network]}/accounts${withDelegationBalances ? '?includes=delegated_balance,undelegating_balance' : ''}`, data: { account_hashes: accountHashes, }, @@ -119,7 +121,7 @@ export class AccountInfoRepository implements IAccountInfoRepository { ): Promise> { try { const resp = await this._httpProvider.get>({ - url: `${CasperWalletApiUrl[network]}/cspr-name-resolutions/${csprName}`, + url: `${this._casperWalletApiUrl[network]}/cspr-name-resolutions/${csprName}`, params: { includes: 'resolved_public_key,account_info,centralized_account_info', }, diff --git a/src/data/repositories/appEvents/index.ts b/src/data/repositories/appEvents/index.ts index 2883959..fbfd30a 100644 --- a/src/data/repositories/appEvents/index.ts +++ b/src/data/repositories/appEvents/index.ts @@ -1,7 +1,6 @@ import { AppEventsError, AppEventsErrorType, - CasperWalletApiEndpoints, CSPR_API_PROXY_HEADERS, DataResponse, IAppEventsRepository, @@ -17,11 +16,15 @@ import { IMarketingEventApiResponse, IReleaseEventApiResponse } from './types'; import { AppMarketingEventDto, AppReleaseEventDto } from '../../dto'; import { Maybe } from '../../../typings'; import { isAppEventActive } from '../../../utils'; +import { IEnv } from '../../../domain/env'; export * from './types'; export class AppEventsRepository implements IAppEventsRepository { - constructor(private _httpProvider: IHttpDataProvider) {} + constructor( + private _httpProvider: IHttpDataProvider, + private _casperWalletApiByEnvUrl: Record, + ) {} async getReleaseEvents({ currentVersion, @@ -30,7 +33,7 @@ export class AppEventsRepository implements IAppEventsRepository { }: IGetReleaseUpdatesParams): Promise { try { const response = await this._httpProvider.get>({ - url: `${CasperWalletApiEndpoints[env]}/mobile-client-versions`, + url: `${this._casperWalletApiByEnvUrl[env]}/mobile-client-versions`, params: { after: `v${currentVersion}`, }, @@ -50,7 +53,7 @@ export class AppEventsRepository implements IAppEventsRepository { }: IGetMarketingEventsParams = {}): Promise { try { const response = await this._httpProvider.get>({ - url: `${CasperWalletApiEndpoints[env]}/marketing-events`, + url: `${this._casperWalletApiByEnvUrl[env]}/marketing-events`, errorType: 'getMarketingEvents', ...(withProxyHeader ? { headers: CSPR_API_PROXY_HEADERS } : {}), }); diff --git a/src/data/repositories/contractPackage/index.ts b/src/data/repositories/contractPackage/index.ts index 644f490..9752e78 100644 --- a/src/data/repositories/contractPackage/index.ts +++ b/src/data/repositories/contractPackage/index.ts @@ -1,5 +1,5 @@ import { - CasperWalletApiUrl, + CasperNetwork, ContractPackageError, ContractPackageErrorType, CSPR_API_PROXY_HEADERS, @@ -15,7 +15,10 @@ import { ContractPackageDto } from '../../dto'; export * from './types'; export class ContractPackageRepository implements IContractPackageRepository { - constructor(private _httpProvider: IHttpDataProvider) {} + constructor( + private _httpProvider: IHttpDataProvider, + private _casperWalletApiUrl: Record, + ) {} async getContractPackage({ contractPackageHash, @@ -24,7 +27,7 @@ export class ContractPackageRepository implements IContractPackageRepository { }: IGetContractPackageParams) { try { const resp = await this._httpProvider.get>({ - url: `${CasperWalletApiUrl[network]}/contract-packages/${contractPackageHash}`, + url: `${this._casperWalletApiUrl[network]}/contract-packages/${contractPackageHash}`, baseURL: '', errorType: 'getContractPackageRequest', ...(withProxyHeader ? { headers: CSPR_API_PROXY_HEADERS } : {}), diff --git a/src/data/repositories/deploys/index.ts b/src/data/repositories/deploys/index.ts index 872db44..5ae5c53 100644 --- a/src/data/repositories/deploys/index.ts +++ b/src/data/repositories/deploys/index.ts @@ -5,7 +5,6 @@ import { HttpClientNotFoundError, CSPR_API_PROXY_HEADERS, EMPTY_PAGINATED_RESPONSE, - CasperWalletApiUrl, IDeploysRepository, IGetDeploysParams, CloudPaginatedResponse, @@ -13,6 +12,7 @@ import { DataResponse, IDeploy, PaginatedResponse, + CasperNetwork, } from '../../../domain'; import type { IHttpDataProvider, IAccountInfoRepository } from '../../../domain'; import { getAccountHashFromPublicKey } from '../../../utils'; @@ -29,6 +29,7 @@ export class DeploysRepository implements IDeploysRepository { constructor( private _httpProvider: IHttpDataProvider, private _accountInfoRepository: IAccountInfoRepository, + private _casperWalletApiUrl: Record, ) {} async getDeploys({ @@ -41,7 +42,7 @@ export class DeploysRepository implements IDeploysRepository { }: IGetDeploysParams) { try { const resp = await this._httpProvider.get>({ - url: `${CasperWalletApiUrl[network]}/accounts/${activePublicKey}/deploys`, + url: `${this._casperWalletApiUrl[network]}/accounts/${activePublicKey}/deploys`, params: { public_key: activePublicKey, page, @@ -94,7 +95,7 @@ export class DeploysRepository implements IDeploysRepository { const accountHash = getAccountHashFromPublicKey(activePublicKey); const resp = await this._httpProvider.get>({ - url: `${CasperWalletApiUrl[network]}/accounts/${accountHash}/transfers`, + url: `${this._casperWalletApiUrl[network]}/accounts/${accountHash}/transfers`, params: { page, page_size: limit, @@ -142,7 +143,7 @@ export class DeploysRepository implements IDeploysRepository { }: IGetSingleDeployParams) { try { const resp = await this._httpProvider.get>({ - url: `${CasperWalletApiUrl[network]}/deploys/${deployHash}`, + url: `${this._casperWalletApiUrl[network]}/deploys/${deployHash}`, params: { includes: 'rate(1),contract,contract_package,contract_entrypoint,account_info,transfers,nft_token_actions,ft_token_actions', @@ -190,7 +191,7 @@ export class DeploysRepository implements IDeploysRepository { const resp = await this._httpProvider.get< CloudPaginatedResponse >({ - url: `${CasperWalletApiUrl[network]}/accounts/${accountHash}/ft-token-actions`, + url: `${this._casperWalletApiUrl[network]}/accounts/${accountHash}/ft-token-actions`, params: { contract_package_hash: contractPackageHash, // TODO do not worked account_identifier: accountHash, diff --git a/src/data/repositories/nfts/index.ts b/src/data/repositories/nfts/index.ts index 7f8921e..665fc05 100644 --- a/src/data/repositories/nfts/index.ts +++ b/src/data/repositories/nfts/index.ts @@ -1,5 +1,4 @@ import { - CasperWalletApiUrl, DEFAULT_PAGE_LIMIT, EMPTY_PAGINATED_RESPONSE, CSPR_API_PROXY_HEADERS, @@ -11,6 +10,7 @@ import { INft, NftContentType, PaginatedResponse, + CasperNetwork, } from '../../../domain'; import type { IHttpDataProvider } from '../../../domain'; import { getAccountHashFromPublicKey } from '../../../utils'; @@ -20,7 +20,10 @@ import { IApiNft } from './types'; export * from './types'; export class NftsRepository implements INftsRepository { - constructor(private _httpProvider: IHttpDataProvider) {} + constructor( + private _httpProvider: IHttpDataProvider, + private _casperWalletApiUrl: Record, + ) {} async getNfts({ network, @@ -33,7 +36,7 @@ export class NftsRepository implements INftsRepository { const accountHash = getAccountHashFromPublicKey(publicKey); const resp = await this._httpProvider.get>({ - url: `${CasperWalletApiUrl[network]}/accounts/${accountHash}/nft-tokens`, + url: `${this._casperWalletApiUrl[network]}/accounts/${accountHash}/nft-tokens`, params: { page, page_size: limit, diff --git a/src/data/repositories/tokens/index.ts b/src/data/repositories/tokens/index.ts index 7eb294c..0cf48a7 100644 --- a/src/data/repositories/tokens/index.ts +++ b/src/data/repositories/tokens/index.ts @@ -4,7 +4,6 @@ import { TokensError, HttpClientNotFoundError, CSPR_API_PROXY_HEADERS, - CasperWalletApiUrl, ITokensRepository, DataResponse, IGetTokensParams, @@ -12,6 +11,7 @@ import { IToken, IGetCsprFiatCurrencyRateParams, ITokenWithFiatBalance, + CasperNetwork, } from '../../../domain'; import type { IHttpDataProvider } from '../../../domain'; import { CsprBalanceDto, TokenDto, TokenFiatRateDto } from '../../dto'; @@ -21,7 +21,10 @@ import { Erc20Token, IGetCsprBalanceResponse, IGetCurrencyRateResponse } from '. export * from './types'; export class TokensRepository implements ITokensRepository { - constructor(private _httpProvider: IHttpDataProvider) {} + constructor( + private _httpProvider: IHttpDataProvider, + private _casperWalletApiUrl: Record, + ) {} async getTokens({ network, @@ -32,7 +35,7 @@ export class TokensRepository implements ITokensRepository { const accountHash = getAccountHashFromPublicKey(publicKey); const tokensList = await this._httpProvider.get>({ - url: `${CasperWalletApiUrl[network]}/accounts/${accountHash}/ft-token-ownership`, + url: `${this._casperWalletApiUrl[network]}/accounts/${accountHash}/ft-token-ownership`, params: { page_size: 100, // TODO pagination? includes: 'contract_package,friendlymarket_data(1),coingecko_data(1)', @@ -55,7 +58,7 @@ export class TokensRepository implements ITokensRepository { async getCsprBalance({ publicKey, network, withProxyHeader = true }: IGetCsprBalanceParams) { try { const resp = await this._httpProvider.get>({ - url: `${CasperWalletApiUrl[network]}/accounts/${publicKey}`, + url: `${this._casperWalletApiUrl[network]}/accounts/${publicKey}`, errorType: 'getCsprBalance', params: { includes: 'delegated_balance,undelegating_balance', @@ -100,7 +103,7 @@ export class TokensRepository implements ITokensRepository { }: IGetCsprFiatCurrencyRateParams) { try { const resp = await this._httpProvider.get({ - url: `${CasperWalletApiUrl[network]}/rates/1/amount`, + url: `${this._casperWalletApiUrl[network]}/rates/1/amount`, ...(withProxyHeader ? { headers: CSPR_API_PROXY_HEADERS } : {}), errorType: 'getCsprFiatCurrencyRate', }); diff --git a/src/data/repositories/txSignatureRequest/index.ts b/src/data/repositories/txSignatureRequest/index.ts index e0a193f..b66ebe8 100644 --- a/src/data/repositories/txSignatureRequest/index.ts +++ b/src/data/repositories/txSignatureRequest/index.ts @@ -1,9 +1,7 @@ import { CasperNetwork, - CasperWalletApiEndpoints, CSPR_API_PROXY_HEADERS, DataResponse, - GrpcUrl, IAccountInfoRepository, IContractPackage, IContractPackageRepository, @@ -38,6 +36,7 @@ import { TxSignatureRequestDto, } from '../../dto'; import { blake2b } from '@noble/hashes/blake2'; +import { IEnv } from '../../../domain/env'; export * from './types'; @@ -47,12 +46,15 @@ export class TxSignatureRequestRepository implements ITxSignatureRequestReposito private _accountInfoRepository: IAccountInfoRepository, private _tokensRepository: ITokensRepository, private _contractPackageRepository: IContractPackageRepository, + private _casperWalletApiByEnvUrl: Record, + private _grpcUrl: Record, ) {} async prepareSignatureRequest({ transactionJson, signingPublicKeyHex, withProxyHeader = true, + env = 'PRODUCTION', }: IPrepareSignatureRequestParams): Promise { try { const tx = Transaction.fromJSON(transactionJson); @@ -88,7 +90,7 @@ export class TxSignatureRequestRepository implements ITxSignatureRequestReposito } catch (e) {} try { - isWasmProxyOnApi = await this._checkIsWasmProxyTx(tx, withProxyHeader); + isWasmProxyOnApi = await this._checkIsWasmProxyTx(tx, withProxyHeader, env); } catch (e) {} try { @@ -130,7 +132,7 @@ export class TxSignatureRequestRepository implements ITxSignatureRequestReposito } catch (e) {} try { - const handler = new HttpHandler(GrpcUrl[network], 'fetch'); + const handler = new HttpHandler(this._grpcUrl[network], 'fetch'); if (withProxyHeader) { handler.setReferrer(CSPR_API_PROXY_HEADERS.Referer); @@ -263,7 +265,7 @@ export class TxSignatureRequestRepository implements ITxSignatureRequestReposito return null; } - const handler = new HttpHandler(GrpcUrl[network], 'fetch'); + const handler = new HttpHandler(this._grpcUrl[network], 'fetch'); if (withProxyHeader) { handler.setReferrer(CSPR_API_PROXY_HEADERS.Referer); @@ -290,7 +292,11 @@ export class TxSignatureRequestRepository implements ITxSignatureRequestReposito } } - private async _checkIsWasmProxyTx(tx: Transaction, withProxyHeader = true): Promise { + private async _checkIsWasmProxyTx( + tx: Transaction, + withProxyHeader = true, + env: IEnv = 'PRODUCTION', + ): Promise { try { if (!tx.target.session?.moduleBytes) { return false; @@ -301,7 +307,7 @@ export class TxSignatureRequestRepository implements ITxSignatureRequestReposito ); await this._httpProvider.get>({ - url: `${CasperWalletApiEndpoints.PRODUCTION}/odra-wasm-proxies/${blake2bHash}`, + url: `${this._casperWalletApiByEnvUrl[env]}/odra-wasm-proxies/${blake2bHash}`, baseURL: '', errorType: 'checkWasmProxyRequest', ...(withProxyHeader ? { headers: CSPR_API_PROXY_HEADERS } : {}), diff --git a/src/data/repositories/validators/index.ts b/src/data/repositories/validators/index.ts index ecb3737..0e4b2c5 100644 --- a/src/data/repositories/validators/index.ts +++ b/src/data/repositories/validators/index.ts @@ -1,5 +1,5 @@ import { - CasperWalletApiUrl, + CasperNetwork, CloudPaginatedResponse, CSPR_API_PROXY_HEADERS, DataResponse, @@ -20,7 +20,10 @@ import { IApiValidator, IApiValidatorWithStake, IAuctionMetricsResponse } from ' export * from './types'; export class ValidatorsRepository implements IValidatorsRepository { - constructor(private _httpProvider: IHttpDataProvider) {} + constructor( + private _httpProvider: IHttpDataProvider, + private _casperWalletApiUrl: Record, + ) {} async getValidators({ network, @@ -32,7 +35,7 @@ export class ValidatorsRepository implements IValidatorsRepository { const eraId = await this.getCurrentEraId({ network, withProxyHeader }); const resp = await this._httpProvider.get>({ - url: `${CasperWalletApiUrl[network]}/validators`, + url: `${this._casperWalletApiUrl[network]}/validators`, params: { page, page_size: limit, @@ -68,7 +71,7 @@ export class ValidatorsRepository implements IValidatorsRepository { const eraId = await this.getCurrentEraId({ network, withProxyHeader }); const validatorsList = await this._httpProvider.get>({ - url: `${CasperWalletApiUrl[network]}/accounts/${publicKey}/delegations`, + url: `${this._casperWalletApiUrl[network]}/accounts/${publicKey}/delegations`, params: { page: 1, page_size: 100, // TODO Pagination? @@ -90,7 +93,7 @@ export class ValidatorsRepository implements IValidatorsRepository { async getCurrentEraId({ withProxyHeader, network }: IGetGetCurrentEraIdParams): Promise { try { const resp = await this._httpProvider.get>({ - url: `${CasperWalletApiUrl[network]}/auction-metrics`, + url: `${this._casperWalletApiUrl[network]}/auction-metrics`, ...(withProxyHeader ? { headers: CSPR_API_PROXY_HEADERS } : {}), errorType: 'getCurrentEraId', }); diff --git a/src/domain/constants/casperNetwork.ts b/src/domain/constants/casperNetwork.ts index dc2d4a6..b62ad04 100644 --- a/src/domain/constants/casperNetwork.ts +++ b/src/domain/constants/casperNetwork.ts @@ -12,14 +12,15 @@ export const CasperLiveUrl: Record = { integration: 'https://integration.cspr.live', }; -export const CasperWalletApiUrl: Record = { +export const CasperWalletApiByNetworkUrl: Record = { mainnet: 'https://api.mainnet.casperwallet.io', testnet: 'https://api.testnet.casperwallet.io', devnet: 'https://cspr-wallet-api.dev.make.services', integration: 'https://api.integration.casperwallet.io', }; -export const CasperWalletApiEndpoints: Record = { +/** Environment-based url for Casper Wallet Api. Some API network agnostic and do not belong to any {@link CasperWalletApiByNetworkUrl}. Default env is PRODUCTION (in all places where it is used) */ +export const CasperWalletApiByEnvUrl: Record = { PRODUCTION: 'https://api.casperwallet.io', STAGING: 'https://cspr-wallet-api.stg.make.services', }; diff --git a/src/domain/tx-signature-request/repository.ts b/src/domain/tx-signature-request/repository.ts index 75b0175..efeba4f 100644 --- a/src/domain/tx-signature-request/repository.ts +++ b/src/domain/tx-signature-request/repository.ts @@ -1,4 +1,5 @@ import { ITxSignatureRequest } from './entities'; +import { IEnv } from '../env'; export interface ITxSignatureRequestRepository { prepareSignatureRequest(params: IPrepareSignatureRequestParams): Promise; @@ -8,4 +9,5 @@ export interface IPrepareSignatureRequestParams { transactionJson: string; signingPublicKeyHex: string; withProxyHeader?: boolean; + env?: IEnv; } diff --git a/src/setup.ts b/src/setup.ts index 85bbc96..13dba55 100644 --- a/src/setup.ts +++ b/src/setup.ts @@ -11,30 +11,62 @@ import { ContractPackageRepository, } from './data/repositories'; import { Logger } from './utils'; -import { ILogger } from './domain'; +import { + CasperNetwork, + CasperWalletApiByNetworkUrl, + CasperWalletApiByEnvUrl, + GrpcUrl, + ILogger, +} from './domain'; +import { IEnv } from './domain/env'; export interface ISetupRepositoriesParams { debug?: boolean; logger?: ILogger; + casperWalletApiByNetworkUrl?: Record; + /** Environment-based url for Casper Wallet Api. Some API network agnostic and do not belong to any {@link CasperWalletApiByNetworkUrl}. Default env is PRODUCTION (in all places where it is used) */ + casperWalletApiByEnvUrl?: Record; + grpcUrl?: Record; } -export const setupRepositories = ({ logger, debug }: ISetupRepositoriesParams = {}) => { +export const setupRepositories = ({ + logger, + debug, + casperWalletApiByNetworkUrl = CasperWalletApiByNetworkUrl, + casperWalletApiByEnvUrl = CasperWalletApiByEnvUrl, + grpcUrl = GrpcUrl, +}: ISetupRepositoriesParams = {}) => { const log = logger ?? new Logger(); const httpDataProvider = new HttpDataProvider(debug ? log : null); - const accountInfoRepository = new AccountInfoRepository(httpDataProvider); - const tokensRepository = new TokensRepository(httpDataProvider); + const accountInfoRepository = new AccountInfoRepository( + httpDataProvider, + casperWalletApiByNetworkUrl, + ); + const tokensRepository = new TokensRepository(httpDataProvider, casperWalletApiByNetworkUrl); const onRampRepository = new OnRampRepository(httpDataProvider); - const nftsRepository = new NftsRepository(httpDataProvider); - const validatorsRepository = new ValidatorsRepository(httpDataProvider); - const deploysRepository = new DeploysRepository(httpDataProvider, accountInfoRepository); - const appEventsRepository = new AppEventsRepository(httpDataProvider); - const contractPackageRepository = new ContractPackageRepository(httpDataProvider); + const nftsRepository = new NftsRepository(httpDataProvider, casperWalletApiByNetworkUrl); + const validatorsRepository = new ValidatorsRepository( + httpDataProvider, + casperWalletApiByNetworkUrl, + ); + const deploysRepository = new DeploysRepository( + httpDataProvider, + accountInfoRepository, + casperWalletApiByNetworkUrl, + ); + const appEventsRepository = new AppEventsRepository(httpDataProvider, casperWalletApiByEnvUrl); + const contractPackageRepository = new ContractPackageRepository( + httpDataProvider, + casperWalletApiByNetworkUrl, + ); const txSignatureRequestRepository = new TxSignatureRequestRepository( httpDataProvider, accountInfoRepository, tokensRepository, contractPackageRepository, + casperWalletApiByEnvUrl, + grpcUrl, ); return { From a6da9353a84def36e200c6b4b3c79ffe439daaed Mon Sep 17 00:00:00 2001 From: Dmytro Vynnyk Date: Mon, 10 Nov 2025 13:10:03 +0100 Subject: [PATCH 3/5] Update `cep-nft-transfer` to specify `CLTypeUInt8` for `CLOption` initialization, ensuring proper type handling --- src/utils/casperSdk/cep-nft-transfer.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils/casperSdk/cep-nft-transfer.ts b/src/utils/casperSdk/cep-nft-transfer.ts index a44e033..5245f6b 100644 --- a/src/utils/casperSdk/cep-nft-transfer.ts +++ b/src/utils/casperSdk/cep-nft-transfer.ts @@ -16,6 +16,7 @@ import { StoredVersionedContractByHash, Timestamp, Transaction, + CLTypeUInt8, } from 'casper-js-sdk'; export enum NFTTokenStandard { @@ -304,6 +305,6 @@ export function getRuntimeArgsForCep95Transfer({ ), ), token_id: CLValue.newCLUInt256(tokenId), - data: CLValue.newCLOption(null), + data: CLValue.newCLOption(null, CLTypeUInt8), }); } From 043df32658ae584c17520a9916ece0db2f7e065e Mon Sep 17 00:00:00 2001 From: Dmytro Vynnyk Date: Mon, 1 Dec 2025 22:40:50 +0100 Subject: [PATCH 4/5] Add support for handling CEP-18 entry points and improve `TxSignatureRequestDto` logic with `isCep18Action` validation --- .../txSignatureRequest/TxSignatureRequestDto.ts | 15 +++++++++++---- src/domain/constants/casperNetwork.ts | 11 +++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/data/dto/txSignatureRequest/TxSignatureRequestDto.ts b/src/data/dto/txSignatureRequest/TxSignatureRequestDto.ts index 81153eb..59979b9 100644 --- a/src/data/dto/txSignatureRequest/TxSignatureRequestDto.ts +++ b/src/data/dto/txSignatureRequest/TxSignatureRequestDto.ts @@ -5,6 +5,7 @@ import { AssociatedKeysContractInfo, AuctionManagerContractInfo, CasperNetwork, + CEP_18_ACTION_ENTRY_POINTS, CSPR_COIN, CSPRMarketContractInfo, IAccountInfo, @@ -188,10 +189,7 @@ export function getTxSignatureRequestAction( contractPackage, collectionContractPackage, ); - } else if ( - contractTypeId === ContractTypeId.CustomCep18 || - contractTypeId === ContractTypeId.Cep18 - ) { + } else if (isCep18Action(tx, contractTypeId)) { return getTxSignatureRequestCep18Action(tx, accountInfoMap, contractPackage); } else if ( contractTypeId === ContractTypeId.CEP78Nft || @@ -263,3 +261,12 @@ function isContractSpecificContractCall(tx: Transaction, contractInfo: IContract storedTargetId?.byPackageName?.name === contractInfo.contractPackageName ); } + +function isCep18Action(tx: Transaction, contractTypeId?: number): boolean { + const entryPoint = tx.entryPoint.customEntryPoint ?? ''; + + return ( + (contractTypeId === ContractTypeId.CustomCep18 || contractTypeId === ContractTypeId.Cep18) && + CEP_18_ACTION_ENTRY_POINTS.includes(entryPoint.toLowerCase()) + ); +} diff --git a/src/domain/constants/casperNetwork.ts b/src/domain/constants/casperNetwork.ts index b62ad04..f21d0b6 100644 --- a/src/domain/constants/casperNetwork.ts +++ b/src/domain/constants/casperNetwork.ts @@ -219,3 +219,14 @@ export const casperChainNameToCasperNetwork: Record Date: Mon, 1 Dec 2025 23:11:18 +0100 Subject: [PATCH 5/5] Add `iconUrl` support to deploy DTOs and entities; refine CEP-18 entry point validation logic --- src/data/dto/deploys/CsprTransferDeployDto.ts | 2 ++ src/data/dto/deploys/DeployDto.ts | 2 ++ src/data/dto/deploys/common.ts | 5 +++-- src/domain/deploys/entities.ts | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/data/dto/deploys/CsprTransferDeployDto.ts b/src/data/dto/deploys/CsprTransferDeployDto.ts index 4ecfcaf..60d3921 100644 --- a/src/data/dto/deploys/CsprTransferDeployDto.ts +++ b/src/data/dto/deploys/CsprTransferDeployDto.ts @@ -108,6 +108,7 @@ export class CsprTransferDeployDto implements INativeCsprDeploy { this.cep18ActionsResult = []; this.deployHash = data?.deploy_hash ?? ''; this.id = getUniqueId(); + this.iconUrl = null; } readonly recipientAccountInfo: Maybe; @@ -144,4 +145,5 @@ export class CsprTransferDeployDto implements INativeCsprDeploy { readonly cep18ActionsResult: ICep18ActionsResult[]; readonly id: string; readonly deployHash: string; + readonly iconUrl: Maybe; } diff --git a/src/data/dto/deploys/DeployDto.ts b/src/data/dto/deploys/DeployDto.ts index ad8f0d8..2de5945 100644 --- a/src/data/dto/deploys/DeployDto.ts +++ b/src/data/dto/deploys/DeployDto.ts @@ -50,6 +50,7 @@ export class DeployDto implements IDeploy { ); this.contractHash = data?.contract_hash ?? ''; this.contractPackageHash = data?.contract_package_hash ?? ''; + this.iconUrl = data?.contract_package?.icon_url ?? null; this.entryPoint = getEntryPoint(data) ?? null; this.contractName = data?.contract_package?.name ?? null; @@ -75,6 +76,7 @@ export class DeployDto implements IDeploy { readonly executionTypeId: number; readonly contractHash: string; readonly contractPackageHash: string; + readonly iconUrl: Maybe; readonly entryPoint: Maybe; readonly status: DeployStatus; readonly cost: string; diff --git a/src/data/dto/deploys/common.ts b/src/data/dto/deploys/common.ts index 42212cf..547ea0a 100644 --- a/src/data/dto/deploys/common.ts +++ b/src/data/dto/deploys/common.ts @@ -12,6 +12,7 @@ import { AccountKeyType, AssociatedKeysContractHash, AuctionManagerContractHash, + CEP_18_ACTION_ENTRY_POINTS, CSPRMarketContractHash, CSPRStudioCep47ContractHash, DeployType, @@ -41,8 +42,8 @@ export function getDeployType(network: Network, deploy?: Partial; readonly status: DeployStatus; readonly callerPublicKey: string;