|
@@ -1,81 +1,158 @@
|
|
|
-import { getWeb3,buildSignatureParams } from "@/utils/utils.js";
|
|
|
+import { getWeb3, buildSignatureParams } from "@/utils/utils.js";
|
|
|
import jlabiData from "@/utils/abijson/jlabi.json";
|
|
|
+import bmabiData from "@/utils/abijson/bmabi.json";
|
|
|
+import pubData from "@/utils/abijson/pub.json";
|
|
|
|
|
|
-//发放奖励
|
|
|
-async function sendSingleReward(privateKey,amount) {
|
|
|
- // 如果未获取到私钥,直接终止函数
|
|
|
- if (!privateKey) {
|
|
|
- console.warn("⚠️ 未获取到私钥,终止发放奖励流程");
|
|
|
- return {
|
|
|
- status: "error",
|
|
|
- message: "未获取到私钥,无法发放奖励"
|
|
|
- };
|
|
|
+const web3 = await getWeb3();
|
|
|
+
|
|
|
+const TOKEN_ADDRESSES = {
|
|
|
+ wgt: "0xCec9CE45f9E8f41016c89576CD27d74d5103c04c",
|
|
|
+ stt: "0x45F07c7Fe9E12518eA0eec109506799384BE0a95"
|
|
|
+};
|
|
|
+
|
|
|
+const MANAGER_ADDRESS = "0x257853ac4319c76f1cdb00831fd14a48977b45ef";
|
|
|
+
|
|
|
+function normalizePrivateKey(pk) {
|
|
|
+ return pk.startsWith("0x") ? pk : "0x" + pk;
|
|
|
+}
|
|
|
+
|
|
|
+// 获取余额
|
|
|
+async function getBalance(privateKey, type) {
|
|
|
+ try {
|
|
|
+ privateKey = normalizePrivateKey(privateKey);
|
|
|
+ const { address } = web3.eth.accounts.privateKeyToAccount(privateKey);
|
|
|
+ const tokenAddress = TOKEN_ADDRESSES[type.toLowerCase()];
|
|
|
+ const tokenContract = new web3.eth.Contract(pubData, tokenAddress);
|
|
|
+
|
|
|
+ const balanceWei = await tokenContract.methods.balanceOf(address).call();
|
|
|
+ return web3.utils.fromWei(balanceWei, 'ether');
|
|
|
+ } catch (error) {
|
|
|
+ console.error("❌ 获取余额失败:", error);
|
|
|
+ return null;
|
|
|
}
|
|
|
- // 确保私钥格式正确
|
|
|
- if (!privateKey.startsWith("0x")) {
|
|
|
- privateKey = "0x" + privateKey;
|
|
|
+}
|
|
|
+
|
|
|
+// 发放奖励
|
|
|
+async function sendSingleReward(privateKey, amount) {
|
|
|
+ if (!privateKey) {
|
|
|
+ return { status: "error", message: "未获取到私钥,无法发放奖励" };
|
|
|
}
|
|
|
|
|
|
- try {
|
|
|
- const web3 = await getWeb3();
|
|
|
- const senderAccount = web3.eth.accounts.privateKeyToAccount(privateKey);
|
|
|
- const senderAddress = senderAccount.address;
|
|
|
- const tokenAmountWei = web3.utils.toWei(amount.toString(), "ether");
|
|
|
+ privateKey = normalizePrivateKey(privateKey);
|
|
|
|
|
|
+ try {
|
|
|
+ const account = web3.eth.accounts.privateKeyToAccount(privateKey);
|
|
|
+ const sender = account.address;
|
|
|
+ const amountWei = web3.utils.toWei(amount.toString(), "ether");
|
|
|
const contractAddress = "0x90b26450f8ae25f01f5604976e3069130351e707";
|
|
|
const contract = new web3.eth.Contract(jlabiData, contractAddress);
|
|
|
|
|
|
- // 构建签名
|
|
|
- const signatureData = await buildSignatureParams(senderAddress, tokenAmountWei, contractAddress);
|
|
|
- const { timestamp, nonceForSig, signature } = signatureData;
|
|
|
+ const { timestamp, nonceForSig, signature } = await buildSignatureParams(sender, amountWei, contractAddress);
|
|
|
|
|
|
- if (!signature) {
|
|
|
- throw new Error("签名为空");
|
|
|
- }
|
|
|
-
|
|
|
- console.log("✅ 签名成功:", signatureData);
|
|
|
-
|
|
|
- // 构造交易
|
|
|
- const gasPrice = await web3.eth.getGasPrice();
|
|
|
- const nonce = await web3.eth.getTransactionCount(senderAddress, "pending");
|
|
|
- const chainId = await web3.eth.getChainId();
|
|
|
+ if (!signature) throw new Error("签名为空");
|
|
|
|
|
|
const tx = {
|
|
|
- from: senderAddress,
|
|
|
+ from: sender,
|
|
|
to: contractAddress,
|
|
|
data: contract.methods
|
|
|
- .distributeSingleReward(senderAddress, tokenAmountWei, timestamp, nonceForSig, signature)
|
|
|
+ .distributeSingleReward(sender, amountWei, timestamp, nonceForSig, signature)
|
|
|
.encodeABI(),
|
|
|
gas: 500000,
|
|
|
- gasPrice,
|
|
|
- nonce,
|
|
|
- chainId,
|
|
|
+ gasPrice: await web3.eth.getGasPrice(),
|
|
|
+ nonce: await web3.eth.getTransactionCount(sender, "pending"),
|
|
|
+ chainId: await web3.eth.getChainId()
|
|
|
};
|
|
|
|
|
|
- // 签名并发送交易
|
|
|
- const signedTx = await web3.eth.accounts.signTransaction(tx, privateKey);
|
|
|
- const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
|
|
|
+ const signed = await web3.eth.accounts.signTransaction(tx, privateKey);
|
|
|
+ const receipt = await web3.eth.sendSignedTransaction(signed.rawTransaction);
|
|
|
|
|
|
- console.log("✅ 奖励发放成功,交易哈希:", receipt.transactionHash);
|
|
|
- return {
|
|
|
- status: "success",
|
|
|
- receipt
|
|
|
- };
|
|
|
+ return { status: "success", receipt };
|
|
|
|
|
|
} catch (error) {
|
|
|
+ const errMsg = error.message || "奖励发放失败,未知错误";
|
|
|
const fullError = JSON.stringify(error, Object.getOwnPropertyNames(error), 2);
|
|
|
- console.error("🧾 错误详情:", fullError);
|
|
|
+ console.error("🧾 奖励发放失败:", fullError);
|
|
|
+ return { status: "error", message: errMsg, errorData: fullError };
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 通用报名函数(支持 WGT 和 STT)
|
|
|
+async function tokenSignUp(privateKey, amount, type) {
|
|
|
+ privateKey = normalizePrivateKey(privateKey);
|
|
|
+ const tokenAddress = TOKEN_ADDRESSES[type.toLowerCase()];
|
|
|
+ const tokenAmount = web3.utils.toWei(amount.toString(), "ether");
|
|
|
+
|
|
|
+ try {
|
|
|
+ const account = web3.eth.accounts.privateKeyToAccount(privateKey);
|
|
|
+ const sender = account.address;
|
|
|
+
|
|
|
+ const [chainId, gasPriceRaw, nonce] = await Promise.all([
|
|
|
+ web3.eth.getChainId(),
|
|
|
+ web3.eth.getGasPrice(),
|
|
|
+ web3.eth.getTransactionCount(sender)
|
|
|
+ ]);
|
|
|
+
|
|
|
+ const gasPrice = (BigInt(gasPriceRaw) * 10n).toString();
|
|
|
+ const tokenContract = new web3.eth.Contract(pubData, tokenAddress);
|
|
|
+ const exchangeContract = new web3.eth.Contract(bmabiData, MANAGER_ADDRESS);
|
|
|
+
|
|
|
+ // 授权
|
|
|
+ const approveTx = await web3.eth.accounts.signTransaction({
|
|
|
+ from: sender,
|
|
|
+ to: tokenAddress,
|
|
|
+ data: tokenContract.methods.approve(MANAGER_ADDRESS, tokenAmount).encodeABI(),
|
|
|
+ gas: 300000,
|
|
|
+ gasPrice,
|
|
|
+ chainId,
|
|
|
+ nonce
|
|
|
+ }, privateKey);
|
|
|
|
|
|
- if (error.message?.includes('revert')) {
|
|
|
- console.error("⛔ Revert 详细信息:", error.data || "无 revert 详细信息");
|
|
|
- }
|
|
|
+ const approveReceipt = await web3.eth.sendSignedTransaction(approveTx.rawTransaction);
|
|
|
+ if (!approveReceipt.status) return { status: "error", message: "授权失败" };
|
|
|
|
|
|
- throw {
|
|
|
+ // 验证授权余额
|
|
|
+ const [allowance, tokenBalance] = await Promise.all([
|
|
|
+ tokenContract.methods.allowance(sender, MANAGER_ADDRESS).call(),
|
|
|
+ tokenContract.methods.balanceOf(sender).call()
|
|
|
+ ]);
|
|
|
+
|
|
|
+ if (BigInt(allowance) < BigInt(tokenAmount)) return { status: "error", message: "授权额度不足" };
|
|
|
+ if (BigInt(tokenBalance) < BigInt(tokenAmount)) return { status: "error", message: `${type.toUpperCase()} 余额不足` };
|
|
|
+
|
|
|
+ // gas 估算
|
|
|
+ const receiveMethod = type.toLowerCase() === 'wgt' ? 'receiveWGT' : 'receiveSTT';
|
|
|
+ const gasEstimate = await exchangeContract.methods[receiveMethod](tokenAmount).estimateGas({ from: sender });
|
|
|
+ const gasLimit = Math.ceil(Number(gasEstimate) * 1.1);
|
|
|
+ const minGasNeeded = BigInt(gasLimit) * BigInt(gasPrice);
|
|
|
+ const ethBalance = await web3.eth.getBalance(sender);
|
|
|
+
|
|
|
+ if (BigInt(ethBalance) < minGasNeeded) return { status: "error", message: "ETH余额不足以支付Gas" };
|
|
|
+
|
|
|
+ // 发送报名交易
|
|
|
+ const depositTx = await web3.eth.accounts.signTransaction({
|
|
|
+ from: sender,
|
|
|
+ to: MANAGER_ADDRESS,
|
|
|
+ data: exchangeContract.methods[receiveMethod](tokenAmount).encodeABI(),
|
|
|
+ gas: gasLimit,
|
|
|
+ gasPrice,
|
|
|
+ chainId,
|
|
|
+ nonce: await web3.eth.getTransactionCount(sender)
|
|
|
+ }, privateKey);
|
|
|
+
|
|
|
+ const receipt = await web3.eth.sendSignedTransaction(depositTx.rawTransaction);
|
|
|
+ return { status: "success", receipt };
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error("❌ 报名流程出错:", JSON.stringify(error, Object.getOwnPropertyNames(error), 2));
|
|
|
+ return {
|
|
|
status: "error",
|
|
|
- message: error.message || "奖励发放失败,未知错误",
|
|
|
- errorData: fullError
|
|
|
+ message: error.message || "报名失败",
|
|
|
+ errorData: error
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-export { sendSingleReward };
|
|
|
+const WGTForToken = (pk, num) => tokenSignUp(pk, num, 'wgt');
|
|
|
+const STTForToken = (pk, num) => tokenSignUp(pk, num, 'stt');
|
|
|
+
|
|
|
+export { getBalance, sendSingleReward, WGTForToken, STTForToken };
|