接入Luffa钱包
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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后开始轮询 */
|
||||||
|
|||||||
Reference in New Issue
Block a user