From bebe6d8e3ad21dc31e10557320f2b6012e1bef1f Mon Sep 17 00:00:00 2001 From: Kristijan Date: Wed, 27 Aug 2025 18:46:52 +0200 Subject: [PATCH] Version 1.3.51 - 2025-08-27 18:46:52 --- package.json | 2 +- src/index.ts | 252 +++++++------------------------ src/protected.ts | 362 +++++++++++++++++++++++++++++++++++++++++++++ src/types/index.ts | 255 ++++++++++++++++++++++++++++++- 4 files changed, 672 insertions(+), 199 deletions(-) create mode 100644 src/protected.ts diff --git a/package.json b/package.json index a78acdb..dc218f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@icpay/sdk", - "version": "1.3.50", + "version": "1.3.51", "description": "Official icpay SDK for Internet Computer payments", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/index.ts b/src/index.ts index 405559a..46628ef 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,7 +15,10 @@ import { PaymentHistoryResponse, GetPaymentsByPrincipalRequest, LedgerInfo, - SendFundsUsdRequest + SendFundsUsdRequest, + AccountPublic, + LedgerPublic, + SdkLedger, } from './types'; import { IcpayError, createBalanceError, ICPAY_ERROR_CODES } from './errors'; import { IcpayEventCenter, IcpayEventName } from './events'; @@ -26,6 +29,7 @@ import { idlFactory as icpayIdl } from './declarations/icpay_canister_backend/ic import { idlFactory as ledgerIdl } from './declarations/icrc-ledger/ledger.did.js'; import { Principal } from '@dfinity/principal'; import { toAccountIdentifier, debugLog } from './utils'; +import { IcpayProtected } from './protected'; export class Icpay { private config: IcpayConfig; @@ -37,15 +41,16 @@ export class Icpay { private actorProvider?: (canisterId: string, idl: any) => any; private icpayCanisterId: string | null = null; private accountInfoCache: any = null; - private verifiedLedgersCache: { data: VerifiedLedger[] | null; timestamp: number } = { data: null, timestamp: 0 }; + private verifiedLedgersCache: { data: LedgerPublic[] | null; timestamp: number } = { data: null, timestamp: 0 }; private events: IcpayEventCenter; + public protected: IcpayProtected; constructor(config: IcpayConfig) { this.config = { environment: 'production', apiUrl: 'https://api.icpay.org', debug: false, - enableEvents: true, + enableEvents: false, awaitServerNotification: false, ...config }; @@ -95,6 +100,15 @@ export class Icpay { } debugLog(this.config.debug || false, 'privateApiClient created', this.privateApiClient); + + // Initialize protected wrapper + this.protected = new IcpayProtected({ + publicApiClient: this.publicApiClient, + privateApiClient: this.privateApiClient, + emitStart: (name, args) => this.emitMethodStart(name, args), + emitSuccess: (name, result) => this.emitMethodSuccess(name, result), + emitError: (name, error) => this.emitMethodError(name, error), + }); } // ===== Event API (no Lit required) ===== @@ -178,21 +192,19 @@ export class Icpay { /** * Get account information (public method - limited data) */ - async getAccountInfo(): Promise { + async getAccountInfo(): Promise { this.emitMethodStart('getAccountInfo'); try { const response = await this.publicApiClient.get('/sdk/public/account'); const account = response.data; - const result = { + const result: AccountPublic = { id: account.id, name: account.name, isActive: account.isActive, isLive: account.isLive, accountCanisterId: account.accountCanisterId, - walletAddress: account.walletAddress, - createdAt: new Date(account.createdAt), - updatedAt: new Date(account.updatedAt) + icpayCanisterId: account.icpayCanisterId, }; this.emitMethodSuccess('getAccountInfo', result); return result; @@ -211,41 +223,13 @@ export class Icpay { * Get detailed account information (private method - full data) */ async getDetailedAccountInfo(): Promise { - this.requireSecretKey('getDetailedAccountInfo'); - this.emitMethodStart('getDetailedAccountInfo'); - - try { - const response = await this.privateApiClient!.get('/sdk/account'); - const account = response.data; - - const result = { - id: account.id, - name: account.name, - email: account.email, - isActive: account.isActive, - isLive: account.isLive, - accountCanisterId: account.accountCanisterId, - walletAddress: account.walletAddress, - createdAt: new Date(account.createdAt), - updatedAt: new Date(account.updatedAt) - }; - this.emitMethodSuccess('getDetailedAccountInfo', result); - return result; - } catch (error) { - const err = new IcpayError({ - code: 'ACCOUNT_INFO_FETCH_FAILED', - message: 'Failed to fetch detailed account information', - details: error - }); - this.emitMethodError('getDetailedAccountInfo', err); - throw err; - } + return this.protected.getDetailedAccountInfo(); } /** * Get verified ledgers (public method) */ - async getVerifiedLedgers(): Promise { + async getVerifiedLedgers(): Promise { this.emitMethodStart('getVerifiedLedgers'); const now = Date.now(); const cacheAge = 60 * 60 * 1000; // 60 minutes cache @@ -257,7 +241,7 @@ export class Icpay { try { const response = await this.publicApiClient.get('/sdk/public/ledgers/verified'); - const ledgers = response.data.map((ledger: any) => ({ + const ledgers: LedgerPublic[] = response.data.map((ledger: any) => ({ id: ledger.id, name: ledger.name, symbol: ledger.symbol, @@ -266,9 +250,8 @@ export class Icpay { logoUrl: ledger.logoUrl, verified: ledger.verified, fee: ledger.fee, - // Price-related fields - currentPrice: ledger.currentPrice || null, - lastPriceUpdate: ledger.lastPriceUpdate || null + currentPrice: ledger.currentPrice ?? null, + lastPriceUpdate: ledger.lastPriceUpdate ?? null, })); // Update cache @@ -325,23 +308,7 @@ export class Icpay { * If a transaction is not found, a sync notification will be automatically triggered. */ async getTransactionStatus(canisterTransactionId: number): Promise { - this.requireSecretKey('getTransactionStatus'); - this.emitMethodStart('getTransactionStatus', { canisterTransactionId }); - - try { - const response = await this.privateApiClient!.get(`/sdk/transactions/${canisterTransactionId}/status`); - const result = response.data; - this.emitMethodSuccess('getTransactionStatus', result); - return result; - } catch (error) { - const err = new IcpayError({ - code: 'TRANSACTION_STATUS_FETCH_FAILED', - message: 'Failed to fetch transaction status', - details: error - }); - this.emitMethodError('getTransactionStatus', err); - throw err; - } + return this.protected.getTransactionStatus(canisterTransactionId); } /** @@ -1261,126 +1228,44 @@ export class Icpay { * Get payment history for account (requires secret key) */ async getPaymentHistory(request: PaymentHistoryRequest = {}): Promise { - this.requireSecretKey('getPaymentHistory'); - this.emitMethodStart('getPaymentHistory', { request }); - try { - const params = new URLSearchParams(); - - if (request.accountId) params.append('accountId', request.accountId); - if (request.ledgerCanisterId) params.append('ledgerCanisterId', request.ledgerCanisterId); - if (request.fromTimestamp) params.append('fromTimestamp', request.fromTimestamp.toISOString()); - if (request.toTimestamp) params.append('toTimestamp', request.toTimestamp.toISOString()); - if (request.status) params.append('status', request.status); - if (request.limit) params.append('limit', request.limit.toString()); - if (request.offset) params.append('offset', request.offset.toString()); - - const response = await this.privateApiClient!.get(`/sdk/payments/history?${params.toString()}`); - - const result = { - payments: response.data.payments.map((tx: any) => ({ - id: tx.id, - status: tx.status, - amount: tx.amount, - ledgerCanisterId: tx.ledgerCanisterId, - ledgerSymbol: tx.ledgerSymbol, - fromAddress: tx.fromAddress, - toAddress: tx.toAddress, - fee: tx.fee, - decimals: tx.decimals, - tokenPrice: tx.tokenPrice, - expectedSenderPrincipal: tx.expectedSenderPrincipal, - metadata: tx.metadata, - createdAt: new Date(tx.createdAt), - updatedAt: new Date(tx.updatedAt) - })), - total: response.data.total, - limit: response.data.limit, - offset: response.data.offset, - hasMore: response.data.hasMore - }; - this.emitMethodSuccess('getPaymentHistory', { total: result.total }); - return result; - } catch (error) { - const err = new IcpayError({ - code: 'PAYMENT_HISTORY_FETCH_FAILED', - message: 'Failed to fetch payment history', - details: error - }); - this.emitMethodError('getPaymentHistory', err); - throw err; - } + return this.protected.getPaymentHistory(request); } /** * Get payments by principal ID (for connected wallet) - checks both sender_principal_id and expected_sender_principal */ async getPaymentsByPrincipal(request: GetPaymentsByPrincipalRequest): Promise { - this.requireSecretKey('getPaymentsByPrincipal'); - this.emitMethodStart('getPaymentsByPrincipal', { request }); - try { - const params = new URLSearchParams(); - - if (request.limit) params.append('limit', request.limit.toString()); - if (request.offset) params.append('offset', request.offset.toString()); - if (request.status) params.append('status', request.status); - - const response = await this.privateApiClient!.get(`/sdk/payments/by-principal/${request.principalId}?${params.toString()}`); - - const result = { - payments: response.data.payments.map((tx: any) => ({ - id: tx.id, - status: tx.status, - amount: tx.amount, - ledgerCanisterId: tx.ledgerCanisterId, - ledgerSymbol: tx.ledgerSymbol, - fromAddress: tx.fromAddress, - toAddress: tx.toAddress, - fee: tx.fee, - decimals: tx.decimals, - tokenPrice: tx.tokenPrice, - expectedSenderPrincipal: tx.expectedSenderPrincipal, - metadata: tx.metadata, - createdAt: new Date(tx.createdAt), - updatedAt: new Date(tx.updatedAt) - })), - total: response.data.total, - limit: response.data.limit, - offset: response.data.offset, - hasMore: response.data.hasMore - }; - this.emitMethodSuccess('getPaymentsByPrincipal', { total: result.total }); - return result; - } catch (error) { - const err = new IcpayError({ - code: 'PAYMENTS_BY_PRINCIPAL_FETCH_FAILED', - message: 'Failed to fetch payments by principal', - details: error - }); - this.emitMethodError('getPaymentsByPrincipal', err); - throw err; - } + return this.protected.getPaymentsByPrincipal(request); } /** * Get detailed ledger information including price data (public method) */ - async getLedgerInfo(ledgerCanisterId: string): Promise { + async getLedgerInfo(ledgerCanisterId: string): Promise { this.emitMethodStart('getLedgerInfo', { ledgerCanisterId }); try { const response = await this.publicApiClient.get(`/sdk/public/ledgers/${ledgerCanisterId}`); const ledger = response.data; - const result = { + const result: SdkLedger = { id: ledger.id, name: ledger.name, symbol: ledger.symbol, canisterId: ledger.canisterId, + standard: ledger.standard, decimals: ledger.decimals, - logoUrl: ledger.logoUrl || undefined, + logoUrl: ledger.logoUrl ?? null, verified: ledger.verified, - fee: ledger.fee || undefined, - currentPrice: ledger.currentPrice || undefined, - lastPriceUpdate: ledger.lastPriceUpdate ? new Date(ledger.lastPriceUpdate) : undefined + fee: ledger.fee ?? null, + network: ledger.network, + description: ledger.description ?? null, + lastBlockIndex: ledger.lastBlockIndex ?? null, + coingeckoId: ledger.coingeckoId ?? null, + currentPrice: ledger.currentPrice ?? null, + priceFetchMethod: ledger.priceFetchMethod ?? null, + lastPriceUpdate: ledger.lastPriceUpdate ?? null, + createdAt: ledger.createdAt, + updatedAt: ledger.updatedAt, }; this.emitMethodSuccess('getLedgerInfo', { ledgerCanisterId }); return result; @@ -1437,22 +1322,30 @@ export class Icpay { /** * Get all ledgers with price information (public method) */ - async getAllLedgersWithPrices(): Promise { + async getAllLedgersWithPrices(): Promise { this.emitMethodStart('getAllLedgersWithPrices'); try { const response = await this.publicApiClient.get('/sdk/public/ledgers/all-with-prices'); - const result = response.data.map((ledger: any) => ({ + const result: SdkLedger[] = response.data.map((ledger: any) => ({ id: ledger.id, name: ledger.name, symbol: ledger.symbol, canisterId: ledger.canisterId, + standard: ledger.standard, decimals: ledger.decimals, - logoUrl: ledger.logoUrl || undefined, + logoUrl: ledger.logoUrl ?? null, verified: ledger.verified, - fee: ledger.fee || undefined, - currentPrice: ledger.currentPrice || undefined, - lastPriceUpdate: ledger.lastPriceUpdate ? new Date(ledger.lastPriceUpdate) : undefined + fee: ledger.fee ?? null, + network: ledger.network, + description: ledger.description ?? null, + lastBlockIndex: ledger.lastBlockIndex ?? null, + coingeckoId: ledger.coingeckoId ?? null, + currentPrice: ledger.currentPrice ?? null, + priceFetchMethod: ledger.priceFetchMethod ?? null, + lastPriceUpdate: ledger.lastPriceUpdate ?? null, + createdAt: ledger.createdAt, + updatedAt: ledger.updatedAt, })); this.emitMethodSuccess('getAllLedgersWithPrices', { count: result.length }); return result; @@ -1471,38 +1364,7 @@ export class Icpay { * Get account wallet balances (from API, not connected wallet) (private method) */ async getAccountWalletBalances(): Promise { - this.requireSecretKey('getAccountWalletBalances'); - this.emitMethodStart('getAccountWalletBalances'); - try { - const response = await this.privateApiClient!.get('/sdk/account/wallet-balances'); - - const result = { - balances: response.data.balances.map((balance: any) => ({ - ledgerId: balance.ledgerId, - ledgerName: balance.ledgerName, - ledgerSymbol: balance.ledgerSymbol, - canisterId: balance.canisterId, - balance: balance.balance, - formattedBalance: balance.formattedBalance, - decimals: balance.decimals, - currentPrice: balance.currentPrice, - lastPriceUpdate: balance.lastPriceUpdate ? new Date(balance.lastPriceUpdate) : undefined, - lastUpdated: new Date(balance.lastUpdated) - })), - totalBalancesUSD: response.data.totalBalancesUSD, - lastUpdated: new Date(response.data.lastUpdated) - }; - this.emitMethodSuccess('getAccountWalletBalances', { count: result.balances.length, totalUSD: result.totalBalancesUSD }); - return result; - } catch (error) { - const err = new IcpayError({ - code: 'ACCOUNT_WALLET_BALANCES_FETCH_FAILED', - message: 'Failed to fetch account wallet balances', - details: error - }); - this.emitMethodError('getAccountWalletBalances', err); - throw err; - } + return this.protected.getAccountWalletBalances(); } /** diff --git a/src/protected.ts b/src/protected.ts new file mode 100644 index 0000000..7506587 --- /dev/null +++ b/src/protected.ts @@ -0,0 +1,362 @@ +import type { AxiosInstance } from 'axios'; +import { IcpayError } from './errors'; +import type { + SdkPaymentAggregate, + SdkPaymentIntent, + SdkInvoice, + SdkTransaction, + SdkWallet, + SdkLedger, + SdkWebhookEvent, + AccountInfo, + TransactionStatus, + PaymentHistoryRequest, + PaymentHistoryResponse, + GetPaymentsByPrincipalRequest, + AllLedgerBalances, + LedgerBalance, +} from './types'; + +type EmitFn = (name: string, payload?: any) => void; + +export class IcpayProtected { + private publicApiClient: AxiosInstance; + private privateApiClient: AxiosInstance | null; + private emitStart: EmitFn; + private emitSuccess: EmitFn; + private emitError: EmitFn; + + constructor(params: { + publicApiClient: AxiosInstance; + privateApiClient: AxiosInstance | null; + emitStart: EmitFn; + emitSuccess: EmitFn; + emitError: EmitFn; + }) { + this.publicApiClient = params.publicApiClient; + this.privateApiClient = params.privateApiClient; + this.emitStart = params.emitStart; + this.emitSuccess = params.emitSuccess; + this.emitError = params.emitError; + } + + private requireSecretKey(methodName: string): void { + if (!this.privateApiClient) { + throw new IcpayError({ + code: 'SECRET_KEY_REQUIRED', + message: `${methodName} requires secret key authentication. Please provide secretKey in configuration.`, + }); + } + } + + async getPaymentById(id: string): Promise { + this.requireSecretKey('getPaymentById'); + this.emitStart('getPaymentById', { id }); + try { + const res = await this.privateApiClient!.get(`/sdk/payments/${id}`); + this.emitSuccess('getPaymentById', { id }); + return res.data as SdkPaymentAggregate; + } catch (error) { + this.emitError('getPaymentById', error); + throw error; + } + } + + async listPayments(): Promise { + this.requireSecretKey('listPayments'); + this.emitStart('listPayments'); + try { + const res = await this.privateApiClient!.get('/sdk/payments'); + this.emitSuccess('listPayments', { count: Array.isArray(res.data) ? res.data.length : undefined }); + return res.data as SdkPaymentAggregate[]; + } catch (error) { + this.emitError('listPayments', error); + throw error; + } + } + + async getPaymentIntentById(id: string): Promise { + this.requireSecretKey('getPaymentIntentById'); + this.emitStart('getPaymentIntentById', { id }); + try { + const res = await this.privateApiClient!.get(`/sdk/payment-intents/${id}`); + this.emitSuccess('getPaymentIntentById', { id }); + return res.data as SdkPaymentIntent; + } catch (error) { + this.emitError('getPaymentIntentById', error); + throw error; + } + } + + async getInvoiceById(id: string): Promise { + this.requireSecretKey('getInvoiceById'); + this.emitStart('getInvoiceById', { id }); + try { + const res = await this.privateApiClient!.get(`/sdk/invoices/${id}`); + this.emitSuccess('getInvoiceById', { id }); + return res.data as SdkInvoice; + } catch (error) { + this.emitError('getInvoiceById', error); + throw error; + } + } + + async getTransactionById(id: string): Promise { + this.requireSecretKey('getTransactionById'); + this.emitStart('getTransactionById', { id }); + try { + const res = await this.privateApiClient!.get(`/sdk/transactions/${id}`); + this.emitSuccess('getTransactionById', { id }); + return res.data as SdkTransaction; + } catch (error) { + this.emitError('getTransactionById', error); + throw error; + } + } + + async getWalletById(id: string): Promise { + this.requireSecretKey('getWalletById'); + this.emitStart('getWalletById', { id }); + try { + const res = await this.privateApiClient!.get(`/sdk/wallets/${id}`); + this.emitSuccess('getWalletById', { id }); + return res.data as SdkWallet; + } catch (error) { + this.emitError('getWalletById', error); + throw error; + } + } + + async getVerifiedLedgersPrivate(): Promise { + this.requireSecretKey('getVerifiedLedgersPrivate'); + this.emitStart('getVerifiedLedgersPrivate'); + try { + const res = await this.privateApiClient!.get('/sdk/ledgers/verified'); + this.emitSuccess('getVerifiedLedgersPrivate', { count: Array.isArray(res.data) ? res.data.length : undefined }); + return res.data as SdkLedger[]; + } catch (error) { + this.emitError('getVerifiedLedgersPrivate', error); + throw error; + } + } + + async getAllLedgersWithPricesPrivate(): Promise { + this.requireSecretKey('getAllLedgersWithPricesPrivate'); + this.emitStart('getAllLedgersWithPricesPrivate'); + try { + const res = await this.privateApiClient!.get('/sdk/ledgers/all-with-prices'); + this.emitSuccess('getAllLedgersWithPricesPrivate', { count: Array.isArray(res.data) ? res.data.length : undefined }); + return res.data as SdkLedger[]; + } catch (error) { + this.emitError('getAllLedgersWithPricesPrivate', error); + throw error; + } + } + + async getLedgerInfoPrivate(idOrCanisterId: string): Promise { + this.requireSecretKey('getLedgerInfoPrivate'); + this.emitStart('getLedgerInfoPrivate', { idOrCanisterId }); + try { + const res = await this.privateApiClient!.get(`/sdk/ledgers/${idOrCanisterId}`); + this.emitSuccess('getLedgerInfoPrivate', { idOrCanisterId }); + return res.data as SdkLedger; + } catch (error) { + this.emitError('getLedgerInfoPrivate', error); + throw error; + } + } + + async getWebhookEventById(id: string): Promise { + this.requireSecretKey('getWebhookEventById'); + this.emitStart('getWebhookEventById', { id }); + try { + const res = await this.privateApiClient!.get(`/sdk/webhook-events/${id}`); + this.emitSuccess('getWebhookEventById', { id }); + return res.data as SdkWebhookEvent; + } catch (error) { + this.emitError('getWebhookEventById', error); + throw error; + } + } + + // ===== Moved secret methods from Icpay ===== + + async getDetailedAccountInfo(): Promise { + this.requireSecretKey('getDetailedAccountInfo'); + this.emitStart('getDetailedAccountInfo'); + try { + const response = await this.privateApiClient!.get('/sdk/account'); + const account = response.data; + const result: AccountInfo = { + id: account.id, + name: account.name, + email: account.email, + isActive: account.isActive, + isLive: account.isLive, + accountCanisterId: account.accountCanisterId, + walletAddress: account.walletAddress, + createdAt: new Date(account.createdAt), + updatedAt: new Date(account.updatedAt), + } as any; + this.emitSuccess('getDetailedAccountInfo', result); + return result; + } catch (error) { + const err = new IcpayError({ + code: 'ACCOUNT_INFO_FETCH_FAILED', + message: 'Failed to fetch detailed account information', + details: error, + }); + this.emitError('getDetailedAccountInfo', err); + throw err; + } + } + + async getTransactionStatus(canisterTransactionId: number): Promise { + this.requireSecretKey('getTransactionStatus'); + this.emitStart('getTransactionStatus', { canisterTransactionId }); + try { + const response = await this.privateApiClient!.get(`/sdk/transactions/${canisterTransactionId}/status`); + const result = response.data; + this.emitSuccess('getTransactionStatus', result); + return result; + } catch (error) { + const err = new IcpayError({ + code: 'TRANSACTION_STATUS_FETCH_FAILED', + message: 'Failed to fetch transaction status', + details: error, + }); + this.emitError('getTransactionStatus', err); + throw err; + } + } + + async getPaymentHistory(request: PaymentHistoryRequest = {}): Promise { + this.requireSecretKey('getPaymentHistory'); + this.emitStart('getPaymentHistory', { request }); + try { + const params = new URLSearchParams(); + if (request.accountId) params.append('accountId', request.accountId); + if (request.ledgerCanisterId) params.append('ledgerCanisterId', request.ledgerCanisterId); + if (request.fromTimestamp) params.append('fromTimestamp', request.fromTimestamp.toISOString()); + if (request.toTimestamp) params.append('toTimestamp', request.toTimestamp.toISOString()); + if (request.status) params.append('status', request.status); + if (request.limit) params.append('limit', request.limit.toString()); + if (request.offset) params.append('offset', request.offset.toString()); + + const response = await this.privateApiClient!.get(`/sdk/payments/history?${params.toString()}`); + const result: PaymentHistoryResponse = { + payments: response.data.payments.map((tx: any) => ({ + id: tx.id, + status: tx.status, + amount: tx.amount, + ledgerCanisterId: tx.ledgerCanisterId, + ledgerSymbol: tx.ledgerSymbol, + fromAddress: tx.fromAddress, + toAddress: tx.toAddress, + fee: tx.fee, + decimals: tx.decimals, + tokenPrice: tx.tokenPrice, + expectedSenderPrincipal: tx.expectedSenderPrincipal, + metadata: tx.metadata, + createdAt: new Date(tx.createdAt), + updatedAt: new Date(tx.updatedAt), + })), + total: response.data.total, + limit: response.data.limit, + offset: response.data.offset, + hasMore: response.data.hasMore, + } as any; + this.emitSuccess('getPaymentHistory', { total: result.total }); + return result; + } catch (error) { + const err = new IcpayError({ + code: 'PAYMENT_HISTORY_FETCH_FAILED', + message: 'Failed to fetch payment history', + details: error, + }); + this.emitError('getPaymentHistory', err); + throw err; + } + } + + async getPaymentsByPrincipal(request: GetPaymentsByPrincipalRequest): Promise { + this.requireSecretKey('getPaymentsByPrincipal'); + this.emitStart('getPaymentsByPrincipal', { request }); + try { + const params = new URLSearchParams(); + if (request.limit) params.append('limit', request.limit.toString()); + if (request.offset) params.append('offset', request.offset.toString()); + if (request.status) params.append('status', request.status); + + const response = await this.privateApiClient!.get(`/sdk/payments/by-principal/${request.principalId}?${params.toString()}`); + const result: PaymentHistoryResponse = { + payments: response.data.payments.map((tx: any) => ({ + id: tx.id, + status: tx.status, + amount: tx.amount, + ledgerCanisterId: tx.ledgerCanisterId, + ledgerSymbol: tx.ledgerSymbol, + fromAddress: tx.fromAddress, + toAddress: tx.toAddress, + fee: tx.fee, + decimals: tx.decimals, + tokenPrice: tx.tokenPrice, + expectedSenderPrincipal: tx.expectedSenderPrincipal, + metadata: tx.metadata, + createdAt: new Date(tx.createdAt), + updatedAt: new Date(tx.updatedAt), + })), + total: response.data.total, + limit: response.data.limit, + offset: response.data.offset, + hasMore: response.data.hasMore, + } as any; + this.emitSuccess('getPaymentsByPrincipal', { total: result.total }); + return result; + } catch (error) { + const err = new IcpayError({ + code: 'PAYMENTS_BY_PRINCIPAL_FETCH_FAILED', + message: 'Failed to fetch payments by principal', + details: error, + }); + this.emitError('getPaymentsByPrincipal', err); + throw err; + } + } + + async getAccountWalletBalances(): Promise { + this.requireSecretKey('getAccountWalletBalances'); + this.emitStart('getAccountWalletBalances'); + try { + const response = await this.privateApiClient!.get('/sdk/account/wallet-balances'); + const result: AllLedgerBalances = { + balances: response.data.balances.map((balance: any) => ({ + ledgerId: balance.ledgerId, + ledgerName: balance.ledgerName, + ledgerSymbol: balance.ledgerSymbol, + canisterId: balance.canisterId, + balance: balance.balance, + formattedBalance: balance.formattedBalance, + decimals: balance.decimals, + currentPrice: balance.currentPrice, + lastPriceUpdate: balance.lastPriceUpdate ? new Date(balance.lastPriceUpdate) : undefined, + lastUpdated: new Date(balance.lastUpdated), + } as LedgerBalance)), + totalBalancesUSD: response.data.totalBalancesUSD, + lastUpdated: new Date(response.data.lastUpdated), + }; + this.emitSuccess('getAccountWalletBalances', { count: result.balances.length, totalUSD: result.totalBalancesUSD }); + return result; + } catch (error) { + const err = new IcpayError({ + code: 'ACCOUNT_WALLET_BALANCES_FETCH_FAILED', + message: 'Failed to fetch account wallet balances', + details: error, + }); + this.emitError('getAccountWalletBalances', err); + throw err; + } + } +} + + diff --git a/src/types/index.ts b/src/types/index.ts index 4c1f47a..9fff614 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -145,9 +145,7 @@ export interface PublicAccountInfo { isActive: boolean; isLive: boolean; accountCanisterId: number; - walletAddress: string | null; - createdAt: Date; - updatedAt: Date; + icpayCanisterId?: string; } export interface IcpayError { @@ -240,6 +238,257 @@ export interface PaymentHistoryResponse { hasMore: boolean; } +// Public SDK responses +export interface PublicCreateIntentResponse { + paymentIntentId: string; + paymentIntentCode: number | null; + payment: PaymentPublic; + paymentIntent: SdkPaymentIntent; +} + +export interface PublicNotifyResponse { + paymentId: string; + paymentIntentId: string | null; + status: PaymentStatus; + canisterTxId: number | null; + transactionId: string | null; +} + +export type PaymentStatus = 'pending' | 'completed' | 'failed' | 'canceled' | 'refunded'; +export type PaymentIntentStatus = 'requires_payment' | 'processing' | 'succeeded' | 'completed' | 'failed' | 'canceled'; +export type InvoiceStatus = 'draft' | 'open' | 'paid' | 'void'; +export type RefundStatus = 'pending' | 'processing' | 'completed' | 'failed' | 'cancelled'; +export type PayoutStatus = 'pending' | 'processing' | 'completed' | 'failed' | 'cancelled'; +export type LedgerStandard = 'ICRC-1' | 'ICRC-2' | 'ICRC-3' | 'ICRC-10' | 'ICRC-21' | 'ICP' | 'EXT'; +export type LedgerNetwork = 'mainnet' | 'testnet'; +export type PriceFetchMethod = 'coingecko' | 'icpswap'; +export type WalletNetwork = 'ic' | 'eth' | 'btc' | 'sol'; +export type WalletType = 'user' | 'platform' | 'canister'; + +export interface AccountPublic { + id: string; + name: string | null; + isActive: boolean; + isLive: boolean; + accountCanisterId: number; + icpayCanisterId?: string; +} + +export interface LedgerPublic { + id: string; + name: string; + symbol: string; + canisterId: string; + decimals: number; + logoUrl: string | null; + verified: boolean; + fee: string | null; + currentPrice: number | null; + lastPriceUpdate: string | null; +} + +export interface PaymentPublic { + id: string; + accountId: string; + paymentIntentId: string; + transactionId: string | null; + canisterTxId: number | null; + amount: string; + ledgerCanisterId: string; + status: PaymentStatus; + invoiceId: string | null; + metadata: Record; + createdAt: string; + updatedAt: string; +} + +export interface SdkLedger { + id: string; + name: string; + symbol: string; + canisterId: string; + standard: LedgerStandard; + decimals: number; + logoUrl: string | null; + verified: boolean; + fee: string | null; + network: LedgerNetwork; + description: string | null; + lastBlockIndex: string | null; + coingeckoId: string | null; + currentPrice: number | null; + priceFetchMethod: PriceFetchMethod | null; + lastPriceUpdate: string | null; + createdAt: string; + updatedAt: string; +} + +export interface SdkPaymentIntent { + id: string; + accountId: string; + amount: string; + ledgerCanisterId: string; + description: string | null; + expectedSenderPrincipal: string | null; + status: PaymentIntentStatus; + metadata: Record; + intentCode: number; + createdAt: string; + updatedAt: string; +} + +export interface SdkPayment { + id: string; + accountId: string; + paymentIntentId: string; + transactionId: string | null; + canisterTxId: number | null; + amount: string; + ledgerCanisterId: string; + status: PaymentStatus; + invoiceId: string | null; + metadata: Record; + createdAt: string; + updatedAt: string; +} + +export interface SdkInvoice { + id: string; + accountId: string; + paymentId: string | null; + invoiceNumber: string | null; + amountDue: string; + amountPaid: string | null; + currency: string | null; + status: InvoiceStatus; + metadata: Record; + createdAt: string; + updatedAt: string; +} + +export interface SdkTransaction { + id: string; + accountId: string; + canisterTxId: number | null; + accountCanisterId: string | null; + senderPrincipalId: string; + transactionType: 'payment' | 'refund' | 'transfer' | 'withdrawal'; + status: 'pending' | 'processing' | 'completed' | 'failed' | 'cancelled'; + amount: string; + accountAmount: string | null; + platformFeeAmount: string | null; + tokenPrice: number | null; + ledgerId: string | null; + ledgerCanisterId: string; + timestamp: number | null; + indexReceived: number | null; + indexToAccount: number | null; + timestampReceived: number | null; + timestampToAccount: number | null; + metadata: Record; + memo: string | null; + processedAt: string | null; + createdAt: string; + updatedAt: string; +} + +export interface SdkRefund { + id: string; + accountId: string; + transactionId: string | null; + canisterRefundId: string | null; + canisterTxId: string | null; + ledgerCanisterId: string | null; + amount: string; + accountAmount: string | null; + platformRefundAmount: string | null; + status: RefundStatus; + statusMessage: string | null; + indexPlatformToAccount: string | null; + indexToSender: string | null; + timestampPlatformToAccount: string | null; + timestampToSender: string | null; + metadata: Record; + createdAt: string; + updatedAt: string; +} + +export interface SdkPayout { + id: string; + accountId: string; + walletId: string | null; + userId: string | null; + amount: string; + ledgerId: string | null; + ledgerCanisterId: string | null; + accountCanisterId: string | null; + fromSubaccount: string | null; + toWalletAddress: string | null; + toWalletSubaccount: string | null; + blockIndex: string | null; + ledgerTxHash: string | null; + status: PayoutStatus; + statusMessage: string | null; + retryCount: number; + ipAddress: string | null; + userAgent: string | null; + metadata: Record; + createdAt: string; + updatedAt: string; +} + +export interface SdkWallet { + id: string; + accountId: string | null; + walletName: string; + walletAddress: string; + network: WalletNetwork; + type: WalletType; + subaccount: string | null; + icpAccountIdentifier: string | null; + isActive: boolean; + isChanged: boolean; + previousAddress: string | null; + isPrimary: boolean; + isInternal: boolean; + createdAt: string; + updatedAt: string; +} + +export interface SdkWebhookEvent { + id: string; + webhookEndpointId: string; + eventType: string; + eventData: any; + endpointUrl: string; + relationName: string | null; + relationId: string | null; + status: 'pending' | 'sent' | 'delivered' | 'failed' | 'cancelled'; + attempts: number; + maxAttempts: number; + nextRetryAt: string | null; + sentAt: string | null; + deliveredAt: string | null; + responseStatus: number | null; + responseHeaders: Record | null; + responseBody: string | null; + requestHeaders: Record | null; + requestBody: string | null; + errorMessage: string | null; + errorCode: string | null; + processingTimeMs: number | null; + signature: string | null; + createdAt: string; + updatedAt: string; +} + +export interface SdkPaymentAggregate { + payment: SdkPayment; + intent: SdkPaymentIntent | null; + invoice: SdkInvoice | null; + transaction: SdkTransaction | null; +} + export interface GetPaymentsByPrincipalRequest { principalId: string; limit?: number;