UNPKG

@ckboost/client

Version:

TypeScript/JavaScript SDK for dApps to integrate CKBoost - Fast ck-token transactions on Internet Computer through liquidity pools

396 lines (389 loc) 14.3 kB
import { HttpAgent, Actor } from '@dfinity/agent'; import { Principal } from '@dfinity/principal'; // src/ck-testbtc-client.ts // src/candid/ck-testbtc/backend.did.js var idlFactory = ({ IDL }) => { const BoostId = IDL.Nat; const BoostStatus2 = IDL.Variant({ "active": IDL.Null, "cancelled": IDL.Null, "pending": IDL.Null, "completed": IDL.Null }); const Amount = IDL.Nat; const Timestamp = IDL.Int; const Subaccount = IDL.Vec(IDL.Nat8); const BoostRequest2 = IDL.Record({ "id": BoostId, "status": BoostStatus2, "receivedBTC": Amount, "confirmationsRequired": IDL.Nat, "owner": IDL.Principal, "maxFeePercentage": IDL.Float64, "createdAt": Timestamp, "subaccount": Subaccount, "booster": IDL.Opt(IDL.Principal), "updatedAt": Timestamp, "btcAddress": IDL.Opt(IDL.Text), "amount": Amount, "preferredBooster": IDL.Opt(IDL.Principal) }); const Result = IDL.Variant({ "ok": BoostRequest2, "err": IDL.Text }); const BoosterAccount = IDL.Record({ "availableBalance": Amount, "owner": IDL.Principal, "createdAt": Timestamp, "subaccount": Subaccount, "updatedAt": Timestamp, "totalDeposited": Amount }); const Result_2 = IDL.Variant({ "ok": IDL.Text, "err": IDL.Text }); const Result_1 = IDL.Variant({ "ok": BoosterAccount, "err": IDL.Text }); const Main = IDL.Service({ "acceptBoostRequest": IDL.Func([BoostId], [IDL.Text], []), "checkBTCDeposit": IDL.Func([BoostId], [Result], []), "getAllBoostRequests": IDL.Func([], [IDL.Vec(BoostRequest2)], ["query"]), "getAllBoosterAccounts": IDL.Func( [], [IDL.Vec(BoosterAccount)], ["query"] ), "getBoostRequest": IDL.Func([BoostId], [IDL.Opt(BoostRequest2)], ["query"]), "getBoostRequestBTCAddress": IDL.Func([BoostId], [Result_2], []), "getBoosterAccount": IDL.Func( [IDL.Principal], [IDL.Opt(BoosterAccount)], ["query"] ), "getCanisterPrincipal": IDL.Func([], [IDL.Principal], ["query"]), "getDirectBTCAddress": IDL.Func([], [IDL.Text], []), "getPendingBoostRequests": IDL.Func( [], [IDL.Vec(BoostRequest2)], ["query"] ), "getUserBoostRequests": IDL.Func( [IDL.Principal], [IDL.Vec(BoostRequest2)], ["query"] ), "registerBoostRequest": IDL.Func( [Amount, IDL.Float64, IDL.Nat, IDL.Opt(IDL.Principal)], [Result], [] ), "registerBoosterAccount": IDL.Func([], [Result_1], []), "updateBoosterDeposit": IDL.Func([IDL.Principal, Amount], [Result_1], []), "updateReceivedBTC": IDL.Func([BoostId, Amount], [Result], []), "withdrawBoosterFunds": IDL.Func([Amount], [IDL.Text], []) }); return Main; }; // src/candid/ck-testbtc/index.js var canisterId = process.env.CANISTER_ID_BACKEND; var createActor = (canisterId2, options = {}) => { const agent = options.agent || new HttpAgent({ ...options.agentOptions }); if (options.agent && options.agentOptions) { console.warn( "Detected both agent and agentOptions passed to createActor. Ignoring agentOptions and proceeding with the provided agent." ); } if (process.env.DFX_NETWORK !== "ic") { agent.fetchRootKey().catch((err) => { console.warn( "Unable to fetch root key. Check to ensure that your local replica is running" ); console.error(err); }); } return Actor.createActor(idlFactory, { agent, canisterId: canisterId2, ...options.actorOptions }); }; canisterId ? createActor(canisterId) : void 0; // src/types.ts var SupportedToken = /* @__PURE__ */ ((SupportedToken2) => { SupportedToken2["ckTESTBTC"] = "ckTESTBTC"; return SupportedToken2; })(SupportedToken || {}); var TOKEN_CONFIGS = { ["ckTESTBTC" /* ckTESTBTC */]: { token: "ckTESTBTC" /* ckTESTBTC */, backendCanisterId: "75egi-7qaaa-aaaao-qj6ma-cai", ledgerCanisterId: "mc6ru-gyaaa-aaaar-qaaaq-cai", minimumAmount: "0.005", maximumAmount: "1.0", standardFee: "0.00001", confirmationsRequired: 2, blockExplorerUrl: "https://mempool.space/testnet4", decimals: 8, isTestnet: true } }; var BoostStatus = /* @__PURE__ */ ((BoostStatus2) => { BoostStatus2["PENDING"] = "pending"; BoostStatus2["ACTIVE"] = "active"; BoostStatus2["COMPLETED"] = "completed"; BoostStatus2["CANCELLED"] = "cancelled"; return BoostStatus2; })(BoostStatus || {}); var CKBoostErrorType = /* @__PURE__ */ ((CKBoostErrorType2) => { CKBoostErrorType2["NETWORK_ERROR"] = "NETWORK_ERROR"; CKBoostErrorType2["INVALID_AMOUNT"] = "INVALID_AMOUNT"; CKBoostErrorType2["INVALID_TOKEN"] = "INVALID_TOKEN"; CKBoostErrorType2["REQUEST_NOT_FOUND"] = "REQUEST_NOT_FOUND"; CKBoostErrorType2["REQUEST_EXPIRED"] = "REQUEST_EXPIRED"; CKBoostErrorType2["CANISTER_ERROR"] = "CANISTER_ERROR"; CKBoostErrorType2["VALIDATION_ERROR"] = "VALIDATION_ERROR"; return CKBoostErrorType2; })(CKBoostErrorType || {}); var CKBoostError = class extends Error { constructor(type, message, details) { super(message); this.type = type; this.details = details; this.name = "CKBoostError"; } }; // src/ck-testbtc-client.ts var ckTESTBTCClient = class { constructor(config = {}) { this.tokenConfig = TOKEN_CONFIGS["ckTESTBTC" /* ckTESTBTC */]; this.config = { host: config.host || "https://icp-api.io", timeout: config.timeout || 3e4 }; this.agent = new HttpAgent({ host: this.config.host }); this.backend = createActor(this.tokenConfig.backendCanisterId, { agent: this.agent }); if (this.tokenConfig.isTestnet || this.config.host.includes("localhost")) { this.agent.fetchRootKey().catch((err) => { console.warn("Failed to fetch root key:", err); }); } } /** * Generate a deposit address for a ckTESTBTC boost request * * This function: * 1. Validates the input parameters * 2. Calls registerBoostRequest on the backend * 3. Gets the deposit address for the request * 4. Returns formatted deposit information */ async generateDepositAddress(params) { try { const amount = parseFloat(params.amount); const minAmount = parseFloat(this.tokenConfig.minimumAmount); const maxAmount = parseFloat(this.tokenConfig.maximumAmount); if (amount < minAmount) { throw new CKBoostError( "INVALID_AMOUNT" /* INVALID_AMOUNT */, `Amount ${params.amount} is below minimum ${this.tokenConfig.minimumAmount}` ); } if (amount > maxAmount) { throw new CKBoostError( "INVALID_AMOUNT" /* INVALID_AMOUNT */, `Amount ${params.amount} exceeds maximum ${this.tokenConfig.maximumAmount}` ); } if (params.maxFeePercentage < 0.1 || params.maxFeePercentage > 2) { throw new CKBoostError( "VALIDATION_ERROR" /* VALIDATION_ERROR */, "Fee percentage must be between 0.1% and 2.0%" ); } const amountRaw = BigInt(Math.floor(amount * Math.pow(10, this.tokenConfig.decimals))); const confirmationsRequired = BigInt(params.confirmationsRequired || this.tokenConfig.confirmationsRequired); const preferredBooster = params.preferredBooster ? [Principal.fromText(params.preferredBooster)] : []; const registerResult = await this.backend.registerBoostRequest( amountRaw, params.maxFeePercentage, confirmationsRequired, preferredBooster ); if ("err" in registerResult) { throw new CKBoostError( "CANISTER_ERROR" /* CANISTER_ERROR */, `Failed to register boost request: ${registerResult.err}` ); } const boostRequest = registerResult.ok; const requestId = boostRequest.id.toString(); const addressResult = await this.backend.getBoostRequestBTCAddress(boostRequest.id); if ("err" in addressResult) { throw new CKBoostError( "CANISTER_ERROR" /* CANISTER_ERROR */, `Failed to get deposit address: ${addressResult.err}` ); } const depositAddressValue = addressResult.ok; const depositAddress = { requestId, address: depositAddressValue, amount: params.amount, amountRaw: amountRaw.toString(), maxFeePercentage: params.maxFeePercentage, confirmationsRequired: Number(confirmationsRequired), explorerUrl: `${this.tokenConfig.blockExplorerUrl}/address/${depositAddressValue}` }; return { success: true, data: depositAddress }; } catch (error) { if (error instanceof CKBoostError) { return { success: false, error: { type: error.type, message: error.message, details: error.details } }; } return { success: false, error: { type: "NETWORK_ERROR" /* NETWORK_ERROR */, message: error instanceof Error ? error.message : "Unknown error occurred", details: error } }; } } /** * Get detailed information about a ckTESTBTC boost request * * @param requestId - The boost request ID (as string) * @returns Detailed boost request information */ async getBoostRequest(requestId) { try { const boostId = BigInt(requestId); const result = await this.backend.getBoostRequest(boostId); if (result.length === 0) { throw new CKBoostError( "REQUEST_NOT_FOUND" /* REQUEST_NOT_FOUND */, `Boost request with ID ${requestId} not found` ); } const backendRequest = result[0]; const boostRequest = { id: backendRequest.id.toString(), status: this.convertBoostStatus(backendRequest.status), amount: this.rawToTokenAmount(backendRequest.amount), amountRaw: backendRequest.amount.toString(), maxFeePercentage: backendRequest.maxFeePercentage, owner: backendRequest.owner.toString(), booster: backendRequest.booster.length > 0 ? backendRequest.booster[0]?.toString() : void 0, preferredBooster: backendRequest.preferredBooster.length > 0 ? backendRequest.preferredBooster[0]?.toString() : void 0, depositAddress: backendRequest.btcAddress.length > 0 ? backendRequest.btcAddress[0] : void 0, receivedAmount: this.rawToTokenAmount(backendRequest.receivedBTC), confirmationsRequired: Number(backendRequest.confirmationsRequired), createdAt: Number(backendRequest.createdAt), updatedAt: Number(backendRequest.updatedAt), explorerUrl: backendRequest.btcAddress.length > 0 && backendRequest.btcAddress[0] ? `${this.tokenConfig.blockExplorerUrl}/address/${backendRequest.btcAddress[0]}` : this.tokenConfig.blockExplorerUrl }; return { success: true, data: boostRequest }; } catch (error) { if (error instanceof CKBoostError) { return { success: false, error: { type: error.type, message: error.message, details: error.details } }; } return { success: false, error: { type: "NETWORK_ERROR" /* NETWORK_ERROR */, message: error instanceof Error ? error.message : "Unknown error occurred", details: error } }; } } /** * Convert backend BoostStatus variant to our enum */ convertBoostStatus(status) { if ("pending" in status) return "pending" /* PENDING */; if ("active" in status) return "active" /* ACTIVE */; if ("completed" in status) return "completed" /* COMPLETED */; if ("cancelled" in status) return "cancelled" /* CANCELLED */; return "pending" /* PENDING */; } /** * Convert raw amount (bigint) to token amount string */ rawToTokenAmount(rawAmount) { const amount = Number(rawAmount) / Math.pow(10, this.tokenConfig.decimals); return amount.toFixed(this.tokenConfig.decimals); } /** * Utility method to get all pending ckTESTBTC boost requests */ async getPendingBoostRequests() { try { const result = await this.backend.getPendingBoostRequests(); const requests = result.map((backendRequest) => ({ id: backendRequest.id.toString(), status: this.convertBoostStatus(backendRequest.status), amount: this.rawToTokenAmount(backendRequest.amount), amountRaw: backendRequest.amount.toString(), maxFeePercentage: backendRequest.maxFeePercentage, owner: backendRequest.owner.toString(), booster: backendRequest.booster.length > 0 ? backendRequest.booster[0]?.toString() : void 0, preferredBooster: backendRequest.preferredBooster.length > 0 ? backendRequest.preferredBooster[0]?.toString() : void 0, depositAddress: backendRequest.btcAddress.length > 0 ? backendRequest.btcAddress[0] : void 0, receivedAmount: this.rawToTokenAmount(backendRequest.receivedBTC), confirmationsRequired: Number(backendRequest.confirmationsRequired), createdAt: Number(backendRequest.createdAt) / 1e6, // Convert nanoseconds to milliseconds updatedAt: Number(backendRequest.updatedAt) / 1e6, // Convert nanoseconds to milliseconds explorerUrl: backendRequest.btcAddress.length > 0 && backendRequest.btcAddress[0] ? `${this.tokenConfig.blockExplorerUrl}/address/${backendRequest.btcAddress[0]}` : this.tokenConfig.blockExplorerUrl })); return { success: true, data: requests }; } catch (error) { return { success: false, error: { type: "NETWORK_ERROR" /* NETWORK_ERROR */, message: error instanceof Error ? error.message : "Unknown error occurred", details: error } }; } } /** * Get the ckTESTBTC token configuration */ getTokenConfig() { return this.tokenConfig; } }; // src/index.ts var ckTESTBTC_CANISTER_IDS = { CKBOOST_BACKEND: "75egi-7qaaa-aaaao-qj6ma-cai", CKTESTBTC_LEDGER: "mc6ru-gyaaa-aaaar-qaaaq-cai" }; export { BoostStatus, CKBoostError, CKBoostErrorType, SupportedToken, TOKEN_CONFIGS, ckTESTBTCClient, ckTESTBTC_CANISTER_IDS }; //# sourceMappingURL=index.mjs.map //# sourceMappingURL=index.mjs.map