Merge branch 'new-CounterFire' of http://git.kingsome.cn/huangjinming/CounterFireGames into new-CounterFire

This commit is contained in:
yuyongdong 2024-06-26 14:16:09 +08:00
commit d3170e6337
12 changed files with 362 additions and 37 deletions

View File

@ -6,8 +6,8 @@ VUE_APP_GPAL_API='https://game2006api.cebggame.com/'
VUE_APP_PASSPORT_PUBLISHABLE_KEY=pk_imapik-test-eRr-kyOKaZ0jIdrvrPCn
VUE_APP_PASSPORT_REDIRECT_URI=http://localhost:4000/marketplace
VUE_APP_PASSPORT_LOGOUT_URI=http://localhost:4000/
# VUE_APP_PASSPORT_CLIENT_ID=eTmUah69p7ZdRhRYzBta6lZRKXXeXDYj
VUE_APP_PASSPORT_CLIENT_ID=0FNfXxQywm7wjdbyLTDzWt4txc53yRrT
VUE_APP_PASSPORT_CLIENT_ID=eTmUah69p7ZdRhRYzBta6lZRKXXeXDYj
#VUE_APP_PASSPORT_CLIENT_ID=0FNfXxQywm7wjdbyLTDzWt4txc53yRrT
VUE_APP_PASSPORT_MARKET_ADDRESS=0x7d117aA8BD6D31c4fa91722f246388f38ab1942c
VUE_APP_MKT_API='https://market-test.kingsome.cn'
VUE_APP_NET_ID='13473'

View File

