UNPKG

hypay-adapter

Version:

Provides an XRPL payment adapter.

483 lines (472 loc) 15 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // src/index.ts var index_exports = {}; __export(index_exports, { GemWallet: () => GemWallet2, XRPLWallet: () => XRPLWallet, XamanWallet: () => XamanWallet2 }); module.exports = __toCommonJS(index_exports); // src/types/xrpl.ts var NETWORKS = { LOCALNET: "ws://localhost:6006/", TESTNET: "wss://s.altnet.rippletest.net:51233", DEVNET: "wss://s.devnet.rippletest.net:51233", MAINNET: "wss://s1.ripple.com" }; // src/types/wallet.ts var import_xrpl2 = require("xrpl"); var AbstractWallet = class { constructor(network = "TESTNET") { __publicField(this, "networkType"); __publicField(this, "networkAddress"); this.networkType = network; this.networkAddress = NETWORKS[network]; } async getTransactionWithTxid(txid) { const client = new import_xrpl2.Client(this.networkType); await client.connect(); const tx = await client.request({ command: "tx", transaction: txid }); await client.disconnect(); return tx; } async getCurrentFee() { const client = new import_xrpl2.Client(this.networkType); await client.connect(); const feeResponse = await client.request({ command: "fee" }); const { base_fee: _, median_fee: medianFee, minimum_fee: __, open_ledger_fee: ___ } = feeResponse.result.drops; await client.disconnect(); return { medianFee }; } }; // src/controllers/wallet/xaman.ts var import_xumm = require("xumm"); var XamanWallet = class extends AbstractWallet { constructor(destination, apiCredentials) { super(apiCredentials.network ?? "TESTNET"); __publicField(this, "destinationAddress"); __publicField(this, "connectedAddress"); __publicField(this, "xumm"); __publicField(this, "txidTopayloadUuidMapper"); __publicField(this, "authBaseUrl", "https://oauth2.xumm.app/auth"); __publicField(this, "signBaseUrl", "https://xumm.app/sign"); __publicField(this, "apiKey"); __publicField(this, "apiSecret"); this.destinationAddress = destination; this.apiKey = apiCredentials?.key || ""; this.apiSecret = apiCredentials?.secret || ""; this.xumm = new import_xumm.Xumm(this.apiKey, this.apiSecret); this.txidTopayloadUuidMapper = /* @__PURE__ */ new Map(); } async init() { } async connect(params) { try { this.connectedAddress = await this.xumm.user.account; if (!this.connectedAddress) { throw new Error("Failed to retrieve user account"); } return { isReady: true, address: this.connectedAddress, providerName: "XAMAN" }; } catch (e) { const authUrl = this.authBaseUrl + `?client_id=${this.apiKey}&${params ? `redirect_uri=${params.redirectUri}` : ""}&response_type=token&force_network=${this.networkType == "MAINNET" ? "MAINNET" : "TESTNET"}`; return { isReady: false, address: authUrl, providerName: "XAMAN" }; } } async createPaymentTx({ amount, desitination, meta_data }) { if (!this.xumm) { throw new Error("Xaman Wallet SDK is not available."); } const draftTransaction = { txjson: { TransactionType: "Payment", Destination: desitination ?? this.destinationAddress, Amount: amount }, options: { force_network: this.networkType }, custom_meta: { identifier: meta_data?.identifier, instruction: meta_data?.instruction, blob: meta_data?.blob } }; const payload = await this.xumm.payload?.create(draftTransaction); if (!payload) throw new Error("payload is not defined"); return payload.uuid; } signAndSubmit({ payloadUuid }) { if (!this.xumm) { throw new Error("Xaman Wallet SDK is not available."); } return (async () => { try { const isReady = await this.xumm.xapp?.ready(); if (!isReady) throw new Error("Xapp can not loaded. please load screen for debuging."); await this.xumm.xapp?.openSignRequest({ uuid: payloadUuid }); return { isReady: true, signUri: void 0 }; } catch (e) { const signUrl = `${this.signBaseUrl}/${payloadUuid}`; return { isReady: false, signUri: signUrl }; } })(); } async getSubmittedTxResult(payloadUuid) { const payload = await this.xumm.payload?.get(payloadUuid); if (!payload) throw new Error("Error"); if (payload.response.txid) this.txidTopayloadUuidMapper.set(payload.response.txid, payloadUuid); const isSuccess = payload.response.dispatched_result === "tesSUCCESS"; const isSubmitted = payload.response.txid !== null; const isResolved = payload.response.resolved_at !== null; return { success: isSuccess, submitted: isSubmitted, resolved: isResolved, validated: isSuccess && isSubmitted && isResolved, txid: payload.response.txid, createdAt: payload.payload.created_at, expiresAt: payload.payload.expires_at, raw: payload.response }; } async request({ method, params }) { if (!this.xumm) { throw new Error("Xaman Wallet SDK is not available."); } const draftTransaction = { TransactionType: method, ...params }; const payload = await this.xumm.payload?.create({ txjson: draftTransaction }); if (!payload) throw new Error("Error"); return payload.uuid; } async respond(_) { } async ping() { if (!this.xumm) { throw new Error("Xaman Wallet SDK is not available."); } const ping = await this.xumm.ping(); if (ping) return { pong: ping.jwtData?.pong ?? false }; return { pong: false }; } async disconnect() { if (!this.xumm) { throw new Error("Xaman Wallet SDK is not available."); } await this.xumm.logout(); this.connectedAddress = void 0; } formatAuthMessage(params) { return `Sign in request from ${params.origin} Payload: ${params.payload}`; } }; // src/controllers/wallet/gem.ts var import_api = require("@gemwallet/api"); var import_uuid = require("uuid"); var GemWallet = class extends AbstractWallet { constructor(destination) { super(); __publicField(this, "destinationAddress"); __publicField(this, "connectedAddress"); __publicField(this, "payloadUuidToTxidMapper"); // TODO use store __publicField(this, "payloadMapper"); this.destinationAddress = destination; this.payloadUuidToTxidMapper = /* @__PURE__ */ new Map(); this.payloadMapper = /* @__PURE__ */ new Map(); } async init() { } async connect() { const isGemWalletInstalled = await (0, import_api.isInstalled)(); if (!isGemWalletInstalled) { throw new Error("Gem Wallet is not installed in your brower"); } const res = await (0, import_api.getAddress)(); if (res.type === "response" && res.result) { this.connectedAddress = res.result.address; } else { console.error("Can not found wallet address"); return { isReady: false, address: "", providerName: "GEM" }; } return { isReady: true, address: this.connectedAddress, providerName: "GEM" }; } async createPaymentTx({ amount }) { if (!this.connectedAddress) { throw new Error("Can not found wallet address"); } const tx = { amount, destination: this.destinationAddress }; const uuid = (0, import_uuid.v4)(); this.payloadMapper.set(uuid, tx); return uuid; } async signAndSubmit({ payloadUuid }) { const payload = this.payloadMapper.get(payloadUuid); if (!payload) { console.error("payload not found"); return { isReady: false }; } const sendPaymentResponse = await (0, import_api.sendPayment)(payload); const txid = sendPaymentResponse.result?.hash; if (!txid) return { isReady: false }; this.payloadUuidToTxidMapper.set(payloadUuid, txid); return { isReady: true }; } async getSubmittedTxResult(payloadUuid) { const txid = this.payloadUuidToTxidMapper.get(payloadUuid); const tx = await super.getTransactionWithTxid(txid); if (!txid || !tx) throw new Error("Transaction is invalid"); const meta = tx.result.meta; return { success: meta.TransactionResult === "tesSUCCESS", submitted: !!tx.result.validated, resolved: !!tx.result.date, validated: meta.TransactionResult === "tesSUCCESS" && !!tx.result.validated, txid, createdAt: new Date(((tx.result.date ?? 0) + 946684800) * 1e3).toISOString(), expiresAt: void 0, raw: tx.result }; } async request({ method, params }) { if (!this.connectedAddress) { throw new Error("Can not found wallet address"); } const draftTransaction = { TransactionType: method, ...params }; const uuid = (0, import_uuid.v4)(); this.payloadMapper.set(uuid, draftTransaction); return uuid; } async respond(_) { } async ping() { const isGemWalletInstalled = await (0, import_api.isInstalled)(); if (!isGemWalletInstalled) { throw new Error("Gem Wallet is not installed in your brower"); } return { pong: true }; } async disconnect() { this.connectedAddress = void 0; } formatAuthMessage(params) { return `Sign in request from ${params.origin} Payload: ${params.payload}`; } }; // src/controllers/wallet/xrpl.ts var import_xrpl3 = require("xrpl"); var import_uuid2 = require("uuid"); var RawXRPLWallet = class extends AbstractWallet { constructor(destination, secret, network = "TESTNET") { super(network); __publicField(this, "destinationAddress"); __publicField(this, "connectedAddress"); __publicField(this, "payloadUuidToTxidMapper"); __publicField(this, "payloadMapper"); __publicField(this, "client"); __publicField(this, "wallet"); const node = this.getNodeUrl(network); this.client = new import_xrpl3.Client(node); this.destinationAddress = destination; this.payloadUuidToTxidMapper = /* @__PURE__ */ new Map(); this.payloadMapper = /* @__PURE__ */ new Map(); this.wallet = import_xrpl3.Wallet.fromSeed(secret); this.connectedAddress = this.wallet.classicAddress; } getNodeUrl(network) { return NETWORKS[network] ?? NETWORKS["TESTNET"]; } async init() { if (!this.client.isConnected()) { await this.client.connect(); } } async connect() { await this.init(); if (!this.connectedAddress) return { isReady: false, address: "", providerName: "XRPL" }; return { isReady: true, address: this.connectedAddress, providerName: "XRPL" }; } changeConntectedAddress(secret) { this.wallet = import_xrpl3.Wallet.fromSeed(secret); this.connectedAddress = this.wallet.classicAddress; } async createPaymentTx({ amount, desitination, meta_data }) { if (!this.client.isConnected()) { throw new Error("XRPL client does not connected Wallet SDK is not available."); } if (!this.connectedAddress) throw new Error("There are no connected address"); const autofilledTransaction = await this.client.autofill({ TransactionType: "Payment", Account: this.connectedAddress, Destination: desitination ?? this.destinationAddress, Amount: amount, Memos: [ { Memo: { MemoType: (0, import_xrpl3.convertStringToHex)("invoice"), MemoData: (0, import_xrpl3.convertStringToHex)( JSON.stringify({ identifier: meta_data?.identifier, instruction: meta_data?.instruction }) ) } } ] }); const uuid = (0, import_uuid2.v4)(); this.payloadMapper.set(uuid, autofilledTransaction); return uuid; } async signAndSubmit({ payloadUuid }) { const payload = this.payloadMapper.get(payloadUuid); if (!payload) { console.error("payload not found"); return { isReady: false }; } const signed = this.wallet.sign(payload); const response = await this.client.submitAndWait(signed.tx_blob); if (!response.result.hash) return { isReady: false }; this.payloadUuidToTxidMapper.set(payloadUuid, response.result.hash); return { isReady: true }; } async getSubmittedTxResult(payloadUuid) { const txid = this.payloadUuidToTxidMapper.get(payloadUuid); const tx = await this.client.request({ command: "tx", transaction: txid }); if (!txid || !tx) throw new Error("Transaction is invalid"); const meta = tx.result.meta; return { success: meta.TransactionResult === "tesSUCCESS", submitted: !!tx.result.validated, resolved: !!tx.result.date, validated: meta.TransactionResult === "tesSUCCESS" && !!tx.result.validated, txid, createdAt: new Date(((tx.result.date ?? 0) + 946684800) * 1e3).toISOString(), // ripple epoch expiresAt: void 0, raw: tx.result }; } async request({ method, params }) { const result = await this.client.request({ command: method, ...params }); return JSON.stringify(result); } async respond(_) { } async ping() { try { await this.init(); const res = await this.client.request({ command: "ping" }); return { pong: !!res }; } catch { return { pong: false }; } } async disconnect() { if (this.client.isConnected()) { await this.client.disconnect(); } } formatAuthMessage(params) { return `Sign in request from ${params.origin} Payload: ${params.payload}`; } }; // src/index.ts var XamanWallet2 = XamanWallet; var GemWallet2 = GemWallet; var XRPLWallet = RawXRPLWallet; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { GemWallet, XRPLWallet, XamanWallet });