UNPKG

httpay

Version:

HTTPay SDK for interacting with HTTPay smart contracts on Neutron

540 lines (526 loc) 19 kB
import { CosmWasmClient, SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'; import { DirectSecp256k1Wallet } from '@cosmjs/proto-signing'; import { GasPrice } from '@cosmjs/stargate'; /** * This file was automatically generated by @cosmwasm/ts-codegen@1.12.1. * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, * and run the @cosmwasm/ts-codegen generate command to regenerate this file. */ var EscrowTypes = /*#__PURE__*/Object.freeze({ __proto__: null }); /** * This file was automatically generated by @cosmwasm/ts-codegen@1.12.1. * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, * and run the @cosmwasm/ts-codegen generate command to regenerate this file. */ class EscrowQueryClient { constructor(client, contractAddress) { this.getEscrow = async ({ escrowId, }) => { return this.client.queryContractSmart(this.contractAddress, { get_escrow: { escrow_id: escrowId, }, }); }; this.getCollectedFees = async () => { return this.client.queryContractSmart(this.contractAddress, { get_collected_fees: {}, }); }; this.getEscrows = async ({ caller, limit, provider, startAfter, }) => { return this.client.queryContractSmart(this.contractAddress, { get_escrows: { caller, limit, provider, start_after: startAfter, }, }); }; this.client = client; this.contractAddress = contractAddress; this.getEscrow = this.getEscrow.bind(this); this.getCollectedFees = this.getCollectedFees.bind(this); this.getEscrows = this.getEscrows.bind(this); } } class EscrowClient extends EscrowQueryClient { constructor(client, sender, contractAddress) { super(client, contractAddress); this.lockFunds = async ({ authToken, expires, maxFee, toolId, }, fee_ = "auto", memo_, funds_) => { return await this.client.execute(this.sender, this.contractAddress, { lock_funds: { auth_token: authToken, expires, max_fee: maxFee, tool_id: toolId, }, }, fee_, memo_, funds_); }; this.release = async ({ escrowId, usageFee, }, fee_ = "auto", memo_, funds_) => { return await this.client.execute(this.sender, this.contractAddress, { release: { escrow_id: escrowId, usage_fee: usageFee, }, }, fee_, memo_, funds_); }; this.refundExpired = async ({ escrowId, }, fee_ = "auto", memo_, funds_) => { return await this.client.execute(this.sender, this.contractAddress, { refund_expired: { escrow_id: escrowId, }, }, fee_, memo_, funds_); }; this.claimFees = async ({ denom, }, fee_ = "auto", memo_, funds_) => { return await this.client.execute(this.sender, this.contractAddress, { claim_fees: { denom, }, }, fee_, memo_, funds_); }; this.client = client; this.sender = sender; this.contractAddress = contractAddress; this.lockFunds = this.lockFunds.bind(this); this.release = this.release.bind(this); this.refundExpired = this.refundExpired.bind(this); this.claimFees = this.claimFees.bind(this); } } var EscrowClient$1 = /*#__PURE__*/Object.freeze({ __proto__: null, EscrowClient: EscrowClient, EscrowQueryClient: EscrowQueryClient }); /** * This file was automatically generated by @cosmwasm/ts-codegen@1.12.1. * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, * and run the @cosmwasm/ts-codegen generate command to regenerate this file. */ var RegistryTypes = /*#__PURE__*/Object.freeze({ __proto__: null }); /** * This file was automatically generated by @cosmwasm/ts-codegen@1.12.1. * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, * and run the @cosmwasm/ts-codegen generate command to regenerate this file. */ class RegistryQueryClient { constructor(client, contractAddress) { this.getTool = async ({ toolId }) => { return this.client.queryContractSmart(this.contractAddress, { get_tool: { tool_id: toolId, }, }); }; this.getTools = async () => { return this.client.queryContractSmart(this.contractAddress, { get_tools: {}, }); }; this.client = client; this.contractAddress = contractAddress; this.getTool = this.getTool.bind(this); this.getTools = this.getTools.bind(this); } } class RegistryClient extends RegistryQueryClient { constructor(client, sender, contractAddress) { super(client, contractAddress); this.registerTool = async ({ denom, description, endpoint, price, toolId, }, fee_ = "auto", memo_, funds_) => { return await this.client.execute(this.sender, this.contractAddress, { register_tool: { denom, description, endpoint, price, tool_id: toolId, }, }, fee_, memo_, funds_); }; this.updatePrice = async ({ price, toolId, }, fee_ = "auto", memo_, funds_) => { return await this.client.execute(this.sender, this.contractAddress, { update_price: { price, tool_id: toolId, }, }, fee_, memo_, funds_); }; this.updateDenom = async ({ denom, toolId, }, fee_ = "auto", memo_, funds_) => { return await this.client.execute(this.sender, this.contractAddress, { update_denom: { denom, tool_id: toolId, }, }, fee_, memo_, funds_); }; this.updateEndpoint = async ({ endpoint, toolId, }, fee_ = "auto", memo_, funds_) => { return await this.client.execute(this.sender, this.contractAddress, { update_endpoint: { endpoint, tool_id: toolId, }, }, fee_, memo_, funds_); }; this.pauseTool = async ({ toolId, }, fee_ = "auto", memo_, funds_) => { return await this.client.execute(this.sender, this.contractAddress, { pause_tool: { tool_id: toolId, }, }, fee_, memo_, funds_); }; this.resumeTool = async ({ toolId, }, fee_ = "auto", memo_, funds_) => { return await this.client.execute(this.sender, this.contractAddress, { resume_tool: { tool_id: toolId, }, }, fee_, memo_, funds_); }; this.client = client; this.sender = sender; this.contractAddress = contractAddress; this.registerTool = this.registerTool.bind(this); this.updatePrice = this.updatePrice.bind(this); this.updateDenom = this.updateDenom.bind(this); this.updateEndpoint = this.updateEndpoint.bind(this); this.pauseTool = this.pauseTool.bind(this); this.resumeTool = this.resumeTool.bind(this); } } var RegistryClient$1 = /*#__PURE__*/Object.freeze({ __proto__: null, RegistryClient: RegistryClient, RegistryQueryClient: RegistryQueryClient }); /** * High-level HTTPay provider class that simplifies contract interactions */ class HTTPayProvider { constructor(config, tool) { this.config = config; this.tool = tool; } /** * Initialize the provider with blockchain connections */ async initialize() { // Create CosmWasm client this.cosmWasmClient = await CosmWasmClient.connect(this.config.rpcEndpoint); // Create signing client with provider wallet const { client, address } = await this.createSigningClient(); this.signingClient = client; this.providerAddress = address; } /** * Validate payment credentials (escrow ID and auth token) */ async validatePayment(payment) { if (!this.cosmWasmClient) { throw new Error('HTTPayProvider not initialized. Call initialize() first.'); } try { const escrowId = typeof payment.escrowId === 'string' ? parseInt(payment.escrowId, 10) : payment.escrowId; if (isNaN(escrowId)) { return { isValid: false, error: 'Invalid escrowId format - must be a number' }; } const escrowQueryClient = new EscrowQueryClient(this.cosmWasmClient, this.config.escrowAddress); const escrowResponse = await escrowQueryClient.getEscrow({ escrowId: escrowId }); // Validate auth token (simple comparison for now) if (escrowResponse.auth_token !== payment.authToken) { return { isValid: false, error: 'Invalid authentication token' }; } // Check if funds are sufficient (escrow exists means it's active) const maxFee = parseFloat(escrowResponse.max_fee || '0'); if (maxFee <= 0) { return { isValid: false, error: 'Insufficient funds in escrow' }; } return { isValid: true, escrow: { id: escrowId, provider: escrowResponse.provider || '', maxFee: escrowResponse.max_fee || '0', expires: escrowResponse.expires } }; } catch (error) { return { isValid: false, error: error instanceof Error ? error.message : 'Unknown validation error' }; } } /** * Get tool pricing from registry */ async getToolPrice() { if (!this.cosmWasmClient) { throw new Error('HTTPayProvider not initialized. Call initialize() first.'); } try { const registryQueryClient = new RegistryQueryClient(this.cosmWasmClient, this.config.registryAddress); const toolResponse = await registryQueryClient.getTool({ toolId: this.tool.toolId }); if (!toolResponse?.price) { return { error: 'Tool price not found in registry' }; } return { price: toolResponse.price }; } catch (error) { return { error: error instanceof Error ? error.message : 'Failed to fetch tool price' }; } } /** * Process payment by releasing escrow funds */ async processPayment(escrowId, usageFee) { if (!this.signingClient || !this.providerAddress) { throw new Error('HTTPayProvider not initialized. Call initialize() first.'); } try { const escrowClient = new EscrowClient(this.signingClient, this.providerAddress, this.config.escrowAddress); const result = await escrowClient.release({ escrowId: escrowId, usageFee: usageFee }, 'auto'); return { success: true, txHash: result.transactionHash, fee: usageFee }; } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Payment processing failed' }; } } /** * Complete payment flow: validate + process */ async handlePayment(payment) { // Step 1: Validate payment credentials const validation = await this.validatePayment(payment); if (!validation.isValid) { return { validation }; } // Step 2: Get tool price const priceResult = await this.getToolPrice(); if (priceResult.error) { return { validation: { isValid: false, error: `Failed to get tool price: ${priceResult.error}` } }; } // Step 3: Process payment const escrowId = typeof payment.escrowId === 'string' ? parseInt(payment.escrowId, 10) : payment.escrowId; const processing = await this.processPayment(escrowId, priceResult.price); return { validation, processing, price: priceResult.price }; } /** * Private helper to create signing client */ async createSigningClient() { const privateKey = this.tool.provider.privateKey; if (!privateKey || !/^[0-9a-fA-F]{64}$/.test(privateKey)) { throw new Error('Invalid private key. Must be a 64-character hex string.'); } const privateKeyBytes = new Uint8Array(privateKey.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16)) || []); const wallet = await DirectSecp256k1Wallet.fromKey(privateKeyBytes, 'neutron'); const [providerAccount] = await wallet.getAccounts(); const gasPrice = this.config.gasPrice || '0.025untrn'; const client = await SigningCosmWasmClient.connectWithSigner(this.config.rpcEndpoint, wallet, { gasPrice: GasPrice.fromString(gasPrice) }); return { client, address: providerAccount.address }; } } /** * Environment-based configuration utility */ class HTTPayConfigBuilder { constructor() { this.config = {}; this.tool = {}; } /** * Load configuration from environment variables */ static fromEnvironment() { const builder = new HTTPayConfigBuilder(); // Load HTTPay config from environment if (process.env.NEXT_PUBLIC_RPC_ENDPOINT) { builder.config.rpcEndpoint = process.env.NEXT_PUBLIC_RPC_ENDPOINT; } if (process.env.NEXT_PUBLIC_REGISTRY_ADDRESS) { builder.config.registryAddress = process.env.NEXT_PUBLIC_REGISTRY_ADDRESS; } if (process.env.NEXT_PUBLIC_ESCROW_ADDRESS) { builder.config.escrowAddress = process.env.NEXT_PUBLIC_ESCROW_ADDRESS; } if (process.env.NEXT_PUBLIC_CHAIN_ID) { builder.config.chainId = process.env.NEXT_PUBLIC_CHAIN_ID; } if (process.env.NEXT_PUBLIC_GAS_PRICE) { builder.config.gasPrice = process.env.NEXT_PUBLIC_GAS_PRICE; } // Load tool config from environment if (process.env.CLIENT_PRIVATE_KEY) { builder.tool.provider = { privateKey: process.env.CLIENT_PRIVATE_KEY }; } return builder; } /** * Set RPC endpoint */ rpcEndpoint(endpoint) { this.config.rpcEndpoint = endpoint; return this; } /** * Set contract addresses */ contracts(registryAddress, escrowAddress) { this.config.registryAddress = registryAddress; this.config.escrowAddress = escrowAddress; return this; } /** * Set chain configuration */ chain(chainId, gasPrice, gasAdjustment) { this.config.chainId = chainId; if (gasPrice) this.config.gasPrice = gasPrice; if (gasAdjustment) this.config.gasAdjustment = gasAdjustment; return this; } /** * Set tool configuration */ setTool(toolId, privateKey) { this.tool.toolId = toolId; this.tool.provider = { privateKey }; return this; } /** * Build the final configuration objects */ build() { // Validate required fields const requiredConfigFields = [ 'rpcEndpoint', 'registryAddress', 'escrowAddress' ]; for (const field of requiredConfigFields) { if (!this.config[field]) { throw new Error(`Missing required config field: ${field}`); } } if (!this.tool.toolId) { throw new Error('Missing required tool field: toolId'); } if (!this.tool.provider?.privateKey) { throw new Error('Missing required tool field: provider.privateKey'); } return { config: { rpcEndpoint: this.config.rpcEndpoint, registryAddress: this.config.registryAddress, escrowAddress: this.config.escrowAddress, chainId: this.config.chainId || 'pion-1', gasPrice: this.config.gasPrice || '0.025untrn', gasAdjustment: this.config.gasAdjustment || 1.3 }, tool: { toolId: this.tool.toolId, provider: this.tool.provider } }; } } /** * Preset configurations for common networks */ const HTTPayPresets = { neutronTestnet: { rpcEndpoint: "https://rpc-falcron.pion-1.ntrn.tech", chainId: "pion-1", gasPrice: "0.0053untrn", gasAdjustment: 1.3, // Contract addresses would need to be provided registryAddress: "", escrowAddress: "" }, neutronMainnet: { rpcEndpoint: "https://neutron-rpc.publicnode.com", chainId: "neutron-1", gasPrice: "0.0053untrn", gasAdjustment: 1.3, // Contract addresses would need to be provided registryAddress: "", escrowAddress: "" } }; /** * Quick configuration helper */ function createHTTPPayConfig(preset, addresses) { return { ...HTTPayPresets[preset], ...addresses }; } /** * Organized namespace exports for HTTPay SDK (Core only - no React dependencies) */ const Escrow = { ...EscrowTypes, ...EscrowClient$1, }; const Registry = { ...RegistryTypes, ...RegistryClient$1, }; // Default export with all contracts var namespace = { Escrow, Registry, }; var namespace$1 = /*#__PURE__*/Object.freeze({ __proto__: null, Escrow: Escrow, Registry: Registry, default: namespace }); export { EscrowClient, EscrowQueryClient, EscrowTypes, namespace$1 as HTTPay, HTTPayConfigBuilder, HTTPayPresets, HTTPayProvider, RegistryClient, RegistryQueryClient, RegistryTypes, createHTTPPayConfig }; //# sourceMappingURL=index.esm.js.map