diff --git a/components.d.ts b/components.d.ts index 4c63999..c07c10e 100644 --- a/components.d.ts +++ b/components.d.ts @@ -30,9 +30,10 @@ declare module 'vue' { Card: typeof import('./src/components/common/card.vue')['default'] Cart: typeof import('./src/components/cart/index.vue')['default'] ChainModel: typeof import('./src/components/home/ChainModel.vue')['default'] + ChainSelectModel: typeof import('./src/components/chain/ChainSelectModel.vue')['default'] ChipCard: typeof import('./src/components/home/ChipCard.vue')['default'] Collectibles: typeof import('./src/components/assets/collectibles.vue')['default'] - copy: typeof import('./src/components/common/searchView/rank copy.vue')['default'] + copy: typeof import('./src/components/wallet/WalletModel copy.vue')['default'] GameFeatures: typeof import('./src/components/home/GameFeatures.vue')['default'] GameVideo: typeof import('./src/components/home/GameVideo.vue')['default'] Gold: typeof import('./src/components/common/searchView/gold.vue')['default'] @@ -56,7 +57,6 @@ declare module 'vue' { Please: typeof import('./src/components/global/Please.vue')['default'] Price: typeof import('./src/components/common/searchView/Price.vue')['default'] Rank: typeof import('./src/components/common/searchView/rank.vue')['default'] - 'Rank copy': typeof import('./src/components/common/searchView/rank copy.vue')['default'] Roadmap: typeof import('./src/components/about/Roadmap.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] @@ -68,6 +68,8 @@ declare module 'vue' { TeamVision: typeof import('./src/components/about/TeamVision.vue')['default'] Trading: typeof import('./src/components/assets/trading.vue')['default'] TradingCard: typeof import('./src/components/common/tradingCard.vue')['default'] + WalletModel: typeof import('./src/components/wallet/WalletModel.vue')['default'] + WalletSelectModel: typeof import('./src/components/chain/WalletSelectModel.vue')['default'] WeaponCard: typeof import('./src/components/home/WeaponCard.vue')['default'] WeaponModelLoader: typeof import('./src/components/home/WeaponModelLoader.vue')['default'] WhatCounterFire: typeof import('./src/components/home/WhatCounterFire.vue')['default'] diff --git a/src/components/chain/BlockChain.js b/src/components/chain/BlockChain.js new file mode 100644 index 0000000..9758def --- /dev/null +++ b/src/components/chain/BlockChain.js @@ -0,0 +1,20 @@ +import {PassportWallet} from '@/components/chain/PassportWallet'; +import { createSingleton } from '@/utils/singleton'; + +const LOCAL_WALLET_KEY = 'wallet_type'; + +class CBlockChain { + constructor() { + + }; + + initWallet() { + console.log('init wallet') + }; + + preparePassport() { + new PassportWallet() + }; +} + +export const BlockChain = createSingleton(CBlockChain); \ No newline at end of file diff --git a/src/components/chain/ChainSelectModel.vue b/src/components/chain/ChainSelectModel.vue new file mode 100644 index 0000000..1b14007 --- /dev/null +++ b/src/components/chain/ChainSelectModel.vue @@ -0,0 +1,151 @@ + + + + + You need to connect to supported network + + + + + {{ data.name }} + {{ data.desc }} + + + + + + diff --git a/src/components/chain/Market.js b/src/components/chain/Market.js new file mode 100644 index 0000000..aee0e54 --- /dev/null +++ b/src/components/chain/Market.js @@ -0,0 +1,222 @@ +import { baseConfig } from './PassportWallet'; +import { orderbook } from '@imtbl/sdk'; +const marketAddress = import.meta.env.VUE_APP_PASSPORT_MARKET_ADDRESS + +const NATIVE = 'NATIVE' +const ERC20 = 'ERC20' + +class ImtblMarket { + constructor() { + this.client = new orderbook.Orderbook({ baseConfig }); + } + + updateProvider(provider) { + this.provider = provider; + this.signer = this.provider.getSigner(); + } + + /** + * 查询某个nft的所有挂单 + * @param {*} contractAddress + * @returns + */ + async listListings(contractAddress){ + const listOfListings = await this.client.listListings({ + sellItemContractAddress: contractAddress, + status: orderbook.OrderStatusName.ACTIVE, + pageSize: 50, + }); + return listOfListings; + }; + + /** + * 准备一个ERC721的挂单 + * @returns + */ + async _prepareERC721Listing({ contractAddress, tokenId, type = 'ERC721', currencyAddress, currencyAmount}){ + const offerer = await this.signer.getAddress(); + const buyData = { + amount: currencyAmount, + } + if (currencyAddress == NATIVE) { + buyData.type = NATIVE + } else { + buyData.type = ERC20 + buyData.contractAddress = currencyAddress + } + const preparedListing = await this.client.prepareListing({ + makerAddress: offerer, + buy: buyData, + sell: { + contractAddress, + tokenId, + type, + }, + }); + + let orderSignature = '' + for (const action of preparedListing.actions) { + // If the user hasn't yet approved the Immutable Seaport contract to transfer assets from this + // collection on their behalf they'll need to do so before they create an order + if (action.type === orderbook.ActionType.TRANSACTION) { + const builtTx = await action.buildTransaction() + console.log(`Submitting ${action.purpose} transaction`) + await signer.sendTransaction(builtTx); + } + + // For an order to be created (and subsequently filled), Immutable needs a valid signature for the order data. + // This signature is stored off-chain and is later provided to any user wishing to fulfil the open order. + // The signature only allows the order to be fulfilled if it meets the conditions specified by the user that created the listing. + if (action.type === orderbook.ActionType.SIGNABLE) { + orderSignature = await signer._signTypedData( + action.message.domain, + action.message.types, + action.message.value, + ) + } + } + + return { preparedListing, orderSignature } + } + /** + * 创建一个挂单 + * @param {*} preparedListing + * @param {*} orderSignature + */ + async _createListing( + preparedListing, + orderSignature, + currencyAmount + ){ + const amount = (BigInt(currencyAmount) * 2n / 100n).toString() + const order = await this.client.createListing({ + orderComponents: preparedListing.orderComponents, + orderHash: preparedListing.orderHash, + orderSignature, + // Optional maker marketplace fee + makerFees: [{ + amount, + recipientAddress: marketAddress, // Replace address with your own marketplace address + }], + }); + console.log('order:', order); + return order + }; + + /** + * 出售一个ERC721的NFT + * doc: https://docs.immutable.com/docs/zkEVM/products/orderbook/create-listing + * @param {string} contractAddress NFT的合约地址 + * @param {string} tokenId NFT的tokenId + * @param {string} currencyAddress NATIVE 或者 ERC20的合约地址 + * @param {string} currencyAmount 出售价格, 单位 wei + */ + async beginSellERC721({contractAddress, tokenId, currencyAddress, currencyAmount}) { + const { preparedListing, orderSignature } = + await this._prepareERC721Listing({contractAddress, tokenId, currencyAddress, currencyAmount}); + const order = await this._createListing(preparedListing, orderSignature, currencyAmount); + return order + } + /** + * 开始购买 + * doc: https://docs.immutable.com/docs/zkEVM/products/orderbook/fill + * @param {*} listingId + */ + async beginBuy(listingId) { + const fulfiller = await this.signer.getAddress(); + // const fulfiller = marketAddress + console.log(listingId,fulfiller) + const { actions, expiration, order } = await this.client.fulfillOrder( + listingId, + fulfiller, + [] + ); + console.log(`Fulfilling listing ${order}, transaction expiry ${expiration}`); + for (const action of actions) { + if (action.type === orderbook.ActionType.TRANSACTION) { + const builtTx = await action.buildTransaction(); + console.log(`Submitting ${action.purpose} transaction`); + await signer.sendTransaction(builtTx); + } + } + } + /** + * 批量购买 + * doc: https://docs.immutable.com/docs/zkEVM/products/orderbook/fill-bulk + * @param { string[] } listingIds: listingId列表 + */ + async batchBuy(listingIds) { + const fulfiller = await this.signer.getAddress(); + // console.log(listingIds, marketAddress,'---') + // return + try { + const fulfillResponse = await this.client.fulfillBulkOrders( + listingIds.map((listingId) => ({ + listingId, + // you could have up to 2 marketplace fees + takerFees: [], + })), + fulfiller + ); + + if (fulfillResponse.sufficientBalance) { + const { actions, expiration, fulfillableOrders, unfulfillableOrders } = fulfillResponse; + // depending on the application, we can either throw an error if some orders are not fulfillable + // or we can ignore these unfulfillable orders and proceed with fulfillment + if (unfulfillableOrders.length > 0) { + throw new Error( + `Not all orders are fulfillable - unfulfillable orders: ${unfulfillableOrders}` + ); + } + for (const action of actions) { + if (action.type === orderbook.ActionType.TRANSACTION) { + const builtTx = await action.buildTransaction(); + console.log(`Submitting ${action.purpose} transaction`); + await signer.sendTransaction(builtTx); + } + } + console.log( + `Fulfilling listings ${fulfillableOrders}, transaction expiry ${expiration}` + ); + } + } catch (e) { + console.error(`Fulfill bulk orders request failed with ${e}`); + throw e; + } + } + /** + * 取消交易 + * doc: https://docs.immutable.com/docs/zkEVM/products/orderbook/cancel + * @param {*} listingIds + * @returns + */ + async cancelOrder(listingIds) { + const account = await this.signer.getAddress(); + const { signableAction } = await this.client.prepareOrderCancellations(listingIds); + const cancellationSignature = await this.signer._signTypedData( + signableAction.message.domain, + signableAction.message.types, + signableAction.message.value, + ) + return this.client.cancelOrders(listingIds, account, cancellationSignature) + } + /** + * 取消交易, onChain + * doc: https://docs.immutable.com/docs/zkEVM/products/orderbook/cancel + * @param {*} listingIds + * @returns + */ + async cancelOrdersOnChain(listingIds) { + const offerer = await this.signer.getAddress(); + const { cancellationAction } = await this.client.cancelOrdersOnChain( + listingIds, + offerer + ); + + const unsignedCancelOrderTransaction = await cancellationAction.buildTransaction(); + const receipt = await this.signer.sendTransaction(unsignedCancelOrderTransaction); + return receipt; + } +} + +export const Market = createSingleton(ImtblMarket) \ No newline at end of file diff --git a/src/components/chain/PassportWallet.js b/src/components/chain/PassportWallet.js new file mode 100644 index 0000000..5e2887f --- /dev/null +++ b/src/components/chain/PassportWallet.js @@ -0,0 +1,74 @@ +import { config, passport, orderbook, checkout } from '@imtbl/sdk'; +import { createSingleton } from '@/utils/singleton'; +import { providers } from 'ethers'; + +const environment = process.env.NODE_ENV === 'production' ? config.Environment.PRODUCTION : config.Environment.SANDBOX; +const publishableKey = import.meta.env.VUE_APP_PASSPORT_PUBLISHABLE_KEY +const clientId = import.meta.env.VUE_APP_PASSPORT_CLIENT_ID +const redirectUri = import.meta.env.VUE_APP_PASSPORT_REDIRECT_URI +const logoutRedirectUri = import.meta.env.VUE_APP_PASSPORT_LOGOUT_URI + + +export const baseConfig = { environment, publishableKey } +class LPassportWallet { + constructor() { + this.passportInstance = new passport.Passport({ + baseConfig, + clientId, // replace with your client ID from Hub + redirectUri, // replace with one of your redirect URIs from Hub + logoutRedirectUri, // replace with one of your logout URIs from Hub + audience: 'platform_api', + scope: 'openid offline_access email transact', + popupOverlayOptions: { + disableGenericPopupOverlay: false, // Set to true to disable the generic pop-up overlay + disableBlockedPopupOverlay: false, // Set to true to disable the blocked pop-up overlay + } + }); + this.passportInstance.loginCallback().then(()=>{}).catch(err=>{}); + this.client = new orderbook.Orderbook({ baseConfig }); + } + async initWidget() { + const checkoutSDK = new checkout.Checkout({ + baseConfig, + passport: this.passportInstance, + bridge: { enable: true }, + swap: { enable: true }, + onRamp: { enable: true } + }); + + const widgets = await checkoutSDK.widgets({ + config: { theme: checkout.WidgetTheme.DARK }, + }); + + // RECOMMENDED - create all of the widgets once at the start of your application + // use the created widgets throughout your application to mount and unmount in specific parts of your application + const connect = widgets.create(checkout.WidgetType.CONNECT); + const wallet = widgets.create(checkout.WidgetType.WALLET); // you can optionally pass in additional config per widget + const swap = widgets.create(checkout.WidgetType.SWAP); + const bridge = widgets.create(checkout.WidgetType.BRIDGE); + const onramp = widgets.create(checkout.WidgetType.ONRAMP); + + // Mount the wallet widget passing the element id of where to mount the widget + connect.mount('wallet'); + } + get nativeProvider() { + return this.passportInstance.connectEvm(); + } + + get web3Provider() { + const passportProvider = this.passportInstance.connectEvm(); + return new providers.Web3Provider(passportProvider); + } + + + async getAccessToken() { + return await this.passportInstance.getAccessToken(); + } + + async logout() { + await this.passportInstance.logout(); + } + +} + +export const PassportWallet = createSingleton(LPassportWallet) \ No newline at end of file diff --git a/src/components/chain/WalletSelectModel.vue b/src/components/chain/WalletSelectModel.vue new file mode 100644 index 0000000..d4bb427 --- /dev/null +++ b/src/components/chain/WalletSelectModel.vue @@ -0,0 +1,160 @@ + + + + + You need to connect to supported network + + + + + {{ data.name }} + {{ data.desc }} + + + + + + diff --git a/src/components/layout/NavBar.vue b/src/components/layout/NavBar.vue index c28380a..a75b5b7 100644 --- a/src/components/layout/NavBar.vue +++ b/src/components/layout/NavBar.vue @@ -71,6 +71,8 @@ import { useCopyToClipboard } from "./../../hooks/useCopyToClipboard"; import { PassportWallet } from "@/wallet/passPort" import { useImmutableStore } from "@/store/immutable" import { useMarketplaceStore } from "@/store/marketplace" +import WalletSelectModel from "@/components/chain/WalletSelectModel.vue" +import { createModal } from "@/utils/model.util" import Cart from "@/components/cart/index.vue" @@ -228,28 +230,32 @@ watchEffect(() => { // -------------------------------- const immuTableLogin = async () => { - try{ - const walletLogin = await new PassportWallet().connect() - immutableStore.accessToken = walletLogin.accessToken - immutableStore.accounts = walletLogin.accounts[0] - localStorage.setItem('assessToken', walletLogin.accessToken) - localStorage.setItem('assessAddress', walletLogin.accounts[0]) - // console.log(walletLogin) - /* - accessToken - accounts - profile: + let rewardModal = createModal(WalletSelectModel, {}) + + let result = await rewardModal.show() + console.log(`select result : ${result.errcode}`) + // try{ + // const walletLogin = await new PassportWallet().connect() + // immutableStore.accessToken = walletLogin.accessToken + // immutableStore.accounts = walletLogin.accounts[0] + // localStorage.setItem('assessToken', walletLogin.accessToken) + // localStorage.setItem('assessAddress', walletLogin.accounts[0]) + // // console.log(walletLogin) + // /* + // accessToken + // accounts + // profile: - */ - // loginShowMenu.value = !loginShowMenu.value; - // const list = await new PassportWallet().beginSellERC721({ - // contractAddress: '', - // tokenId: '' - // }); - // console.log(list) - } catch (e) { - console.log(e); - } + // */ + // // loginShowMenu.value = !loginShowMenu.value; + // // const list = await new PassportWallet().beginSellERC721({ + // // contractAddress: '', + // // tokenId: '' + // // }); + // // console.log(list) + // } catch (e) { + // console.log(e); + // } } const immuTableLogout = async () => { diff --git a/src/configs/configchain.js b/src/configs/configchain.js index a0e4eeb..3d338f9 100644 --- a/src/configs/configchain.js +++ b/src/configs/configchain.js @@ -9,9 +9,15 @@ export const ALL_PROVIDERS = [ }, { id: 2, - name: "WalletConnect", + name: "OKX", logo: "data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjUxMiIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHdpZHRoPSI1MTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxyYWRpYWxHcmFkaWVudCBpZD0iYSIgY3g9IjAlIiBjeT0iNTAlIiByPSIxMDAlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiM1ZDlkZjYiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMwMDZmZmYiLz48L3JhZGlhbEdyYWRpZW50PjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+PHBhdGggZD0ibTI1NiAwYzE0MS4zODQ4OTYgMCAyNTYgMTE0LjYxNTEwNCAyNTYgMjU2cy0xMTQuNjE1MTA0IDI1Ni0yNTYgMjU2LTI1Ni0xMTQuNjE1MTA0LTI1Ni0yNTYgMTE0LjYxNTEwNC0yNTYgMjU2LTI1NnoiIGZpbGw9InVybCgjYSkiLz48cGF0aCBkPSJtNjQuNjkxNzU1OCAzNy43MDg4Mjk4YzUxLjUzMjgwNzItNTAuMjc4NDM5NyAxMzUuMDgzOTk0Mi01MC4yNzg0Mzk3IDE4Ni42MTY3OTkyIDBsNi4yMDIwNTcgNi4wNTEwOTA2YzIuNTc2NjQgMi41MTM5MjE4IDIuNTc2NjQgNi41ODk3OTQ4IDAgOS4xMDM3MTc3bC0yMS4yMTU5OTggMjAuNjk5NTc1OWMtMS4yODgzMjEgMS4yNTY5NjE5LTMuMzc3MSAxLjI1Njk2MTktNC42NjU0MjEgMGwtOC41MzQ3NjYtOC4zMjcwMjA1Yy0zNS45NTA1NzMtMzUuMDc1NDk2Mi05NC4yMzc5NjktMzUuMDc1NDk2Mi0xMzAuMTg4NTQ0IDBsLTkuMTQwMDI4MiA4LjkxNzU1MTljLTEuMjg4MzIxNyAxLjI1Njk2MDktMy4zNzcxMDE2IDEuMjU2OTYwOS00LjY2NTQyMDggMGwtMjEuMjE1OTk3My0yMC42OTk1NzU5Yy0yLjU3NjY0MDMtMi41MTM5MjI5LTIuNTc2NjQwMy02LjU4OTc5NTggMC05LjEwMzcxNzd6bTIzMC40OTM0ODUyIDQyLjgwODkxMTcgMTguODgyMjc5IDE4LjQyMjcyNjJjMi41NzY2MjcgMi41MTM5MTAzIDIuNTc2NjQyIDYuNTg5NzU5My4wMDAwMzIgOS4xMDM2ODYzbC04NS4xNDE0OTggODMuMDcwMzU4Yy0yLjU3NjYyMyAyLjUxMzk0MS02Ljc1NDE4MiAyLjUxMzk2OS05LjMzMDg0LjAwMDA2Ni0uMDAwMDEtLjAwMDAxLS4wMDAwMjMtLjAwMDAyMy0uMDAwMDMzLS4wMDAwMzRsLTYwLjQyODI1Ni01OC45NTc0NTFjLS42NDQxNi0uNjI4NDgxLTEuNjg4NTUtLjYyODQ4MS0yLjMzMjcxIDAtLjAwMDAwNC4wMDAwMDQtLjAwMDAwOC4wMDAwMDctLjAwMDAxMi4wMDAwMTFsLTYwLjQyNjk2ODMgNTguOTU3NDA4Yy0yLjU3NjYxNDEgMi41MTM5NDctNi43NTQxNzQ2IDIuNTEzOTktOS4zMzA4NDA4LjAwMDA5Mi0uMDAwMDE1MS0uMDAwMDE0LS4wMDAwMzA5LS4wMDAwMjktLjAwMDA0NjctLjAwMDA0NmwtODUuMTQzODY3NzQtODMuMDcxNDYzYy0yLjU3NjYzOTI4LTIuNTEzOTIxLTIuNTc2NjM5MjgtNi41ODk3OTUgMC05LjEwMzcxNjNsMTguODgyMzEyNjQtMTguNDIyNjk1NWMyLjU3NjYzOTMtMi41MTM5MjIyIDYuNzU0MTk5My0yLjUxMzkyMjIgOS4zMzA4Mzk3IDBsNjAuNDI5MTM0NyA1OC45NTgyNzU4Yy42NDQxNjA4LjYyODQ4IDEuNjg4NTQ5NS42Mjg0OCAyLjMzMjcxMDMgMCAuMDAwMDA5NS0uMDAwMDA5LjAwMDAxODItLjAwMDAxOC4wMDAwMjc3LS4wMDAwMjVsNjAuNDI2MTA2NS01OC45NTgyNTA4YzIuNTc2NTgxLTIuNTEzOTggNi43NTQxNDItMi41MTQwNzQzIDkuMzMwODQtLjAwMDIxMDMuMDAwMDM3LjAwMDAzNTQuMDAwMDcyLjAwMDA3MDkuMDAwMTA3LjAwMDEwNjNsNjAuNDI5MDU2IDU4Ljk1ODM1NDhjLjY0NDE1OS42Mjg0NzkgMS42ODg1NDkuNjI4NDc5IDIuMzMyNzA5IDBsNjAuNDI4MDc5LTU4Ljk1NzE5MjVjMi41NzY2NC0yLjUxMzkyMzEgNi43NTQxOTktMi41MTM5MjMxIDkuMzMwODM5IDB6IiBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHRyYW5zZm9ybT0idHJhbnNsYXRlKDk4IDE2MCkiLz48L2c+PC9zdmc+", - desc: "Scan with WalletConnect to connect", + desc: "Connect to your OKX Wallet", + }, + { + id: 3, + name: "Passport", + logo: "data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjUxMiIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHdpZHRoPSI1MTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxyYWRpYWxHcmFkaWVudCBpZD0iYSIgY3g9IjAlIiBjeT0iNTAlIiByPSIxMDAlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiM1ZDlkZjYiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMwMDZmZmYiLz48L3JhZGlhbEdyYWRpZW50PjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+PHBhdGggZD0ibTI1NiAwYzE0MS4zODQ4OTYgMCAyNTYgMTE0LjYxNTEwNCAyNTYgMjU2cy0xMTQuNjE1MTA0IDI1Ni0yNTYgMjU2LTI1Ni0xMTQuNjE1MTA0LTI1Ni0yNTYgMTE0LjYxNTEwNC0yNTYgMjU2LTI1NnoiIGZpbGw9InVybCgjYSkiLz48cGF0aCBkPSJtNjQuNjkxNzU1OCAzNy43MDg4Mjk4YzUxLjUzMjgwNzItNTAuMjc4NDM5NyAxMzUuMDgzOTk0Mi01MC4yNzg0Mzk3IDE4Ni42MTY3OTkyIDBsNi4yMDIwNTcgNi4wNTEwOTA2YzIuNTc2NjQgMi41MTM5MjE4IDIuNTc2NjQgNi41ODk3OTQ4IDAgOS4xMDM3MTc3bC0yMS4yMTU5OTggMjAuNjk5NTc1OWMtMS4yODgzMjEgMS4yNTY5NjE5LTMuMzc3MSAxLjI1Njk2MTktNC42NjU0MjEgMGwtOC41MzQ3NjYtOC4zMjcwMjA1Yy0zNS45NTA1NzMtMzUuMDc1NDk2Mi05NC4yMzc5NjktMzUuMDc1NDk2Mi0xMzAuMTg4NTQ0IDBsLTkuMTQwMDI4MiA4LjkxNzU1MTljLTEuMjg4MzIxNyAxLjI1Njk2MDktMy4zNzcxMDE2IDEuMjU2OTYwOS00LjY2NTQyMDggMGwtMjEuMjE1OTk3My0yMC42OTk1NzU5Yy0yLjU3NjY0MDMtMi41MTM5MjI5LTIuNTc2NjQwMy02LjU4OTc5NTggMC05LjEwMzcxNzd6bTIzMC40OTM0ODUyIDQyLjgwODkxMTcgMTguODgyMjc5IDE4LjQyMjcyNjJjMi41NzY2MjcgMi41MTM5MTAzIDIuNTc2NjQyIDYuNTg5NzU5My4wMDAwMzIgOS4xMDM2ODYzbC04NS4xNDE0OTggODMuMDcwMzU4Yy0yLjU3NjYyMyAyLjUxMzk0MS02Ljc1NDE4MiAyLjUxMzk2OS05LjMzMDg0LjAwMDA2Ni0uMDAwMDEtLjAwMDAxLS4wMDAwMjMtLjAwMDAyMy0uMDAwMDMzLS4wMDAwMzRsLTYwLjQyODI1Ni01OC45NTc0NTFjLS42NDQxNi0uNjI4NDgxLTEuNjg4NTUtLjYyODQ4MS0yLjMzMjcxIDAtLjAwMDAwNC4wMDAwMDQtLjAwMDAwOC4wMDAwMDctLjAwMDAxMi4wMDAwMTFsLTYwLjQyNjk2ODMgNTguOTU3NDA4Yy0yLjU3NjYxNDEgMi41MTM5NDctNi43NTQxNzQ2IDIuNTEzOTktOS4zMzA4NDA4LjAwMDA5Mi0uMDAwMDE1MS0uMDAwMDE0LS4wMDAwMzA5LS4wMDAwMjktLjAwMDA0NjctLjAwMDA0NmwtODUuMTQzODY3NzQtODMuMDcxNDYzYy0yLjU3NjYzOTI4LTIuNTEzOTIxLTIuNTc2NjM5MjgtNi41ODk3OTUgMC05LjEwMzcxNjNsMTguODgyMzEyNjQtMTguNDIyNjk1NWMyLjU3NjYzOTMtMi41MTM5MjIyIDYuNzU0MTk5My0yLjUxMzkyMjIgOS4zMzA4Mzk3IDBsNjAuNDI5MTM0NyA1OC45NTgyNzU4Yy42NDQxNjA4LjYyODQ4IDEuNjg4NTQ5NS42Mjg0OCAyLjMzMjcxMDMgMCAuMDAwMDA5NS0uMDAwMDA5LjAwMDAxODItLjAwMDAxOC4wMDAwMjc3LS4wMDAwMjVsNjAuNDI2MTA2NS01OC45NTgyNTA4YzIuNTc2NTgxLTIuNTEzOTggNi43NTQxNDItMi41MTQwNzQzIDkuMzMwODQtLjAwMDIxMDMuMDAwMDM3LjAwMDAzNTQuMDAwMDcyLjAwMDA3MDkuMDAwMTA3LjAwMDEwNjNsNjAuNDI5MDU2IDU4Ljk1ODM1NDhjLjY0NDE1OS42Mjg0NzkgMS42ODg1NDkuNjI4NDc5IDIuMzMyNzA5IDBsNjAuNDI4MDc5LTU4Ljk1NzE5MjVjMi41NzY2NC0yLjUxMzkyMzEgNi43NTQxOTktMi41MTM5MjMxIDkuMzMwODM5IDB6IiBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9Im5vbnplcm8iIHRyYW5zZm9ybT0idHJhbnNsYXRlKDk4IDE2MCkiLz48L2c+PC9zdmc+", + desc: "Connect with immutable Passport", }, ]; diff --git a/src/main.js b/src/main.js index cea4c19..f12662f 100644 --- a/src/main.js +++ b/src/main.js @@ -18,8 +18,8 @@ import { notification } from 'ant-design-vue'; import { createPinia } from 'pinia' import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' -import {PassportWallet} from '@/wallet/passPort'; -const passPortCallback = new PassportWallet() +import { BlockChain } from '@/components/chain/BlockChain'; +new BlockChain().preparePassport(); const pinia = createPinia() pinia.use(piniaPluginPersistedstate) @@ -40,6 +40,5 @@ app .use(VueAnimXyz) .use(vue3dLoader) .use(Antd) - .use(passPortCallback) .use(router) .mount("#app"); diff --git a/src/utils/model.util.js b/src/utils/model.util.js new file mode 100644 index 0000000..5d84857 --- /dev/null +++ b/src/utils/model.util.js @@ -0,0 +1,28 @@ +import {ref, render, createVNode} from 'vue' +import { Deferred } from './promise.util'; + +// 动态创建Component, 并append至body, 返回一个对象, 用于调用Component的方法 +export const createModal = (Component, props) => { + const visible = ref(false); + props.visible = visible; + const container = document.createElement('div') + document.body.appendChild(container) + const deferred = new Deferred(); + const show = () => { + visible.value = true; + return deferred.promise; + }; + + const close = (result) => { + visible.value = false; + container.remove(); + deferred.resolve(result); + }; + props.close = close; + const vnode = createVNode(Component, props) + render(vnode, container) + return { + close, + show + } +} 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/wallet/passPort.js b/src/wallet/passPort.js index 1021f9a..cbf250c 100644 --- a/src/wallet/passPort.js +++ b/src/wallet/passPort.js @@ -27,7 +27,7 @@ class LPassportWallet { disableBlockedPopupOverlay: false, // Set to true to disable the blocked pop-up overlay } }); - this.passportInstance.loginCallback(); + this.passportInstance.loginCallback().then(()=>{}).catch(err=>{}); this.client = new orderbook.Orderbook({ baseConfig }); } async initWidget() { @@ -55,8 +55,6 @@ class LPassportWallet { connect.mount('wallet'); } async connect() { - // const profile = await this.passportInstance.login(); - // console.log(profile,'-----------------------------------------------------------------') const passportProvider = this.passportInstance.connectEvm(); this.web3Provider = new providers.Web3Provider(passportProvider); this.signer = this.web3Provider.getSigner();