接入Luffa钱包

This commit is contained in:
chen wei bo
2025-09-28 23:04:39 +08:00
parent 303003b550
commit 7489206537
5 changed files with 134 additions and 61 deletions
+2 -2
View File
@@ -154,12 +154,12 @@ export class SDKManager {
} }
// 签名交易 // 签名交易
public async signTransaction(rawData: any): Promise<{ signedData: string }> { public async signTransaction(rawTx: any): Promise<{ signedData: string }> {
if (!this.walletSDK) return; if (!this.walletSDK) return;
// 判断是否实现交易能力 // 判断是否实现交易能力
if ("signTransaction" in this.walletSDK) { if ("signTransaction" in this.walletSDK) {
const txCap = this.walletSDK as unknown as ITransactionCap; const txCap = this.walletSDK as unknown as ITransactionCap;
return txCap.signTransaction(rawData); return txCap.signTransaction(rawTx);
} }
throw new Error("当前钱包 SDK 不支持 signTransaction 功能"); throw new Error("当前钱包 SDK 不支持 signTransaction 功能");
} }
@@ -5,12 +5,12 @@
export interface ITransactionCap { export interface ITransactionCap {
/** /**
* 签名交易(由 DApp 构造交易对象) * 签名交易
* *
* @param rawData 原始交易对象 * @param rawTx 原始交易参数
* @returns 已签名交易 * @returns 已签名交易
*/ */
signTransaction(rawData: any): Promise<{ signedData: string }>; signTransaction(rawTx: any): Promise<{ signedData: string }>;
/** /**
* 发送交易(广播到链上) * 发送交易(广播到链上)
@@ -1,12 +1,19 @@
import { IWalletSDK } from "../core/IWalletSDK"; import { IWalletSDK } from "../core/IWalletSDK";
import { ISignCap } from "../core/ISignCap";
import { ITransactionCap } from "../core/ITransactionCap"; import { ITransactionCap } from "../core/ITransactionCap";
import { logger } from "db://assets/Scripts/Main/Common/Logger"; import { logger } from "db://assets/Scripts/Main/Common/Logger";
export class LuffaWalletSDK implements IWalletSDK, ISignCap, ITransactionCap { export class LuffaWalletSDK implements IWalletSDK, ITransactionCap {
// 运行环境,endless 为主网, eds 为测试网
private network: string;
// 自己的钱包地址
private address: string | null = null; private address: string | null = null;
// Luffa ID
private luffaId: any = null; private luffaId: any = null;
constructor() {
this.network = "eds";
}
// 初始化 // 初始化
init(cb?: Function): void { init(cb?: Function): void {
logger.log("Luffa 钱包初始化"); logger.log("Luffa 钱包初始化");
@@ -22,11 +29,11 @@ export class LuffaWalletSDK implements IWalletSDK, ISignCap, ITransactionCap {
uuid: this.create16String(), uuid: this.create16String(),
methodName: "connect", methodName: "connect",
initData: { initData: {
network: "endless", // endless 为主网, ends 为测试网 network: this.network, // endless 为主网, eds 为测试网
}, },
metadata: { metadata: {
superBox: true, superBox: true,
url: "https://your-game-domain.com", // 建议填自己游戏的唯一标识 url: "https://xchat188.com/", // 建议填自己游戏的唯一标识
// icon: "https://your-game-domain.com/icon.png", // icon: "https://your-game-domain.com/icon.png",
}, },
from: "", from: "",
@@ -56,54 +63,79 @@ export class LuffaWalletSDK implements IWalletSDK, ISignCap, ITransactionCap {
return this.address; return this.address;
} }
// 签名消息 (单签) // 签名交易
async signMessage(message: string, options?: any): Promise<{ signature: string; fullMessage?: string }> { async signTransaction(rawTx: any): Promise<{ signedData: string }> {
logger.log("调用 Luffa 单签签名"); logger.log("签名交易:", rawTx);
if ("contract" in rawTx) {
return this.signTransactionV2(rawTx);
} else {
return this.signTransactionV1(rawTx);
}
}
// 签名交易,方法一
async signTransactionV1(rawTx: any): Promise<{ signedData: string }> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const opts = { // DATA
api_name: "luffaWebRequest", const DATA = {
data: { module: "0x1", // 固定写死
uuid: this.create16String(), moduleName: "endless_account", // 固定写死
methodName: "signMessageV2", functionName: "transfer", // 固定写死
initData: { network: "endless" }, data: JSON.stringify({
from: this.address ?? "", "1_address_address": rawTx.toAddress, // 对方钱包地址
data: { "2_u128_amount": String(rawTx.amount * 100000000), // 金额 * 10^8
message, }),
nonce: options?.nonce ?? Date.now(), // 默认用时间戳 argsData: [],
address: options?.address ?? false, };
application: options?.application ?? false,
chainId: options?.chainId ?? false, const opts = {
}, api_name: "luffaWebRequest",
data: {
uuid: this.create16String(), // 生成随机16位字符串
from: this.address ?? "", // 自己的钱包地址
methodName: "packageTransaction",
initData: {
network: this.network, // endless 为主网, eds 为测试网
}, },
success: (res) => { data: DATA, // 传入构造好的 DATA
logger.log("signMessageV2 success:", res); },
resolve({ success: (res) => {
signature: res.data?.signature, logger.log("packageTransactionV1 success:", res);
fullMessage: res.data?.fullMessage, resolve({ signedData: res.data?.rawData });
}); },
}, fail: (err) => {
fail: (err) => { logger.error("packageTransactionV1 fail:", err);
logger.error("signMessageV2 fail:", err); reject(err);
reject(err); },
}, };
}; wx.invokeNativePlugin(opts);
wx.invokeNativePlugin(opts);
}); });
} }
// 签名交易 // 签名交易,方法二
async signTransaction(rawData: any): Promise<{ signedData: string }> { async signTransactionV2(rawTx: any): Promise<{ signedData: string }> {
logger.log("签名交易", rawData); const payload = {
function: rawTx.contract, // 合约地址::合约名::函数名
functionArguments: rawTx.args ?? [],
typeArguments: rawTx.typeArgs ?? [],
typeEnum: []
};
const allData = {
payload,
secondarySignerAddresses: rawTx.secondarySigners ?? [], //多签地址集合 非多签可以不用
feePayer: rawTx.feePayer ?? "" //手续费
};
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const opts = { const opts = {
api_name: "luffaWebRequest", api_name: "luffaWebRequest",
data: { data: {
uuid: this.create16String(), uuid: this.create16String(),
from: this.address ?? "", from: this.address ?? "", //自己的钱包地址
methodName: "packageTransactionV2", methodName: "packageTransactionV2",
initData: { network: "endless" }, initData: { network: this.network },
data: { data: {
data: JSON.stringify(rawData), data: JSON.stringify(allData),
}, },
}, },
success: (res) => { success: (res) => {
@@ -117,11 +149,11 @@ export class LuffaWalletSDK implements IWalletSDK, ISignCap, ITransactionCap {
}; };
wx.invokeNativePlugin(opts); wx.invokeNativePlugin(opts);
}); });
} }
// 发送交易(广播到链上) // 发送交易(广播到链上)
async sendTransaction(signedData: string): Promise<{ hash: string }> { async sendTransaction(signedData: string): Promise<{ hash: string }> {
logger.log("发送交易", signedData); logger.log("发送交易(广播到链上)", signedData);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const opts = { const opts = {
api_name: "luffaWebRequest", api_name: "luffaWebRequest",
@@ -129,7 +161,7 @@ export class LuffaWalletSDK implements IWalletSDK, ISignCap, ITransactionCap {
uuid: this.create16String(), uuid: this.create16String(),
from: this.address ?? "", from: this.address ?? "",
methodName: "signAndSubmitTransaction", methodName: "signAndSubmitTransaction",
initData: { network: "endless" }, initData: { network: this.network },
data: { data: {
serializedTransaction: { serializedTransaction: {
data: signedData, data: signedData,
+53 -12
View File
@@ -9,20 +9,61 @@ import { type OpenStrategy } from "./PaymentOpener";
import { DataManager, DataId } from "db://assets/Scripts/chat18x/data/DataManager"; import { DataManager, DataId } from "db://assets/Scripts/chat18x/data/DataManager";
import { OrderData } from "db://assets/Scripts/chat18x/data/OrderData"; import { OrderData } from "db://assets/Scripts/chat18x/data/OrderData";
import { logger } from "db://assets/Scripts/Main/Common/Logger"; import { logger } from "db://assets/Scripts/Main/Common/Logger";
import { SDKManager } from "db://assets/Scripts/Main/Channel/SDKManager";
export class LuffaPayFlow implements PaymentFlow { export class LuffaPayFlow implements PaymentFlow {
constructor(private delayMs: number = 5000) {} constructor(private delayMs: number = 10000) {}
async run(orderId: string, _payUrl: string, _open: OpenStrategy): Promise<proto.cs.ICSQueryOrderRes | null> { async run(orderId: string, _payUrl: string, _open: OpenStrategy): Promise<proto.cs.ICSQueryOrderRes | null> {
// 延时 try {
await this.delay(this.delayMs); // 连接钱包(只需一次,如果已连过可以跳过)
// 开始轮询 const address = SDKManager.I.getWalletAddress();
const data = await this.pollOrder(orderId); if (!address) {
// 刷新订单数据 logger.log("钱包未连接,开始连接 Luffa 钱包...");
const orderData = DataManager.I.getDataById<OrderData>(DataId.Order); await new Promise<void>((resolve, reject) => {
orderData.applyQueryOrder(orderId, data); SDKManager.I.connectWallet((addr) => {
// 返回结果 if (addr) {
return data; logger.log("已连接 Luffa 钱包:", addr);
resolve();
} else {
logger.error("Luffa 钱包连接失败");
reject(new Error("Luffa 钱包连接失败"));
}
});
});
}
// 构造交易参数
const rawTx = {
toAddress: "Hm3g4xXM4JHt5EwFUcvVZ8RthR4KWUnR51fKHCbnKkiZ", // TODO
amount: 1 // TODO
};
// 签名交易
const signed = await SDKManager.I.signTransaction(rawTx);
logger.log("Luffa 签名结果:", signed);
// 发送交易
const sent = await SDKManager.I.sendTransaction(signed.signedData);
logger.log("Luffa 交易已提交,hash:", sent.hash);
// 等待一会再开始轮询
await this.delay(this.delayMs);
// 开始轮询订单状态
const data = await this.pollOrder(orderId);
// 刷新订单数据
const orderData = DataManager.I.getDataById<OrderData>(DataId.Order);
orderData.applyQueryOrder(orderId, data);
// 返回结果
return data;
} catch (e) {
logger.error("Luffa Payment process exception:", e);
return null;
}
} }
async resume(orderId: string, _payUrl: string): Promise<proto.cs.ICSQueryOrderRes | null> { async resume(orderId: string, _payUrl: string): Promise<proto.cs.ICSQueryOrderRes | null> {
@@ -33,8 +74,8 @@ export class LuffaPayFlow implements PaymentFlow {
private async pollOrder(orderId: string) { private async pollOrder(orderId: string) {
const poller = new PaymentPoller(); const poller = new PaymentPoller();
return poller.poll(orderId, { return poller.poll(orderId, {
maxDurationMs: 10 * 60 * 1000, maxDurationMs: 2 * 60 * 1000,
startIntervalMs: 5000, startIntervalMs: 3000,
maxIntervalMs: 10000, maxIntervalMs: 10000,
jitter: true, jitter: true,
}, (d) => logger.log()); }, (d) => logger.log());
@@ -28,7 +28,7 @@ export class PaymentService {
this.flowMap = new Map<PaymentMethod, PaymentFlow>(); this.flowMap = new Map<PaymentMethod, PaymentFlow>();
this.flowMap.set(PaymentMethod.CashPay, new CashInrFlow(this.waitAppResumeIfNeeded.bind(this))); this.flowMap.set(PaymentMethod.CashPay, new CashInrFlow(this.waitAppResumeIfNeeded.bind(this)));
this.flowMap.set(PaymentMethod.Web3, new WebUsdFlow(5000)); this.flowMap.set(PaymentMethod.Web3, new WebUsdFlow(5000));
this.flowMap.set(PaymentMethod.Luffa, new LuffaPayFlow(5000)); this.flowMap.set(PaymentMethod.Luffa, new LuffaPayFlow(10000));
} }
/** 发起支付:创建订单→打开URL→回到App后开始轮询 */ /** 发起支付:创建订单→打开URL→回到App后开始轮询 */