diff --git a/.github/workflows/merge-when-green.yml b/.github/workflows/merge-when-green.yml deleted file mode 100644 index 190381d..0000000 --- a/.github/workflows/merge-when-green.yml +++ /dev/null @@ -1,86 +0,0 @@ -name: Merge PR when checks pass - -on: - pull_request_target: - types: [opened, reopened, synchronize, ready_for_review] - workflow_dispatch: - -permissions: - pull-requests: write - contents: write - -jobs: - merge-when-green: - if: | - (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') || - (github.event_name == 'pull_request') - runs-on: ubuntu-latest - steps: - - name: Identify PR - id: find_pr - uses: actions/github-script@v7 - with: - script: | - let pr = context.payload.pull_request; - if (!pr) { - core.info('No PR to consider.'); - core.setOutput('pr_number', ''); - return; - } - core.setOutput('pr_number', pr.number.toString()); - - - name: Attempt merge if green - if: steps.find_pr.outputs.pr_number != '' - uses: actions/github-script@v7 - with: - script: | - // Check if github object is available - if (!github) { - core.setFailed('GitHub API is not available in this context'); - return; - } - - const prNumber = parseInt('${{ steps.find_pr.outputs.pr_number }}', 10); - - try { - const { data: pr } = await github.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNumber, - }); - - if (pr.draft) { - core.info(`PR #${prNumber} is draft. Skipping.`); - return; - } - if (pr.state !== 'open') { - core.info(`PR #${prNumber} is not open. Skipping.`); - return; - } - if (!['master','main'].includes(pr.base.ref)) { - core.info(`PR #${prNumber} base is ${pr.base.ref}, not master/main. Skipping.`); - return; - } - - const { data: prDetails } = await github.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNumber, - }); - - if (prDetails.mergeable_state !== 'clean' && prDetails.mergeable_state !== 'has_hooks') { - core.info(`PR #${prNumber} mergeable_state=${prDetails.mergeable_state}. Not clean yet.`); - return; - } - - await github.pulls.merge({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNumber, - merge_method: 'merge', - }); - core.info(`Merged PR #${prNumber}.`); - } catch (e) { - core.info(`Merge attempt failed (likely required checks/approvals unmet): ${e.message}`); - } - diff --git a/README.md b/README.md index 4becacf..abb8fdc 100644 --- a/README.md +++ b/README.md @@ -1,490 +1,32 @@ # ICPay SDK -Official SDK for Internet Computer payments with account-based authentication and wallet integration. - -## Version History - -### v1.3.37 (Latest) -- Added debug configuration option for development and troubleshooting -- All console.log statements now respect the debug setting -- Improved logging for transaction flow and API operations - -### v1.3.2 -- Initial release with user-based authentication +Official SDK for integrating Internet Computer payments with ICPay. ## Installation +Using pnpm: ```bash -npm install @icpay/sdk -``` - -## Quick Start - -### Frontend Usage (Public Mode) -```typescript -import Icpay from '@icpay/sdk'; - -const icpay = new Icpay({ - publishableKey: 'pk_live_your_publishable_key_here', - environment: 'production' -}); - -// Safe for client-side -const accountInfo = await icpay.getAccountInfo(); -const ledgers = await icpay.getVerifiedLedgers(); -const priceCalc = await icpay.calculateTokenAmountFromUSD({ - usdAmount: 100, - ledgerCanisterId: 'ryjl3-tyaaa-aaaaa-aaaba-cai' -}); - -// Connect wallet for balance and transaction operations -await icpay.connectWallet('internet-identity'); -``` - -### Server-Side Usage (Private Mode) -```typescript -import Icpay from '@icpay/sdk'; - -const icpay = new Icpay({ - secretKey: 'sk_live_your_secret_key_here', - environment: 'production' -}); - -// Server-side operations -const transactions = await icpay.protected.getTransactionHistory(); -const accountBalances = await icpay.protected.getAccountWalletBalances(); -``` - -## Authentication Modes - -The SDK supports two authentication modes: - -### Public Mode (Frontend-Safe) -Use `publishableKey` for client-side applications: - -```typescript -const icpay = new Icpay({ - publishableKey: 'pk_live_your_publishable_key_here', - environment: 'production' -}); -``` - -**Available in Public Mode:** -- `getAccountInfo()` - Basic account information -- `getVerifiedLedgers()` - Ledger list with prices -- `getLedgerInfo()` - Individual ledger details -- `getAllLedgersWithPrices()` - All ledgers with pricing -- `calculateTokenAmountFromUSD()` - Price calculations -- `getAllLedgerBalances()` - All ledger balances (with connected wallet) -- `getSingleLedgerBalance()` - Single ledger balance (with connected wallet) -- `sendFunds()` - Send funds to canister -- `sendFundsUsd()` - Send funds using USD amounts -- Wallet connection and balance checking (with connected wallet) - -### Private Mode (Server-Side) -Use `secretKey` for server-side operations: - -```typescript -const icpay = new Icpay({ - secretKey: 'sk_live_your_secret_key_here', - environment: 'production' -}); -``` - -**Available in Private Mode:** -- All public methods -- `getDetailedAccountInfo()` - Full account data -- `getTransactionStatus()` - Transaction status by ID -- `getTransactionHistory()` - Transaction data with filtering -- `getAccountWalletBalances()` - Detailed balance info - -## Enhanced Features - -### 1. Balance Management - -#### Get All Ledger Balances -Fetch balances for all verified ledgers for the connected wallet: - -```typescript -// Connect wallet first -await icpay.connectWallet('internet-identity'); - -// Get all balances -const allBalances = await icpay.getAllLedgerBalances(); -console.log('Total USD Value:', allBalances.totalBalancesUSD); -console.log('Balances:', allBalances.balances.map(b => ({ - symbol: b.ledgerSymbol, - balance: b.formattedBalance, - usdValue: b.currentPrice ? - (parseFloat(b.formattedBalance) * b.currentPrice).toFixed(2) : 'N/A' -}))); -``` - -#### Get Single Ledger Balance -Fetch balance for a specific ledger: - -```typescript -const icpBalance = await icpay.getSingleLedgerBalance('ryjl3-tyaaa-aaaaa-aaaba-cai'); -console.log('ICP Balance:', { - balance: icpBalance.formattedBalance, - usdValue: icpBalance.currentPrice ? - (parseFloat(icpBalance.formattedBalance) * icpBalance.currentPrice).toFixed(2) : 'N/A' -}); -``` - -### 2. Price Calculation - -Convert USD amounts to token amounts using real-time pricing: - -```typescript -const priceCalculation = await icpay.calculateTokenAmountFromUSD({ - usdAmount: 100, // $100 USD - ledgerCanisterId: 'ryjl3-tyaaa-aaaaa-aaaba-cai' // ICP ledger -}); - -console.log('Token Amount:', { - humanReadable: priceCalculation.tokenAmountHuman, // "1.5 ICP" - inDecimals: priceCalculation.tokenAmountDecimals, // "150000000" - currentPrice: priceCalculation.currentPrice, - priceTimestamp: priceCalculation.priceTimestamp -}); -``` - -### 3. Transaction History - -Get detailed transaction history with filtering: - -```typescript -const history = await icpay.getTransactionHistory({ - limit: 20, - offset: 0, - status: 'completed', - fromTimestamp: new Date('2024-01-01'), - toTimestamp: new Date() -}); - -console.log('Transactions:', history.transactions.map(tx => ({ - id: tx.id, - amount: tx.amount, - currency: tx.currency, - status: tx.status, - createdAt: tx.createdAt -}))); -``` - -### 4. USD-Based Payments - -Send funds using USD amounts with automatic token conversion: - -```typescript -const payment = await icpay.sendFundsUsd({ - usdAmount: 5.25, // $5.25 USD - ledgerCanisterId: 'ryjl3-tyaaa-aaaaa-aaaba-cai', - metadata: { - orderId: 'order-123', - customerEmail: 'customer@example.com' - } -}); - -console.log('Payment sent:', { - transactionId: payment.transactionId, - status: payment.status, - amount: payment.amount, - timestamp: payment.timestamp -}); -``` - -### 5. Enhanced Ledger Information - -Get detailed ledger information including price data: - -```typescript -const ledgerInfo = await icpay.getLedgerInfo('ryjl3-tyaaa-aaaaa-aaaba-cai'); -console.log('Ledger Info:', { - name: ledgerInfo.name, - symbol: ledgerInfo.symbol, - currentPrice: ledgerInfo.currentPrice, - lastPriceUpdate: ledgerInfo.lastPriceUpdate -}); -``` - -## Connected Wallet Integration - -When using your own wallet connector instead of Plug N Play, provide a `connectedWallet` object: - -```typescript -interface ConnectedWallet { - /** - * The principal/owner of the wallet (string format) - * Required for balance checking and transaction operations - */ - owner?: string; - - /** - * The principal of the wallet (Principal object format) - * Alternative to owner property - */ - principal?: any; // Principal type from @dfinity/principal - - /** - * Whether the wallet is currently connected - * Used to determine connection status - */ - connected?: boolean; - - /** - * Optional method to get the principal - * Alternative to owner/principal properties - */ - getPrincipal?: () => string | any; -} -``` - -**Minimum Requirements:** -- Provide either `owner` (string) or `principal` (Principal object) for balance checking -- Provide `connected` property or implement `getPrincipal()` method for connection status -- For transaction signing, provide `actorProvider` function that returns an actor with signing capabilities - -**Example with Plug N Play:** -```typescript -const icpay = new Icpay({ - publishableKey: 'pk_live_your_key', - connectedWallet: account, // Plug N Play account object - actorProvider: getActor, // Plug N Play actor provider -}); -``` - -**Example with custom wallet:** -```typescript -const icpay = new Icpay({ - publishableKey: 'pk_live_your_key', - connectedWallet: { - owner: 'your-principal-string', - connected: true - }, - actorProvider: (canisterId, idl) => { - // Return your custom actor with signing capabilities - return createActor(canisterId, idl); - } -}); -``` - -## Configuration - -```typescript -interface IcpayConfig { - // For public operations (frontend-safe) - publishableKey?: string; - - // For private operations (server-side only) - secretKey?: string; - - environment?: 'development' | 'production'; - apiUrl?: string; - icHost?: string; - - // Wallet configuration - usePlugNPlay?: boolean; - plugNPlayConfig?: Record; - connectedWallet?: ConnectedWallet; - actorProvider?: (canisterId: string, idl: any) => ActorSubclass; - - // Debug configuration - debug?: boolean; -} -``` -``` - -**Note:** Either `publishableKey` (public mode) or `secretKey` (private mode) must be provided. - -### Debug Configuration - -The SDK includes a debug mode that can be enabled to output detailed console logs for development and troubleshooting: - -```typescript -const icpay = new Icpay({ - publishableKey: 'pk_live_your_key_here', - debug: true // Enable debug logging -}); -``` - -**Debug Mode Features:** -- Detailed logging of all SDK operations -- Transaction flow tracking -- API request/response logging -- Wallet connection debugging -- Balance checking logs - -**Usage:** -- **Development**: Set `debug: true` to see detailed operation logs -- **Production**: Leave `debug` unset or set to `false` (default) to avoid console clutter -- **Troubleshooting**: Enable debug mode to diagnose issues with transactions or wallet connections - -**Example Output:** -``` -[ICPay SDK] constructor { config: {...} } -[ICPay SDK] sendFunds start { request: {...} } -[ICPay SDK] checking balance { ledgerCanisterId: "...", requiredAmount: "..." } -[ICPay SDK] balance ok { actualBalance: "..." } -[ICPay SDK] creating payment intent -[ICPay SDK] payment intent created { paymentIntentId: "...", paymentIntentCode: ... } -[ICPay SDK] sendFunds done { transactionId: ..., status: "completed" } -``` - -## API Reference - -### Account Methods - -#### `getAccountInfo(): Promise` -Get basic account information (public method). - -#### `getDetailedAccountInfo(): Promise` -Get detailed account information (private method). - -### Ledger Methods - -#### `getVerifiedLedgers(): Promise` -Get list of verified ledgers with price information. - -#### `getLedgerInfo(ledgerCanisterId: string): Promise` -Get detailed information for a specific ledger. - -#### `getAllLedgersWithPrices(): Promise` -Get all ledgers with current price information. - -### Balance Methods - -#### `getAllLedgerBalances(): Promise` -Get balances for all verified ledgers (requires connected wallet). - -#### `getSingleLedgerBalance(ledgerCanisterId: string): Promise` -Get balance for a specific ledger (requires connected wallet). - -#### `getLedgerBalance(ledgerCanisterId: string): Promise` -Get raw balance for a specific ledger (requires connected wallet). - -#### `getAccountWalletBalances(): Promise` -Get account wallet balances from API (private method). - -### Transaction Methods - -#### `sendFunds(request: CreateTransactionRequest): Promise` -Send funds to a specific ledger. - -#### `sendFundsUsd(request: SendFundsUsdRequest): Promise` -Send funds using USD amount with automatic conversion. - -#### `getTransactionStatus(canisterTransactionId: number): Promise` -Get transaction status by canister transaction ID (private method). - -#### `getTransactionHistory(request?: TransactionHistoryRequest): Promise` -Get transaction history for the account with optional filtering (private method). - -### Price Methods - -#### `calculateTokenAmountFromUSD(request: PriceCalculationRequest): Promise` -Calculate token amount from USD price for a specific ledger. - -### Wallet Methods - -#### `showWalletModal(): Promise` -Show wallet connection modal. - -#### `connectWallet(providerId: string): Promise` -Connect to a specific wallet provider. - -#### `disconnectWallet(): Promise` -Disconnect from wallet. - -#### `isWalletConnected(): boolean` -Check if wallet is connected. - -#### `getAccountAddress(): string` -Get the connected wallet's account address. - -### Types - -#### `VerifiedLedger` -```typescript -interface VerifiedLedger { - id: string; - name: string; - symbol: string; - canisterId: string; - decimals: number; - logoUrl: string | null; - verified: boolean; - fee: string | null; - currentPrice?: number | null; - lastPriceUpdate?: string | null; -} -``` - -#### `LedgerBalance` -```typescript -interface LedgerBalance { - ledgerId: string; - ledgerName: string; - ledgerSymbol: string; - canisterId: string; - balance: string; // Raw balance in smallest unit - formattedBalance: string; // Human readable balance - decimals: number; - currentPrice?: number; // USD price if available - lastPriceUpdate?: Date; - lastUpdated: Date; -} +pnpm add @icpay/sdk ``` -#### `PriceCalculationResult` -```typescript -interface PriceCalculationResult { - usdAmount: number; - ledgerCanisterId: string; - ledgerSymbol: string; - ledgerName: string; - currentPrice: number; - priceTimestamp: Date; - tokenAmountHuman: string; // Human readable amount (e.g., "1.5 ICP") - tokenAmountDecimals: string; // Amount in smallest unit (e.g., "150000000") - decimals: number; -} +Using yarn: +```bash +yarn add @icpay/sdk ``` -#### `SendFundsUsdRequest` -```typescript -interface SendFundsUsdRequest { - usdAmount: string | number; - ledgerCanisterId: string; - accountCanisterId?: string; // Optional, will be fetched if not provided - metadata?: Record; -} +Using npm: +```bash +npm install @icpay/sdk ``` -## Examples - -See the `examples/` directory for comprehensive usage examples: +## Documentation -- `basic-usage.ts` - Basic SDK functionality -- `public-usage.ts` - Frontend-safe operations with publishable key -- `enhanced-usage.ts` - Server-side operations with secret key +For full usage guides, configuration, API reference, and examples, see the ICPay documentation: [ICPay Docs](https://docs.icpay.org). -## Error Handling - -The SDK uses a consistent error handling pattern: - -```typescript -try { - const balances = await icpay.getAllLedgerBalances(); -} catch (error) { - if (error instanceof IcpayError) { - console.error('ICPay Error:', error.code, error.message); - } else { - console.error('Unexpected error:', error); - } -} -``` +## Basic Info -## Support +- Works in browser and Node.js environments +- TypeScript-ready with bundled types +- Supports public (publishable key) and private (secret key) usage -For support and questions, please refer to the ICPay documentation or contact the development team. \ No newline at end of file +If you need help getting started, the step-by-step guides and examples on the [ICPay Docs](https://docs.icpay.org) cover common setups and advanced scenarios. \ No newline at end of file diff --git a/SEND_FUNDS_QUICKSTART.md b/SEND_FUNDS_QUICKSTART.md deleted file mode 100644 index 1af5ef3..0000000 --- a/SEND_FUNDS_QUICKSTART.md +++ /dev/null @@ -1,51 +0,0 @@ -## ICPay SDK — Send Funds Quickstart - -A minimal example to initialize the ICPay SDK and create a payment using `sendFunds`. - -### 1) Install - -```bash -npm install @icpay/sdk -``` - -### 2) Initialize and send funds (frontend-safe) - -```typescript -import Icpay from '@icpay/sdk'; - -async function main() { - // 1) Create SDK instance using your publishable key - const icpay = new Icpay({ - publishableKey: 'pk_live_your_publishable_key_here' - }); - - await icpay.connectWallet('internet-identity'); - - const payment = await icpay.sendFunds({ - ledgerCanisterId: await icpay.getLedgerCanisterIdBySymbol('ICP'), - amount: '10000000', // 0.1 ICP - metadata: { - orderId: 'order-123', - note: 'Example payment' - } - }); - - console.log('Payment sent:', { - transactionId: payment.transactionId, - status: payment.status, - amount: payment.amount, - timestamp: payment.timestamp - }); -} - -main().catch(console.error); -``` - -### Notes - -- `ledgerCanisterId` above is the ICP mainnet ledger. Use another verified ledger ID as needed. -- `amount` must be provided in the smallest unit (e8s for ICP). -- To send by USD instead of token units, use `sendFundsUsd({ usdAmount, ledgerCanisterId, metadata })`. -- For server-side usage, initialize with `secretKey` instead of `publishableKey`. - - diff --git a/package.json b/package.json index afea622..5d708ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@icpay/sdk", - "version": "1.3.57", + "version": "1.3.58", "description": "Official icpay SDK for Internet Computer payments", "main": "dist/index.js", "types": "dist/index.d.ts",