@ -4,10 +4,12 @@ import { OkxWallet } from '@/components/chain/wallet/OkxWallet';
import {walletStore} from "@/store/wallet";
import WalletSelectModel from "@/components/chain/WalletSelectModel.vue";
import {createModal} from "@/utils/model.util";
import {isTokenExpired, genRefreshToken, cfgChainId, switchEthereumChain} from "@/components/chain/utils"
import {ImtblMarket} from "@/components/chain/Market";
import { ALL_PROVIDERS } from "@/configs/configchain";
import {Locker} from "@/components/chain/contract/Locker";
export const allProviders = {
1: MetaMaskWallet,
2: OkxWallet,
@ -43,50 +45,85 @@ export class BlockChain {
new PassportWallet();
}
async restoreWallet(walletType) {
this.wallet = new allProviders[walletType]();
const { provider, token } = await this.wallet.web3Provider();
this.provider = provider
this.token = token
async updateInfo({provider, accounts}) {
this.web3Provider = provider
if (!this.store.token) {
const {token, refreshToken}= await this.wallet.getAccessToken();
this.store.token = token
this.store.refreshToken = refreshToken
} else {
if (isTokenExpired(3600, this.store.token)) {
if (this.store.refreshToken && !isTokenExpired(300, this.store.refreshToken)) {
const {token, refreshToken} = await genRefreshToken(this.store.refreshToken);
this.store.token = token;
this.store.refreshToken = refreshToken;
} else {
const {token, refreshToken}= await this.wallet.getAccessToken();
this.store.token = token
this.store.refreshToken = refreshToken
}
}
}
this.store.address = accounts[0];
this.store.$persist();
this.market.updateProvider(provider);
return provider;
}
async restoreWallet(walletType) {
this.wallet = new allProviders[walletType]();
const { provider, accounts } = await this.wallet.web3Provider();
await this.updateInfo({provider, accounts })
return provider;
}
async connect() {
// if this only one provider configed, use it directly
if (ALL_PROVIDERS.length === 1) {
const walletType = ALL_PROVIDERS[0].id
this.wallet = new allProviders[walletType]();
const { provider, accounts, token } = await this.wallet.web3Provider();
this.provider = provider
this.market.updateProvider(provider);
this.store.walletType = walletType;
this.store.address = accounts[0];
this.token = token
this.store.$persist();
return
const { provider, accounts } = await this.wallet.web3Provider();
await this.updateInfo({ provider, accounts })
return provider;
}
const rewardModal = createModal(WalletSelectModel, {});
let result = await rewardModal.show();
const result = await rewardModal.show();
if (!result.errcode) {
this.provider = result.provider;
this.market.updateProvider(this.provider);
this.wallet = new allProviders[result.wallet]();
this.store.walletType = result.wallet;
this.store.address = result.accounts[0];
this.token = token
this.store.$persist();
this.wallet = new allProviders[result.wallet]();
await this.updateInfo(result)
return result.provider
} else {
console.log(`select result : ${result.errmsg}`);
throw new Error(result.errmsg);
}
}
get token() {
const suffix = (this.store.walletType == 2 || this.store.walletType == 1) ? '.cf' : ''
return this.store.token+suffix
}
async logout() {
this.token = '';
this.store.reset();
this.store.$persist();
await this.wallet.logout();
}
async getChainId() {
return this.wallet.getChainId();
}
/**
* 检查并切换到目标链, 各上链前须调用该方法
*/
async checkAndChangeChain() {
let chainId = await this.getChainId();
if (chainId !== cfgChainId) {
console.log(`current chain: ${chainId}, want: ${cfgChainId}`)
chainId = await switchEthereumChain(this.web3Provider.provider, cfgChainId);
}
}
}

View File

@ -6,8 +6,9 @@ const NATIVE = 'NATIVE'
const ERC20 = 'ERC20'
export class ImtblMarket {
constructor() {
constructor(_chainInstance) {
this.client = new orderbook.Orderbook({ baseConfig });
this.bc = _chainInstance
}
updateProvider(provider) {
@ -21,6 +22,7 @@ export class ImtblMarket {
* @returns
*/
async listListings(contractAddress){
await this.bc.checkAndChangeChain();
const listOfListings = await this.client.listListings({
sellItemContractAddress: contractAddress,
status: orderbook.OrderStatusName.ACTIVE,
@ -114,6 +116,7 @@ export class ImtblMarket {
* @param {string} currencyAmount 出售价格, 单位 wei
*/
async beginSellERC721({contractAddress, tokenId, currencyAddress, currencyAmount, orderExpiry}) {
await this.bc.checkAndChangeChain();
const { preparedListing, orderSignature } =
await this._prepareERC721Listing({contractAddress, tokenId, currencyAddress, currencyAmount, orderExpiry});
const order = await this._createListing(preparedListing, orderSignature, currencyAmount);
@ -125,6 +128,7 @@ export class ImtblMarket {
* @param {*} listingId
*/
async beginBuy(listingId) {
await this.bc.checkAndChangeChain();
const fulfiller = await this.signer.getAddress();
// const fulfiller = marketAddress
console.log(listingId,fulfiller)
@ -149,6 +153,7 @@ export class ImtblMarket {
* @param { string[] } listingIds: listingId列表
*/
async batchBuy(listingIds) {
await this.bc.checkAndChangeChain();
const fulfiller = await this.signer.getAddress();
// console.log(listingIds, marketAddress,'---')
// return
@ -211,6 +216,7 @@ export class ImtblMarket {
* @returns
*/
async cancelOrdersOnChain(listingIds) {
await this.bc.checkAndChangeChain();
const offerer = await this.signer.getAddress();
const { cancellationAction } = await this.client.cancelOrdersOnChain(
listingIds,

View File

@ -35,10 +35,6 @@ import { computed } from "vue";
import { ALL_PROVIDERS } from "@/configs/configchain";
import { allProviders } from "@/components/chain/BlockChain"
import {walletStore} from "@/store/wallet";
const localWalletStore = walletStore()
const props = defineProps({
visible: Boolean,
close: Function,

View File

@ -0,0 +1,49 @@
export class SiweMessage {
constructor(param) {
Object.assign(this, param);
}
toMessage() {
const header = `${this.domain} wants you to sign in with your Ethereum account:`;
const uriField = `URI: ${this.uri}`;
let prefix = [header, this.address].join('\n');
const versionField = `Version: ${this.version}`;
const chainField = `Chain ID: ` + this.chainId || '1';
const nonceField = `Nonce: ${this.nonce}`;
const suffixArray = [uriField, versionField, chainField, nonceField];
this.issuedAt = this.issuedAt || new Date().toISOString();
suffixArray.push(`Issued At: ${this.issuedAt}`);
if (this.expirationTime) {
const expiryField = `Expiration Time: ${this.expirationTime}`;
suffixArray.push(expiryField);
}
if (this.notBefore) {
suffixArray.push(`Not Before: ${this.notBefore}`);
}
if (this.requestId) {
suffixArray.push(`Request ID: ${this.requestId}`);
}
if (this.resources) {
suffixArray.push(
[`Resources:`, ...this.resources.map(x => `- ${x}`)].join('\n')
);
}
const suffix = suffixArray.join('\n');
prefix = [prefix, this.statement].join('\n\n');
if (this.statement) {
prefix += '\n';
}
return [prefix, suffix].join('\n');
}
}

View File

@ -21,18 +21,19 @@ export class Locker {
async lock(nft, tokenIds) {
// call single method with abi and address
console.log('lock nft', nft, tokenIds)
const nftContract = new ethers.Contract(nft, erc721Abi, this.bc.provider.getSigner())
await this.bc.checkAndChangeChain();
const nftContract = new ethers.Contract(nft, erc721Abi, this.bc.web3Provider.getSigner())
for (let tokenId of tokenIds) {
const addressApproval = await nftContract.getApproved(tokenId)
if ((addressApproval || "").toLowerCase() != lockAddress.toLowerCase()) {
const resApproval = await nftContract.approve(lockAddress, tokenId);
await this.bc.provider.waitForTransaction(resApproval.hash)
await this.bc.web3Provider.waitForTransaction(resApproval.hash)
console.debug('approve', resApproval.hash)
}
}
const contract = new ethers.Contract(lockAddress, lockAbi, this.bc.provider.getSigner())
const contract = new ethers.Contract(lockAddress, lockAbi, this.bc.web3Provider.getSigner())
const res = await contract.lock(nft, tokenIds)
await this.bc.provider.waitForTransaction(res.hash)
await this.bc.web3Provider.waitForTransaction(res.hash)
return res.hash
}
}

View File

@ -0,0 +1,188 @@
export const WALLET_API_HOST_TEST = 'https://oauth-svr.cebggame.com/test';
export const WALLET_API_HOST_RELEASE = 'https://wallet.cebggame.com';
const apiBase = process.env.NODE_ENV === 'production' ? WALLET_API_HOST_RELEASE : WALLET_API_HOST_TEST;
import { SiweMessage } from './common/SiweMessage';
import { ethers } from 'ethers';
import assert from 'assert'
import { AllChains } from "@/configs/allchain";
import { Deferred } from '@/utils/promise.util';
export const cfgChainId = parseInt(import.meta.env.VUE_APP_NET_ID);
assert(cfgChainId, 'VUE_APP_NET_ID not configured');
let chainCfg;
for (const d of AllChains) {
if (d.id === cfgChainId) {
chainCfg = d;
break;
}
}
assert(chainCfg, 'chain config not found');
export const currentChainCfg = chainCfg;
const request = async(url, data, method = 'POST') => {
let headers = {
'Content-Type': 'application/json',
'api_version': 2,
'api_platform': 'marketplace',
'api_env': process.env.NODE_ENV === 'production' ? 'release' : 'dev'
};
return fetch(url, {
method,
body: JSON.stringify(data),
headers
}).then(res => res.json());
}
const loginWithSignature = async(message, signature) => {
const url = `${apiBase}/wallet/login/general`;
const data = {
channel: 13,
code: signature,
message,
nb: 1
}
return request(url, data);
}
export const genRefreshToken = async(refreshToken) => {
const url = `${apiBase}/wallet/refresh_token`;
const data = { refreshToken }
const res = await request(url, data);
if (res.errcode) {
throw new Error(res.errmsg);
}
return res.data;
}
const utf8ToHex = (str) => {
return '0x' + Buffer.from(str).toString('hex');
}
export const signLogin = async (provider, address) => {
const nonce = Date.now()+'';
address = ethers.utils.getAddress(address);
let chainId = await provider.request({ method: "eth_chainId" });
chainId = parseInt(chainId);
const message = new SiweMessage({
domain: document.location.host,
address,
chainId,
uri: document.location.origin,
version: "1",
statement: "CF MarketPlace",
nonce,
});
const msgSign = message.toMessage();
const signature = await provider.request({
"method": "personal_sign",
"params": [
utf8ToHex(msgSign),
address
]
});
const res = await loginWithSignature(message, signature);
if (res.errcode) {
throw new Error(res.errmsg);
}
return res.data;
}
export function parseTokenData(token) {
if (!token) {
return {};
}
let datas = token.split(".");
if (datas.length < 2) {
return {};
}
try {
return JSON.parse(window.atob(datas[1]));
} catch (err) {
return {};
}
}
/**
* check if token expired
* @param token jwt token string
* @param fixed fixed seconds
* @returns
*/
export function isTokenExpired(fixed, token) {
if (!token) {
return true;
}
let data = parseTokenData(token);
if (!data.exp) {
return true;
}
let now = Date.now() / 1000 | 0;
return data.exp < now - fixed;
}
/**
* 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 = toHexChainId(targetChainId)
const deferred = new Deferred();
const onChainChange = (chainId) => {
const chainIdNum = parseInt(chainId)
console.log('switchEthereumChain: ', chainIdNum)
provider.removeListener('chainChanged', onChainChange)
if (chainIdNum !== targetChainId) {
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
}

View File

@ -1,4 +1,5 @@
import { providers } from "ethers"
import { signLogin } from '@/components/chain/utils.js'
export class MetaMaskWallet{
constructor() {
@ -18,6 +19,12 @@ export class MetaMaskWallet{
return { provider, accounts };
}
async getAccessToken() {
const accounts = await this.nativeProvider.request({ method: "eth_requestAccounts" });
const { token, refreshToken } = await signLogin(this.nativeProvider, accounts[0]);
return { token, refreshToken }
}
async logout() {
await this.nativeProvider.request({
"method": "wallet_revokePermissions",
@ -28,4 +35,9 @@ export class MetaMaskWallet{
]
});
}
async getChainId() {
const chainId = await this.nativeProvider.request({ method: "eth_chainId" });
return parseInt(chainId);
}
}

View File

@ -19,7 +19,18 @@ export class OkxWallet{
return { provider, accounts };
}
async getAccessToken() {
const accounts = await this.nativeProvider.request({ method: "eth_requestAccounts" });
const { token, refreshToken } = await signLogin(this.nativeProvider, accounts[0]);
return { token, refreshToken }
}
async logout() {
await this.nativeProvider.request({ method: 'wallet_disconnect' });
}
async getChainId() {
const chainId = await this.nativeProvider.request({ method: "eth_chainId" });
return parseInt(chainId);
}
}

View File

@ -1,5 +1,6 @@
import { config, passport, orderbook, checkout } from '@imtbl/sdk';
import { providers } from 'ethers';
import { cfgChainId } from '@/components/chain/utils.js';
const environment = process.env.NODE_ENV === 'production' ? config.Environment.PRODUCTION : config.Environment.SANDBOX;
const publishableKey = import.meta.env.VUE_APP_PASSPORT_PUBLISHABLE_KEY
@ -20,6 +21,7 @@ export class PassportWallet {
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
logoutMode: 'silent',
audience: 'platform_api',
scope: 'openid offline_access email transact',
popupOverlayOptions: {
@ -63,17 +65,21 @@ export class PassportWallet {
const accounts = await passportProvider.request({ method: "eth_requestAccounts" });
const provider = new providers.Web3Provider(passportProvider);
const token = await this.passportInstance.getAccessToken()
console.log(`accesstoken`, token)
return { provider, accounts, token };
}
async getAccessToken() {
return await this.passportInstance.getAccessToken();
const token = await this.passportInstance.getAccessToken();
return { token }
}
async logout() {
await this.passportInstance.logout();
await this.passportInstance.logoutSilentCallback(logoutRedirectUri);
}
async getChainId() {
return Promise.resolve(cfgChainId)
}
}

View File

@ -282,5 +282,21 @@ export const AllChains = [
id: 1666700000,
symbol: 'ONE',
explorerurl: 'https://explorer.harmony.one'
},
{
name: 'Immutable zkEVM',
type: 'Mainnet',
rpc: 'https://rpc.immutable.com',
id: 13371,
symbol: 'IMX',
explorerurl: 'https://explorer.immutable.com'
},
{
name: 'Immutable zkEVM Testnet',
type: 'Testnet',
rpc: 'https://rpc.testnet.immutable.com',
id: 13473,
symbol: 'tIMX',
explorerurl: 'https://explorer.testnet.immutable.com'
}
]

View File

@ -7,7 +7,8 @@ export const walletStore = defineStore(
const walletType = ref();
const address = ref();
const chainId = ref();
const tokenId = ref();
const token = ref();
const refreshToken = ref();
const showAddress = computed(() => {
if (address.value.length > 10) {
@ -20,13 +21,15 @@ export const walletStore = defineStore(
walletType.value = '';
address.value = '';
chainId.value = '';
tokenId.value = '';
token.value = '';
refreshToken.value = '';
}
return {
walletType,
address,
chainId,
tokenId,
token,
refreshToken,
showAddress,
reset,
};