From af2f076ad699f2457bb1df413a6f8a2aa7133456 Mon Sep 17 00:00:00 2001 From: CounterFire2023 <136581895+CounterFire2023@users.noreply.github.com> Date: Sun, 14 Apr 2024 18:40:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=E9=93=BE=E4=B8=8A=E4=BA=A4=E4=BA=92?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=90=88=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 1 + .env.production | 3 +- src/utils/chainapi.js | 27 ++- src/utils/utils.js | 11 + src/wallet/abi.js | 496 ++++++++++++++++++++++++++++++++++++++++++ src/wallet/index.js | 75 ++++++- 6 files changed, 606 insertions(+), 7 deletions(-) create mode 100644 src/wallet/abi.js diff --git a/.env.development b/.env.development index 840d2e6..ab9d2e2 100644 --- a/.env.development +++ b/.env.development @@ -18,3 +18,4 @@ VUE_APP_APP_NAME = 'CF UAW' # 铭文的验证地址 VUE_APP_SCRIPTION_ADDRESS='0x50A8e60041A206AcaA5F844a1104896224be6F39' +VUE_APP_CONTRACT='0x0Fd13D2CD0B6c679B6f92590E0b91C18DDe7BD3A' diff --git a/.env.production b/.env.production index 1440b65..3332ec5 100644 --- a/.env.production +++ b/.env.production @@ -15,4 +15,5 @@ VUE_APP_CHAIN_ID = '5611' VUE_APP_APP_NAME = 'CF UAW' -VUE_APP_SCRIPTION_ADDRESS='0xcd4bb3402f1a444a1af10f31946ed37dac0eac4d' \ No newline at end of file +VUE_APP_SCRIPTION_ADDRESS='0xcd4bb3402f1a444a1af10f31946ed37dac0eac4d' +VUE_APP_CONTRACT='0x0Fd13D2CD0B6c679B6f92590E0b91C18DDe7BD3A' \ No newline at end of file diff --git a/src/utils/chainapi.js b/src/utils/chainapi.js index dfdbf28..015cb9b 100644 --- a/src/utils/chainapi.js +++ b/src/utils/chainapi.js @@ -14,7 +14,7 @@ export const sendOpenChest = async (address, chestId) => { * @param {*} val * @returns */ -export const sendToChain = async (type, address, val) => { +export const sendToChainScription = async (type, address, val) => { const storeageKey = `${address}_${type}_${val || 'default'}` if (localStorage.getItem(storeageKey)) { return @@ -37,6 +37,31 @@ export const sendToChain = async (type, address, val) => { return storeageKey } +const chainMethods = { + 'chest_open': 'chainOpenBox', + 'explore': 'chainExplore', + 'task_claim': 'chainClaimTask', + 'check': 'chainCheckIn', + 'chest_enhance': 'enhanceBox', +} +export const sendToChain = async (type, address, val) => { + if (!chainMethods[type]) { + throw new Error('Invalid chain method') + } + const storeageKey = `${address}_${type}_${val || 'default'}` + if (localStorage.getItem(storeageKey)) { + return + } + if (store.state.wallet.chainId+'' !== process.env.VUE_APP_CHAIN_ID){ + await new Wallet().changeChain() + } + let chainRes = await new Wallet()[chainMethods[type]](address, val) + if (!chainRes?.transactionHash) { + throw new Error('Failed to claim task') + } + localStorage.setItem(storeageKey, chainRes.transactionHash) + return storeageKey +} // 探索 export const sendExplore = async (address, explore_id) => { diff --git a/src/utils/utils.js b/src/utils/utils.js index abce28f..e99fed0 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -26,4 +26,15 @@ export function formatShowAddress(address) { if (!address) return '' if (address.length < 8) return address return address.slice(0, 4) + '...' + address.slice(-4) +} + + +export function base64ToHex(str) { + const raw = atob(str); + let result = ''; + for (let i = 0; i < raw.length; i++) { + const hex = raw.charCodeAt(i).toString(16); + result += (hex.length === 2 ? hex : '0' + hex); + } + return result; } \ No newline at end of file diff --git a/src/wallet/abi.js b/src/wallet/abi.js new file mode 100644 index 0000000..c18352b --- /dev/null +++ b/src/wallet/abi.js @@ -0,0 +1,496 @@ +export const treasureAbi = [ + { + inputs: [], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'user', + type: 'address', + }, + { + indexed: true, + internalType: 'uint256', + name: 'action', + type: 'uint256', + }, + { + indexed: false, + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + ], + name: 'ActionEvent', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'uint256', + name: 'duration', + type: 'uint256', + }, + ], + name: 'DurationUpdated', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'previousOwner', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'newOwner', + type: 'address', + }, + ], + name: 'OwnershipTransferred', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'bool', + name: 'isPaused', + type: 'bool', + }, + ], + name: 'StateUpdated', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'verifier', + type: 'address', + }, + ], + name: 'VerifierUpdated', + type: 'event', + }, + { + inputs: [ + { + internalType: 'address', + name: 'signer', + type: 'address', + }, + { + internalType: 'bytes32', + name: 'hash', + type: 'bytes32', + }, + { + internalType: 'bytes', + name: 'signature', + type: 'bytes', + }, + ], + name: 'checkSigner', + outputs: [], + stateMutability: 'pure', + type: 'function', + constant: true, + }, + { + inputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + name: 'checkinHistory', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + constant: true, + }, + { + inputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + name: 'claimTaskHistory', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + constant: true, + }, + { + inputs: [], + name: 'duration', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + constant: true, + }, + { + inputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + name: 'enhanceHistory', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + constant: true, + }, + { + inputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + name: 'exploreHistory', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + constant: true, + }, + { + inputs: [], + name: 'isPaused', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool', + }, + ], + stateMutability: 'view', + type: 'function', + constant: true, + }, + { + inputs: [], + name: 'minDuration', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + constant: true, + }, + { + inputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + name: 'openBoxHistory', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + constant: true, + }, + { + inputs: [], + name: 'owner', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + constant: true, + }, + { + inputs: [], + name: 'renounceOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'newOwner', + type: 'address', + }, + ], + name: 'transferOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'valNew', + type: 'uint256', + }, + ], + name: 'updateDuation', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'bool', + name: '_isPaused', + type: 'bool', + }, + ], + name: 'updatePaused', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_verifier', + type: 'address', + }, + ], + name: 'updateVerifier', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [], + name: 'dailyCheckin', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'step', + type: 'uint256', + }, + ], + name: 'explore', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'boxId', + type: 'uint256', + }, + ], + name: 'enhanceBox', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'boxId', + type: 'uint256', + }, + ], + name: 'openBox', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'taskId', + type: 'uint256', + }, + ], + name: 'claimTaskReward', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'uint256', + name: 'actionType', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'val', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'signTime', + type: 'uint256', + }, + { + internalType: 'uint256', + name: 'saltNonce', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'signature', + type: 'bytes', + }, + ], + name: 'generalAction', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '_user', + type: 'address', + }, + { + internalType: 'uint256', + name: '_type', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_val', + type: 'uint256', + }, + { + internalType: 'address', + name: '_contract', + type: 'address', + }, + { + internalType: 'uint256', + name: '_chainId', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_signTime', + type: 'uint256', + }, + { + internalType: 'uint256', + name: '_saltNonce', + type: 'uint256', + }, + ], + name: 'getMessageHash', + outputs: [ + { + internalType: 'bytes32', + name: '', + type: 'bytes32', + }, + ], + stateMutability: 'pure', + type: 'function', + constant: true, + }, +]; diff --git a/src/wallet/index.js b/src/wallet/index.js index 0a40332..7f30342 100644 --- a/src/wallet/index.js +++ b/src/wallet/index.js @@ -5,9 +5,10 @@ import { loginNonce, hexToBase58, aesEncrypt, loginWithSignature } from '@/utils import { SiweMessage } from '@/utils/siwe.js'; import { GlobalData } from '@/utils/GlobalData.js'; -import { parseTokenData } from '@/utils/utils.js'; +import { parseTokenData, base64ToHex } from '@/utils/utils.js'; import { setToken } from '@/utils/cookies.js'; import store from '@/store' +import { treasureAbi } from './abi.js' // Wallet Connect初始化 import { EthereumProvider } from '@walletconnect/ethereum-provider'; @@ -262,8 +263,8 @@ export class Wallet { async sendScription(address, dataStr){ const data = Web3.utils.utf8ToHex(dataStr) - const provider = new Web3(this.provider); - let gasPrice = await provider.eth.getGasPrice() + const web3 = this.web3 + let gasPrice = await web3.eth.getGasPrice() gasPrice = gasPrice * 2n // const gasPrice = 100000000n; console.log('gasPrice: ',gasPrice) @@ -274,9 +275,73 @@ export class Wallet { value: '0x0', data } - let gasLimit = await provider.eth.estimateGas(sendObj) + let gasLimit = await web3.eth.estimateGas(sendObj) console.log('gasLimit: ', gasLimit,sendObj) Object.assign(sendObj, {gasPrice, gasLimit}) - return provider.eth.sendTransaction(sendObj) + return web3.eth.sendTransaction(sendObj) + } + get web3() { + return new Web3(this.provider); + } + + initInstance(web3, address, abi, user, ) { + // const web3 = new Web3(this.provider); + return new web3.eth.Contract(abi, address, { from: user }); + } + + async chainCheckIn(address) { + let web3 = this.web3; + const instance = this.initInstance(web3, process.env.VUE_APP_CONTRACT, treasureAbi, address); + let gasPrice = await web3.eth.getGasPrice() + console.log('chainCheckIn gasPrice: ', gasPrice) + gasPrice = gasPrice * 2n + let gasLimit = await instance.methods.dailyCheckin().estimateGas(); + return instance.methods.dailyCheckin().send({ from: address, gasPrice, gasLimit }); + } + + async chainExplore(address, exploreId) { + let web3 = this.web3; + let idBN = web3.utils.toBigInt('0x'+exploreId) + const instance = this.initInstance(web3, process.env.VUE_APP_CONTRACT, treasureAbi, address); + let gasPrice = await web3.eth.getGasPrice() + gasPrice = gasPrice * 2n + let gasLimit = await instance.methods.explore(idBN).estimateGas({ from: address }); + return instance.methods.explore(idBN).send({ from: address, gasPrice, gasLimit }); + } + + async enhanceBox(address, shareCode) { + let web3 = this.web3; + const codeHex = shareCode.split("") + .map(c => c.charCodeAt(0).toString(16).padStart(2, "0")) + .join(""); + let codeBn = web3.utils.toBigInt('0x'+codeHex) + const instance = this.initInstance(web3, process.env.VUE_APP_CONTRACT, treasureAbi, address); + let gasPrice = await web3.eth.getGasPrice() + gasPrice = gasPrice * 2n + let gasLimit = await instance.methods.enhanceBox(codeBn).estimateGas({ from: address }); + return instance.methods.enhanceBox(codeBn).send({ from: address, gasPrice, gasLimit }); + } + + async chainOpenBox(address, boxId) { + let web3 = this.web3; + let boxIdBN = web3.utils.toBigInt('0x'+boxId) + const instance = this.initInstance(web3, process.env.VUE_APP_CONTRACT, treasureAbi, address); + let gasPrice = await web3.eth.getGasPrice() + gasPrice = gasPrice * 2n + let gasLimit = await instance.methods.openBox(boxIdBN).estimateGas({ from: address }); + return instance.methods.openBox(boxIdBN).send({ from: address, gasPrice, gasLimit }); + } + + async chainClaimTask(address, taskId) { + let web3 = this.web3; + const taskIdHex = taskId.split("") + .map(c => c.charCodeAt(0).toString(16).padStart(2, "0")) + .join(""); + let taskIdBN = web3.utils.toBigInt('0x'+taskIdHex) + const instance = this.initInstance(web3, process.env.VUE_APP_CONTRACT, treasureAbi, address); + let gasPrice = await web3.eth.getGasPrice() + gasPrice = gasPrice * 2n + let gasLimit = await instance.methods.claimTaskReward(taskIdBN).estimateGas({ from: address }); + return instance.methods.claimTaskReward(taskIdBN).send({ from: address, gasPrice, gasLimit }); } }