diff --git a/src/abi/mint.js b/src/abi/mint.js index 909b7c9..335dd2a 100644 --- a/src/abi/mint.js +++ b/src/abi/mint.js @@ -1,4 +1,4 @@ - +import {Deferred} from '../utils/promise.util.js' const MINT_CONTRACT_ADDRESS=import.meta.env.VITE_CLAIMWL_ADDRESS const RPC='https://rpc.testnet.immutable.com/' @@ -18,7 +18,6 @@ const requestChain = async (rpc, method, params) => { } const res = await fetch(rpc, options) const json = await res.json() - console.log(json) if (json.error) { throw new Error(json.error.message) } @@ -40,7 +39,7 @@ export const queryMintStatus = async(user) => { const res = await queryMintData(user, data) // remove '0x', split with 64 length let nums = res.slice(2).match(/.{64}/g) - nums = nums.map(o => parseInt(o)); + nums = nums.map(o => parseInt(o, 16)); return nums } @@ -71,13 +70,82 @@ export const fetchMintConfig = async() => { export const fetchAllMintedCount = async()=> { const data = '0x34eafb11' const res = await queryMintData(MINT_CONTRACT_ADDRESS, data) - return parseInt(res) + return parseInt(res, 16) } // 已mint的NFT列表 -const fetchUserNftList = async(user) => { +export const fetchUserNftList = async(user) => { const data = '0x7d10ab3f' - return queryMintData(user, data) + const res = await queryMintData(user, data) + let nums = res.slice(2).match(/.{64}/g) + let results = [] + if (nums.length > 2) { + for (let i = 2; i < nums.length; i ++) { + results.push(BigInt('0x'+nums[i]).toString()) + } + } + return results } + +/** + * number to hex string + * @param {number} chainId + * @return {string} + */ +export function toHexChainId(chainId) { + return '0x' + chainId.toString(16) +} + +export const switchEthereumChain = async (provider, targetChainId) => { + const hexChainId = (targetChainId.indexOf('0x') >= 0) ? targetChainId : toHexChainId(targetChainId) + const deferred = new Deferred(); + const onChainChange = (chainId) => { + const chainIdNum = parseInt(chainId) + console.log('switchEthereumChain: ', chainIdNum) + provider.removeListener('chainChanged', onChainChange) + if (chainId !== hexChainId) { + deferred.reject(new Error('switch chain failed')) + return + } + deferred.resolve(chainIdNum) + } + provider.on('chainChanged', onChainChange) + try { + await provider.request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId: hexChainId }] + }) + console.log('success send switch chain request') + } catch (e) { + console.log('error switch chain: ', e) + if (e.code === 4902 || e.message.indexOf('Unrecognized chain ID') >= 0) { + try { + const data = chainCfg + await provider.request({ + method: 'wallet_addEthereumChain', + params: [ + { + chainId: hexChainId, + chainName: data.name, + nativeCurrency: { + name: data.symbol, + symbol: data.symbol, + decimals: data.decimals || 18 + }, + blockExplorerUrls: [data.explorerurl], + rpcUrls: [data.rpc] + } + ] + }) + console.log('success send add chain request') + } catch (addError) { + console.error('error add chain: ', addError) + provider.removeListener('chainChanged', onChainChange) + deferred.reject(addError) + } + } + } + return deferred.promise +} diff --git a/src/utils/promise.util.js b/src/utils/promise.util.js new file mode 100644 index 0000000..4d752ae --- /dev/null +++ b/src/utils/promise.util.js @@ -0,0 +1,69 @@ +function retry(promiseFn, options) { + let retries = 0; + let defaultOptions = { + maxRetries: 3, + whitelistErrors: [] + }; + Object.assign(defaultOptions, options); + const { maxRetries, whitelistErrors } = options; + const retryPromise = async () => { + try { + return await promiseFn(); + } catch (err) { + if (retries < maxRetries && whitelistErrors.some((whitelistedError) => err instanceof whitelistedError.constructor)) { + retries++; + return retryPromise(); + } + throw err; + } + }; + return retryPromise(); +} +var Deferred = class { + constructor() { + this.promise = new Promise((resolve, reject) => { + this._resolve = resolve; + this._reject = reject; + }); + } + resolve(value) { + this._resolve(value); + } + reject(reason) { + this._reject(reason); + } + then(onfulfilled, onrejected) { + return this.promise.then(onfulfilled, onrejected); + } + catch(onrejected) { + return this.promise.catch(onrejected); + } +}; +var PromiseQueue = class { + constructor({ concurrency = 2 }) { + this._current = 0; + this._list = []; + this.concurrency = concurrency; + } + add(promiseFn) { + this._list.push(promiseFn); + this.loadNext(); + } + loadNext() { + if (this._list.length === 0 || this.concurrency === this._current) + return; + this._current++; + const fn = this._list.shift(); + const promise = fn.call(this); + promise.then(this.onLoaded.bind(this)).catch(this.onLoaded.bind(this)); + } + onLoaded() { + this._current--; + this.loadNext(); + } +}; +export { + Deferred, + PromiseQueue, + retry +}; \ No newline at end of file diff --git a/src/view/mintIndex.vue b/src/view/mintIndex.vue index a0b3b8a..1f2ab44 100644 --- a/src/view/mintIndex.vue +++ b/src/view/mintIndex.vue @@ -712,7 +712,7 @@ import { disconnectLink, claimStage2Nft, balanceOfAmount, - isSepoliNetwork, + checkAndSwitchChain, mintConfig, fetchWLCount, fetchMintedCount @@ -827,7 +827,7 @@ const getLinkWallet = async value => { localStorage.setItem("address", res); localStorage.setItem("walletName", value); walletDialogVisible.value = false; - await isSepoliNetwork(value); + await checkAndSwitchChain(value); } else { if (value == "disconnect") { if (localStorage.getItem("walletName") == "connect") { @@ -858,7 +858,7 @@ const getLinkWallet = async value => { isWallet.value = localStorage.getItem("walletName"); getAddress.value = localStorage.getItem("address"); walletDialogVisible.value = false; - await isSepoliNetwork(value); + await checkAndSwitchChain(value); } await mintInit(); }; diff --git a/src/wallet/index.js b/src/wallet/index.js index d342bf0..aa2a5ea 100644 --- a/src/wallet/index.js +++ b/src/wallet/index.js @@ -4,7 +4,7 @@ import ERC_abi from './../abi/ImmutableERC20MinterBurnerPermit.json' import CFNFT_abi from './../abi/CFNFTGame.json' import CLAIM_abi from './../abi/NFTClaimStage2.json' import CLAIMWL_abi from './../abi/NFTClaimStage2WL.json' -import { queryMintStatus, fetchMintConfig, fetchAllMintedCount } from '../abi/mint.js' +import { queryMintStatus, fetchMintConfig, fetchAllMintedCount,switchEthereumChain,fetchUserNftList } from '../abi/mint.js' var abis = { "ERC": ERC_abi, "CFNFT": CFNFT_abi, @@ -105,30 +105,15 @@ export async function isWalletConnected() { } // 检查是否有arbitrum-sepolia网络 -export async function isSepoliNetwork(name) { - let res - if (name == 'ethereum') { - res = await window.ethereum.request({ - method: "wallet_switchEthereumChain", - params: [ - { - chainId: chainId - } - ] - }); - return false - } else if (name == 'okxwallet') { - res = - await window.ethereum.request({ - method: "wallet_switchEthereumChain", - params: [ - { - chainId: chainId - } - ] - }); - return false - } else if (name == 'connect') { +export async function checkAndSwitchChain(name) { + if (name == 'ethereum' || name == 'okxwallet') { + const provider = window[name] + const _chainId = await provider.request({ method: "eth_chainId" }); + if (_chainId != chainId) { + await switchEthereumChain(provider, chainId) + } + return true + } else { return false } } @@ -204,6 +189,7 @@ export async function addNetwork(name) { const GAS_BOOST = 2 // claim NFT export const claimStage2Nft = async (name, myAddress, params, mintPrice, web3) => { + await checkAndSwitchChain(name) const price = params * mintPrice * 1e18 console.log(BigInt(price)) const gasPrice = await web3.eth.getGasPrice() @@ -241,22 +227,11 @@ export const mintConfig = async (name, myAddress) => { // 当前用户白单数量 export const fetchWLCount = async (myAddress) => { const nums = await queryMintStatus(myAddress) - console.log(nums) return nums } // 当前用户已获得的数量 export const fetchMintedCount = async (name, myAddress) => { - let web3 - if (name == 'ethereum') { - web3 = new Web3(window.ethereum); - } else if (name == 'okxwallet') { - web3 = new Web3(okxwallet) - } else if (name == 'connect') { - web3 = new Web3(provider) - } - let contract = new web3.eth.Contract(abis['CLAIMWL'].abi, claimWlAddress, { from: myAddress }) - const tokenArr = await contract.methods.mintedNft(myAddress).call(); - return tokenArr + return fetchUserNftList(myAddress) } diff --git a/src/wallet/initPassport.js b/src/wallet/initPassport.js index 11a182c..ad9c765 100644 --- a/src/wallet/initPassport.js +++ b/src/wallet/initPassport.js @@ -1,8 +1,9 @@ import { config, passport } from '@imtbl/sdk'; console.log(import.meta.env.VITE_GPAL_ROUTER,'import.meta.env.VITE_GPAL_ROUTER') +const environment = process.env.NODE_ENV === 'production' ? config.Environment.PRODUCTION : config.Environment.SANDBOX; const passportInstance = new passport.Passport({ baseConfig: { - environment: config.Environment.SANDBOX, // or Environment.PRODUCTION + environment, // or Environment.PRODUCTION publishableKey: import.meta.env.VITE_PASSPORT_PUBLISHABLE_KEY, // replace with your publishable API key from Hub pk_imapik-tU10buLqoyLZ0o54rcub pk_imapik-test-1E-detBXtG7U$5961WuL // publishableKey: '', // replace with your publishable API key from Hub },