hypay-adapter
Version:
Provides an XRPL payment adapter.
483 lines (472 loc) • 15 kB
JavaScript
"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
});