整理上链流程

This commit is contained in:
CounterFire2023 2024-06-21 16:47:19 +08:00
parent f26f278cec
commit 1ec2178fc9
12 changed files with 766 additions and 31 deletions

6
components.d.ts vendored
View File

@ -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']

View File

@ -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);

View File

@ -0,0 +1,151 @@
<template>
<div class="chain-modal" v-if="props.visible" :class="{ mobile: 'mobile' }">
<div class="modal-bg" @click="cancelSelect"></div>
<div class="modal-content" :class="{ mobile: 'mobile' }">
<div class="modal-title">You need to connect to supported network</div>
<div
class="chain-modal-card"
v-for="data in currentDatas"
:key="data.name"
@click="cardClicked(data.id)"
>
<div class="icon">
<img :src="data.logo" :alt="data.name" />
</div>
<div class="name">{{ data.name }}</div>
<div class="desc">{{ data.desc }}</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from "vue";
import { useChainStore } from "@/store/chain";
const chain = useChainStore();
const props = defineProps({
visible: Boolean,
close: Function,
});
const chainDatas = computed(() => {
return [...chain.chainManager.availableChains.values()];
});
const currentDatas = computed(() => {
return chainDatas.value;
});
function cardClicked(id) {
hideModal(id);
}
function cancelSelect() {
hideModal({errcode: 1, errmsg: "user cancel select chain"});
}
function hideModal(result = null) {
props.close(result);
}
</script>
<style lang="scss" scoped>
.chain-modal {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: auto;
margin: 0;
z-index: 10;
.modal-bg {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: auto;
margin: 0;
background-color: #000000a3;
}
.modal-content {
width: 500px;
max-height: 400px;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
display: flex;
flex-direction: column;
.mobile {
width: 100vw;
}
.modal-title {
background-color: rgb(255, 255, 255);
color: black;
border-radius: 12px 12px 0 0;
padding: 15px 20px;
border-bottom: 1px solid rgba(195, 195, 195, 0.14);
}
.chain-modal-card {
background-color: rgb(255, 255, 255);
transition: background-color 0.2s ease-in-out 0s;
display: flex;
flex-direction: column;
-webkit-box-pack: center;
justify-content: center;
-webkit-box-align: center;
align-items: center;
padding: 24px 16px;
text-align: center;
cursor: pointer;
&:first-child {
border-radius: 12px 12px 0 0;
}
&:not(:first-child) {
border-top: 1px solid rgba(195, 195, 195, 0.14);
}
&:last-child {
border-radius: 0 0 12px 12px;
}
.icon {
width: 45px;
height: 45px;
display: flex;
border-radius: 50%;
overflow: visible;
box-shadow: none;
-webkit-box-pack: center;
justify-content: center;
-webkit-box-align: center;
align-items: center;
img {
width: 100%;
height: 100%;
}
.icon-svg {
width: 100%;
height: 100%;
fill: currentColor;
color: unset;
stroke: none;
}
}
.name {
width: 100%;
font-size: 24px;
font-weight: 700;
margin-top: 0.5em;
color: rgb(12, 12, 13);
}
.desc {
width: 100%;
font-size: 18px;
margin: 0.333em 0px;
color: rgb(169, 169, 188);
}
}
}
}
</style>

View File

@ -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)

View File

@ -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)

View File

@ -0,0 +1,160 @@
<template>
<div class="chain-modal" v-if="props.visible" :class="{ mobile: 'mobile' }">
<div class="modal-bg" @click="cancelSelect"></div>
<div class="modal-content" :class="{ mobile: 'mobile' }">
<div class="modal-title">You need to connect to supported network</div>
<div
class="chain-modal-card"
v-for="data in currentDatas"
:key="data.name"
@click="cardClicked(data.id)"
>
<div class="icon">
<img :src="data.logo" :alt="data.name" />
</div>
<div class="name">{{ data.name }}</div>
<div class="desc">{{ data.desc }}</div>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from "vue";
import { ALL_PROVIDERS } from "@/configs/configchain";
import { PassportWallet } from '@/components/chain/PassportWallet';
import { providers } from "ethers"
const props = defineProps({
visible: Boolean,
close: Function,
});
const allProviders = {
1: window.ethereum,
2: window.okxwallet,
3: new PassportWallet().nativeProvider
}
const currentDatas = computed(() => {
return ALL_PROVIDERS;
});
async function cardClicked(id) {
console.log("card clicked:", id);
const provider = allProviders[id];
const web3Provider = new providers.Web3Provider(provider);
const accounts = await web3Provider.provider.request({ method: "eth_requestAccounts" });
console.log(accounts)
hideModal({errcode: 0, provider: web3Provider, wallet: id, accounts});
}
function cancelSelect() {
hideModal({errcode: 1, errmsg: "user cancel select wallet"});
}
function hideModal(result = null) {
props.close(result);
}
</script>
<style lang="scss" scoped>
.chain-modal {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: auto;
margin: 0;
z-index: 10;
.modal-bg {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: auto;
margin: 0;
background-color: #000000a3;
}
.modal-content {
width: 500px;
max-height: 400px;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
display: flex;
flex-direction: column;
.mobile {
width: 100vw;
}
.modal-title {
background-color: rgb(255, 255, 255);
color: black;
border-radius: 12px 12px 0 0;
padding: 15px 20px;
border-bottom: 1px solid rgba(195, 195, 195, 0.14);
}
.chain-modal-card {
background-color: rgb(255, 255, 255);
transition: background-color 0.2s ease-in-out 0s;
display: flex;
flex-direction: column;
-webkit-box-pack: center;
justify-content: center;
-webkit-box-align: center;
align-items: center;
padding: 24px 16px;
text-align: center;
cursor: pointer;
&:first-child {
border-radius: 12px 12px 0 0;
}
&:not(:first-child) {
border-top: 1px solid rgba(195, 195, 195, 0.14);
}
&:last-child {
border-radius: 0 0 12px 12px;
}
.icon {
width: 45px;
height: 45px;
display: flex;
border-radius: 50%;
overflow: visible;
box-shadow: none;
-webkit-box-pack: center;
justify-content: center;
-webkit-box-align: center;
align-items: center;
img {
width: 100%;
height: 100%;
}
.icon-svg {
width: 100%;
height: 100%;
fill: currentColor;
color: unset;
stroke: none;
}
}
.name {
width: 100%;
font-size: 24px;
font-weight: 700;
margin-top: 0.5em;
color: rgb(12, 12, 13);
}
.desc {
width: 100%;
font-size: 18px;
margin: 0.333em 0px;
color: rgb(169, 169, 188);
}
}
}
}
</style>

View File

@ -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, {})
*/
// loginShowMenu.value = !loginShowMenu.value;
// const list = await new PassportWallet().beginSellERC721({
// contractAddress: '',
// tokenId: ''
// });
// console.log(list)
} catch (e) {
console.log(e);
}
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);
// }
}
const immuTableLogout = async () => {

View File

@ -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",
},
];

View File

@ -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");

28
src/utils/model.util.js Normal file
View File

@ -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
}
}

69
src/utils/promise.util.js Normal file
View File

@ -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
};

View File

@ -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();