ffi
This commit is contained in:
parent
740e3694b4
commit
c2a22d32ca
451
README.md
451
README.md
@ -1,3 +1,454 @@
|
||||
运行代码指令
|
||||
npm run dev
|
||||
yarn run dev
|
||||
const ERC20ABI = [
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "_nftTarget",
|
||||
type: "address"
|
||||
},
|
||||
{
|
||||
internalType: "address[]",
|
||||
name: "_manageAddress",
|
||||
type: "address[]"
|
||||
}
|
||||
],
|
||||
stateMutability: "nonpayable",
|
||||
type: "constructor"
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "user",
|
||||
type: "address"
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "nft",
|
||||
type: "address"
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
internalType: "uint256[]",
|
||||
name: "nftSIds",
|
||||
type: "uint256[]"
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
internalType: "uint256[]",
|
||||
name: "nftTIds",
|
||||
type: "uint256[]"
|
||||
}
|
||||
],
|
||||
name: "Minted",
|
||||
type: "event"
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "bytes32",
|
||||
name: "role",
|
||||
type: "bytes32"
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "bytes32",
|
||||
name: "previousAdminRole",
|
||||
type: "bytes32"
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "bytes32",
|
||||
name: "newAdminRole",
|
||||
type: "bytes32"
|
||||
}
|
||||
],
|
||||
name: "RoleAdminChanged",
|
||||
type: "event"
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "bytes32",
|
||||
name: "role",
|
||||
type: "bytes32"
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "account",
|
||||
type: "address"
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "sender",
|
||||
type: "address"
|
||||
}
|
||||
],
|
||||
name: "RoleGranted",
|
||||
type: "event"
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "bytes32",
|
||||
name: "role",
|
||||
type: "bytes32"
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "account",
|
||||
type: "address"
|
||||
},
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "sender",
|
||||
type: "address"
|
||||
}
|
||||
],
|
||||
name: "RoleRevoked",
|
||||
type: "event"
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "DEFAULT_ADMIN_ROLE",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bytes32",
|
||||
name: "",
|
||||
type: "bytes32"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
constant: true
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "MANAGE_ROLE",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bytes32",
|
||||
name: "",
|
||||
type: "bytes32"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
constant: true
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "bytes32",
|
||||
name: "role",
|
||||
type: "bytes32"
|
||||
}
|
||||
],
|
||||
name: "getRoleAdmin",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bytes32",
|
||||
name: "",
|
||||
type: "bytes32"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
constant: true
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "bytes32",
|
||||
name: "role",
|
||||
type: "bytes32"
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "index",
|
||||
type: "uint256"
|
||||
}
|
||||
],
|
||||
name: "getRoleMember",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "",
|
||||
type: "address"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
constant: true
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "bytes32",
|
||||
name: "role",
|
||||
type: "bytes32"
|
||||
}
|
||||
],
|
||||
name: "getRoleMemberCount",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
constant: true
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "bytes32",
|
||||
name: "role",
|
||||
type: "bytes32"
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "account",
|
||||
type: "address"
|
||||
}
|
||||
],
|
||||
name: "grantRole",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function"
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "bytes32",
|
||||
name: "role",
|
||||
type: "bytes32"
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "account",
|
||||
type: "address"
|
||||
}
|
||||
],
|
||||
name: "hasRole",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
constant: true
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "nft",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "contract IBEERC721",
|
||||
name: "",
|
||||
type: "address"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
constant: true
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256"
|
||||
}
|
||||
],
|
||||
name: "nftMinted",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
constant: true
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "",
|
||||
type: "address"
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256"
|
||||
}
|
||||
],
|
||||
name: "ownerToNFTs",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
constant: true
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "bytes32",
|
||||
name: "role",
|
||||
type: "bytes32"
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "account",
|
||||
type: "address"
|
||||
}
|
||||
],
|
||||
name: "renounceRole",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function"
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "bytes32",
|
||||
name: "role",
|
||||
type: "bytes32"
|
||||
},
|
||||
{
|
||||
internalType: "address",
|
||||
name: "account",
|
||||
type: "address"
|
||||
}
|
||||
],
|
||||
name: "revokeRole",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function"
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "bytes4",
|
||||
name: "interfaceId",
|
||||
type: "bytes4"
|
||||
}
|
||||
],
|
||||
name: "supportsInterface",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "bool",
|
||||
name: "",
|
||||
type: "bool"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
constant: true
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "_user",
|
||||
type: "address"
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "count",
|
||||
type: "uint256"
|
||||
}
|
||||
],
|
||||
name: "mintToUser",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function"
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "_user",
|
||||
type: "address"
|
||||
},
|
||||
{
|
||||
internalType: "uint256[]",
|
||||
name: "_nftIds",
|
||||
type: "uint256[]"
|
||||
}
|
||||
],
|
||||
name: "addNFTData",
|
||||
outputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "function"
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "_user",
|
||||
type: "address"
|
||||
}
|
||||
],
|
||||
name: "getMintableCount",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "",
|
||||
type: "uint256"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
constant: true
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "address",
|
||||
name: "_user",
|
||||
type: "address"
|
||||
}
|
||||
],
|
||||
name: "getMintableNftIds",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "uint256[]",
|
||||
name: "",
|
||||
type: "uint256[]"
|
||||
}
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
constant: true
|
||||
}
|
||||
]
|
@ -1,3 +1,4 @@
|
||||
import request from "@/utils/request";
|
||||
/**
|
||||
* begin claim badge
|
||||
* @param {*} data: {id: string}
|
||||
|
BIN
src/assets/img/badge/more-hover.png
Normal file
BIN
src/assets/img/badge/more-hover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
@ -11,6 +11,7 @@ import {
|
||||
ACTIVATE_PROXY_ABI,
|
||||
MYSTERY_BOX_ABI,
|
||||
MYSTERY_PROXY_ABI,
|
||||
MEDAL_REWARDS_ABI,
|
||||
} from "@/configs/contracts";
|
||||
|
||||
const AppModule = useAppStore(pinia);
|
||||
@ -115,6 +116,7 @@ export default class ChainManager {
|
||||
console.log("balance: ", balance);
|
||||
return balance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get amount of mystery boxes
|
||||
|
@ -6,9 +6,10 @@ import { useUserStore } from "@/store/user";
|
||||
import { isMobile } from "@/utils/resize";
|
||||
import { hasMetamask, toHexChainId } from "@/utils/chain.util";
|
||||
import { AllChains } from "@/configs/allchain";
|
||||
import { ERC20ABI } from "@/configs/contracts";
|
||||
import { ERC20ABI, LIMIT_ABI, MEDAL_REWARDS_ABI } from "@/configs/contracts";
|
||||
import { TransactionReceipt } from "web3-core";
|
||||
import { useEventBus } from "@vueuse/core";
|
||||
import { Global } from "@/configs/global";
|
||||
import * as bus_event from "@/bus/event";
|
||||
import pinia from "@/store";
|
||||
|
||||
@ -95,6 +96,7 @@ export class Blockchain {
|
||||
return;
|
||||
}
|
||||
this.web3 = new Web3(this.provider);
|
||||
|
||||
const chainId = await this.web3.eth.getChainId();
|
||||
await this.checkChain(chainId);
|
||||
|
||||
@ -126,7 +128,7 @@ export class Blockchain {
|
||||
* @private
|
||||
*/
|
||||
private async checkChain(chainId: number) {
|
||||
if (!this.chainMap.has(chainId)) {
|
||||
if (chainId !== AVAILABLE_CHAINS[0]) {
|
||||
// if (this.walletType === 1) {
|
||||
try {
|
||||
await this.selectChain();
|
||||
@ -195,19 +197,12 @@ export class Blockchain {
|
||||
*/
|
||||
private selectChain(): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
busNeedChangeChain.emit({
|
||||
confirm: async (id: number) => {
|
||||
console.log("select chain: ", id);
|
||||
this.currentChain = id;
|
||||
if (this.provider) {
|
||||
await this.switchEthereumChain();
|
||||
}
|
||||
resolve && resolve(id);
|
||||
},
|
||||
cancel: (reason: any) => {
|
||||
console.log("cancel select chain: ", reason);
|
||||
reject && reject(reason);
|
||||
},
|
||||
this.switchEthereumChain(AVAILABLE_CHAINS[0], (res: any)=>{
|
||||
if (res.err) {
|
||||
reject && reject(res.err)
|
||||
return
|
||||
}
|
||||
resolve && resolve(res.chain)
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -256,6 +251,11 @@ export class Blockchain {
|
||||
}
|
||||
|
||||
public async getContractInstance(address: string, abi: any = ERC20ABI) {
|
||||
if (!this.web3) {
|
||||
throw new Error(
|
||||
"Web3 instance is not initialized. Please call `initWeb3` method after user login."
|
||||
);
|
||||
}
|
||||
if (!this.instanceCacheMap.has(address)) {
|
||||
const instance = new this.web3.eth.Contract(abi, address, {
|
||||
from: AppModule.accountId,
|
||||
@ -344,49 +344,38 @@ export class Blockchain {
|
||||
* @param {() => void} cb
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async switchEthereumChain(chainId?: number, cb?: () => void) {
|
||||
chainId = chainId || this.currentChain;
|
||||
async switchEthereumChain(chainId?: number, cb?: (res: any) => void) {
|
||||
chainId = chainId || AVAILABLE_CHAINS[0];
|
||||
const hexChainId = toHexChainId(chainId);
|
||||
const onChainChange = (chainId: string) => {
|
||||
console.log("switchEthereumChain: ", chainId);
|
||||
this.provider.removeListener("chainChanged", onChainChange);
|
||||
cb && cb();
|
||||
cb && cb({chain: chainId});
|
||||
};
|
||||
this.provider.on("chainChanged", onChainChange);
|
||||
try {
|
||||
const data = this.chainMap.get(chainId)!;
|
||||
await this.provider.request({
|
||||
method: "wallet_switchEthereumChain",
|
||||
params: [{ chainId: hexChainId }],
|
||||
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("switch chain success");
|
||||
} catch (e: any) {
|
||||
console.log("switch chain error: ", e);
|
||||
if (e.code === 4902 || e.message.indexOf("Unrecognized chain ID") >= 0) {
|
||||
try {
|
||||
const data = this.chainMap.get(chainId)!;
|
||||
await this.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("add chain success");
|
||||
} catch (addError) {
|
||||
console.error("add chain error: ", addError);
|
||||
this.provider.removeListener("chainChanged", onChainChange);
|
||||
}
|
||||
}
|
||||
// console.error(e)
|
||||
console.log("add chain success");
|
||||
} catch (addError) {
|
||||
console.error("add chain error: ", addError);
|
||||
this.provider.removeListener("chainChanged", onChainChange);
|
||||
cb && cb({err: addError})
|
||||
}
|
||||
}
|
||||
|
||||
@ -455,6 +444,38 @@ export class Blockchain {
|
||||
console.log("increaseAllowance: ", res);
|
||||
}
|
||||
|
||||
public async totalSupply(address: string) {
|
||||
const coinInstance: any = await this.getContractInstance(
|
||||
Global.LIMIT_ABI_Address,
|
||||
LIMIT_ABI
|
||||
);
|
||||
const res = await coinInstance.methods.totalSupply().call({ gas: 1000000 });
|
||||
console.log("totalSupply: ", res);
|
||||
return res
|
||||
}
|
||||
// 获取当前用户可mint的数量
|
||||
public async getMintableCount(address?: string) {
|
||||
// address = address || //TODO: current address
|
||||
const coinInstance: any = await this.getContractInstance(
|
||||
Global.MEDAL_REWARDS_Address,
|
||||
MEDAL_REWARDS_ABI
|
||||
);
|
||||
const res = await coinInstance.methods
|
||||
.getMintableCount(AppModule.accountId)
|
||||
.call({ gas: 1000000 });
|
||||
console.log("getMintableCount: ", res);
|
||||
return res
|
||||
}
|
||||
// 获取当前用户的mint总数
|
||||
public async supplyLimit(address: string) {
|
||||
const coinInstance: any = await this.getContractInstance(
|
||||
Global.LIMIT_ABI_Address,
|
||||
LIMIT_ABI
|
||||
);
|
||||
const res = await coinInstance.methods.supplyLimit().call({ gas: 1000000 });
|
||||
console.log("supplyLimit: ", res);
|
||||
return res
|
||||
}
|
||||
/**
|
||||
* @param {string} address
|
||||
* @param {string | null} account
|
||||
|
@ -47,7 +47,7 @@ import { useCopyToClipboard } from "./../../hooks/useCopyToClipboard";
|
||||
const AppModule = useAppStore();
|
||||
const chain = useChainStore();
|
||||
const app = useAppStore();
|
||||
|
||||
const emit = defineEmits(['login-success'])
|
||||
|
||||
const { copied, copyToClipboard } = useCopyToClipboard(AppModule.accountId);
|
||||
const message = copied.value
|
||||
@ -64,14 +64,16 @@ const formatAddress = computed(() => {
|
||||
async function login(event) {
|
||||
if (!chain.logined) {
|
||||
await chain.chainManager.login();
|
||||
|
||||
chain.logined = chain.chainManager.isLogined;
|
||||
emit('login-success');
|
||||
}
|
||||
}
|
||||
|
||||
const logout = async () => {
|
||||
await chain.chainManager.logout();
|
||||
|
||||
|
||||
chain.logined = chain.chainManager.isLogined;
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -15,7 +15,7 @@ export const ALL_PROVIDERS = [
|
||||
},
|
||||
];
|
||||
|
||||
export const AVAILABLE_CHAINS = env === "production" ? [321] : [322];
|
||||
export const AVAILABLE_CHAINS = env === "production" ? [137] : [80001];
|
||||
|
||||
export const OFFICE_ACCOUNT =
|
||||
env === "production"
|
||||
|
File diff suppressed because it is too large
Load Diff
4
src/configs/global.ts
Normal file
4
src/configs/global.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export namespace Global {
|
||||
export const MEDAL_REWARDS_Address: string = "0xC0DA6D9d8AaDCFf7BD6d69B8b46948dD40BF0dec"; // 分发地址
|
||||
export const LIMIT_ABI_Address: string = "0x5b36329D0DA1F56eD60F3C5DE1855c8dE0440140"; // 徽章地址
|
||||
}
|
@ -67,7 +67,7 @@ export const useUserStore = defineStore("user", () => {
|
||||
if (!res.errcode && res.data?.token) {
|
||||
accountId.value = account;
|
||||
setToken(res.data.token);
|
||||
|
||||
glodata.token = getToken();
|
||||
setAccountId(account);
|
||||
AppModule.updateAccount(account);
|
||||
AppModule.updateToken(res.data.token);
|
||||
@ -83,6 +83,9 @@ export const useUserStore = defineStore("user", () => {
|
||||
removeToken();
|
||||
token.value = "";
|
||||
accountId.value = "";
|
||||
glodata.token = '';
|
||||
glodata.accountId=''
|
||||
AppModule.updateToken("");
|
||||
AppModule.updateAccount("");
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="my-container">
|
||||
<NavBar></NavBar>
|
||||
<NavBar @login-success="fetchData"></NavBar>
|
||||
<div class="content-top">
|
||||
<div class="text-left">
|
||||
<img src="../assets/img/badge/left-text.png" alt="" />
|
||||
@ -20,7 +20,7 @@
|
||||
<div class="card shadow-md rounded cards-container">
|
||||
<div></div>
|
||||
<div
|
||||
class="card-title text-xl mb-8 text-yellow-color font-poppins-semiBoldItalic cards-container"
|
||||
class="card-title text-xl text-yellow-color font-poppins-semiBoldItalic cards-container"
|
||||
>
|
||||
<div>GENESIS</div>
|
||||
</div>
|
||||
@ -41,7 +41,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="genesicard">
|
||||
<div class="genesis-title pt-24 font-firaSans-blackItalic">
|
||||
<div class="genesis-title font-firaSans-blackItalic">
|
||||
Genesis NFT <br />
|
||||
holder Only
|
||||
</div>
|
||||
@ -61,20 +61,29 @@
|
||||
</div>
|
||||
<div class="ml-3">December 1 (st), 2022</div>
|
||||
</div>
|
||||
<div class="december-number">2000 / 4000</div>
|
||||
<div class="december-number">
|
||||
{{ totalSupply || "0" }} / {{ supplyLimit || "0" }}
|
||||
</div>
|
||||
<div
|
||||
:class="isbtn === true ? 'disabled-claim' : 'claim'"
|
||||
:class="mintableCount == 0 ? 'disabled-claim' : 'claim'"
|
||||
@click="handClaimBadge"
|
||||
>
|
||||
<div class="claim-item">Claim your Airdorp</div>
|
||||
</div>
|
||||
<div class="dis-msg">
|
||||
<div class="msg">You’re not eligible for this stage.<img class="rabbit" src="../assets/img/badge/rabbit.png" alt=""></div>
|
||||
<div class="msg">
|
||||
{{ message
|
||||
}}<img
|
||||
class="rabbit"
|
||||
src="../assets/img/badge/rabbit.png"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card shadow-md rounded cards-container">
|
||||
<div
|
||||
class="text-xl font-bold font-poppins-semiBoldItalic card-title-right mb-4 p-3 text-black-color-300 cards-container"
|
||||
class="text-xl font-bold font-poppins-semiBoldItalic card-title-right text-black-color-300 cards-container"
|
||||
>
|
||||
EXPLORER
|
||||
</div>
|
||||
@ -91,7 +100,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="timeline">
|
||||
<div class="timeline-boder flex justify-center pt-12">
|
||||
<div class="timeline-boder flex justify-center pt-6">
|
||||
<img src="../assets/img/badge/timeline.png" alt="" />
|
||||
</div>
|
||||
<div class="pt-2">
|
||||
@ -103,6 +112,7 @@
|
||||
<li>Beta Test I</li>
|
||||
<li>Beta Test II</li>
|
||||
</ul>
|
||||
<div class="coming">Coming Soon</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -127,19 +137,25 @@ import {
|
||||
import { useAppStore } from "@/store/app";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
import { useMouse, useRafFn } from "@vueuse/core";
|
||||
|
||||
import { beginClaim, checkClaimStatus } from "../api/badge";
|
||||
import { useMouseRotation } from "../hooks/useMouseRotation";
|
||||
import NavBar from "@/components/layout/NavBar.vue";
|
||||
import ImageTextModal from "../components/global/ImageTextModal.vue";
|
||||
|
||||
import { useChainStore } from "@/store/chain";
|
||||
const AppModule = useAppStore();
|
||||
const scrollOffset = ref("0%");
|
||||
const parallaxFactor = 0.135; // 视差滚动系数,可以根据需要调整
|
||||
const visible = ref(false);
|
||||
const isbtn = ref(false);
|
||||
|
||||
const canClaim = ref(false);
|
||||
const chain = useChainStore();
|
||||
const totalSupply = ref(0);
|
||||
const mintableCount = ref(0);
|
||||
const supplyLimit = ref(0);
|
||||
const message = ref("");
|
||||
const handlHero = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
const handleScroll = () => {
|
||||
const currentScrollTop =
|
||||
window.pageYOffset || document.documentElement.scrollTop;
|
||||
@ -165,8 +181,62 @@ const {
|
||||
stopTracking: stopTracking2,
|
||||
} = useMouseRotation();
|
||||
|
||||
const handClaimBadge = () => {
|
||||
isbtn.value = true;
|
||||
const handClaimBadge = async () => {
|
||||
if (mintableCount.value == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!chain.logined) {
|
||||
await chain.chainManager.login();
|
||||
chain.logined = chain.chainManager.isLogined;
|
||||
}
|
||||
} catch (error) {
|
||||
message.error("登录失败,请稍后重试");
|
||||
console.error(error);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 调用 beginClaim API
|
||||
const res = await beginClaim(1);
|
||||
// message.loading("领取中,请稍等...", 0);
|
||||
console.log("领取失败,请稍后重试!", res.data.taskId);
|
||||
// 轮询检查 claim 任务状态
|
||||
let status = 0;
|
||||
let timer;
|
||||
while (status !== 9 && status !== 10) {
|
||||
await new Promise((resolve) => {
|
||||
timer = setTimeout(resolve, 5000); // 每隔5秒查询一次
|
||||
});
|
||||
const resStatus = await checkClaimStatus(res.data.taskId);
|
||||
status = resStatus.data.status;
|
||||
console.log("status", resStatus.data.status);
|
||||
}
|
||||
|
||||
// message.destroy(); // 销毁 loading message
|
||||
|
||||
if (status === 9) {
|
||||
console.log("领取成功!");
|
||||
message.value = "claim success!";
|
||||
clearTimeout(timer); // 清除定时器
|
||||
// message.success("领取成功!");
|
||||
} else if (status === 10) {
|
||||
console.log("领取失败,请稍后重试!");
|
||||
message.value = "claim failure!";
|
||||
clearTimeout(timer); // 清除定时器
|
||||
// message.error("领取失败,请稍后重试");
|
||||
}
|
||||
if (status === 0) {
|
||||
message.value = "claiming !";
|
||||
}
|
||||
} catch (error) {
|
||||
// message.destroy();
|
||||
// message.error("领取过程中发生错误,请稍后重试");
|
||||
console.log("领取过程中发生错误,请稍后重试!");
|
||||
// clearTimeout(timer); // 清除定时器
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
const bgTranslateX = ref(0);
|
||||
@ -178,12 +248,34 @@ const handleScrolls = () => {
|
||||
bgTranslateX.value -= scrollDelta / 3; // 背景图片水平方向移动的速度
|
||||
scrollPos.value = newScrollPos;
|
||||
};
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
// 获取总数
|
||||
totalSupply.value = await chain.chainManager.bc.totalSupply();
|
||||
|
||||
onMounted(() => {
|
||||
//获取可mint的数量
|
||||
mintableCount.value = await chain.chainManager.bc.getMintableCount();
|
||||
|
||||
mintableCount.value == 0
|
||||
? (message.value = "You’re not eligible for this stage.")
|
||||
: "";
|
||||
//获取当前用户的mint总数
|
||||
supplyLimit.value = await chain.chainManager.bc.supplyLimit();
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
}
|
||||
console.log("totalSupply.value:", totalSupply.value);
|
||||
console.log("mintableCount.value:", mintableCount.value);
|
||||
console.log("supplyLimit.value:", supplyLimit.value);
|
||||
};
|
||||
// 初始化时获取数据
|
||||
onMounted(async () => {
|
||||
if (AppModule.accountId) {
|
||||
await fetchData();
|
||||
}
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
window.addEventListener("scroll", handleScrolls);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
window.removeEventListener("scroll", handleScrolls);
|
||||
@ -207,7 +299,7 @@ onUnmounted(() => {
|
||||
.star-bg {
|
||||
position: absolute;
|
||||
left: 30px;
|
||||
top:30px;
|
||||
top: 30px;
|
||||
bottom: 0;
|
||||
right: 20px;
|
||||
z-index: -1;
|
||||
@ -220,7 +312,7 @@ onUnmounted(() => {
|
||||
.bg {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
top: -10px;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: -2;
|
||||
@ -233,7 +325,7 @@ onUnmounted(() => {
|
||||
.text-left {
|
||||
position: absolute;
|
||||
left: 85px;
|
||||
bottom: 30px;
|
||||
bottom: 10px;
|
||||
animation: slide-up 1s ease-out;
|
||||
}
|
||||
.text-right {
|
||||
@ -250,10 +342,10 @@ onUnmounted(() => {
|
||||
font-weight: 500;
|
||||
color: #ffb900;
|
||||
}
|
||||
.timeline{
|
||||
width:1188px;
|
||||
.timeline {
|
||||
width: 1188px;
|
||||
margin-left: 5px;
|
||||
height: 38px;
|
||||
height: 38px;
|
||||
}
|
||||
.card {
|
||||
transition: transform 0.1s ease;
|
||||
@ -263,16 +355,32 @@ onUnmounted(() => {
|
||||
}
|
||||
.card-title {
|
||||
font-size: 80px;
|
||||
margin-bottom: 19px;
|
||||
// font-family: "Poppins";
|
||||
font-weight: normal;
|
||||
color: #ffb900;
|
||||
position: relative;
|
||||
line-height: 60px;
|
||||
background: linear-gradient(180deg, #f9fe1d 0%, #ffbb17 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
.card-title::after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
right: 125px;
|
||||
bottom: 3px;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background: #fcde1a;
|
||||
margin-left: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.card-title-right {
|
||||
font-size: 40px;
|
||||
margin-top: 16px;
|
||||
text-align: center;
|
||||
// font-family: "Fira Sans";
|
||||
font-weight: normal;
|
||||
}
|
||||
@ -307,7 +415,7 @@ p {
|
||||
text-align: center;
|
||||
line-height: 28px;
|
||||
&:hover {
|
||||
background: url("../assets/img/badge/more.png");
|
||||
background: url("../assets/img/badge/more-hover.png");
|
||||
}
|
||||
}
|
||||
.btn-more-right {
|
||||
@ -324,6 +432,15 @@ p {
|
||||
color: #a7a7a7;
|
||||
text-align: center;
|
||||
line-height: 28px;
|
||||
.coming {
|
||||
position: absolute;
|
||||
top: -90px;
|
||||
left: 20px;
|
||||
font-size: 16px;
|
||||
font-family: "Poppins-Regular";
|
||||
font-weight: 400;
|
||||
color: #a7a7a7;
|
||||
}
|
||||
}
|
||||
.btn-more-right:hover .dropdown-menu {
|
||||
display: block;
|
||||
@ -336,6 +453,7 @@ p {
|
||||
left: 0;
|
||||
// background-color: white;
|
||||
background: url("../assets/img/badge/dropdown-menu-bg.png") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
min-width: 145px;
|
||||
// box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
|
||||
list-style-type: none;
|
||||
@ -345,12 +463,20 @@ p {
|
||||
}
|
||||
|
||||
.dropdown-menu li {
|
||||
padding: 4px 10px;
|
||||
padding: 2px 10px;
|
||||
}
|
||||
.dropdown-menu li::after {
|
||||
content: "";
|
||||
display: block;
|
||||
border-bottom: 1px solid #838383;
|
||||
margin-top: -1px; /* 调整下划线与文字之间的间距 */
|
||||
}
|
||||
|
||||
.dropdown-menu li:hover {
|
||||
// background-color: #f1f1f1;
|
||||
}
|
||||
.dropdown-menu li:last-child::after {
|
||||
border-bottom: none;
|
||||
}
|
||||
.card-top {
|
||||
width: 450px;
|
||||
height: 450px;
|
||||
@ -443,6 +569,7 @@ p {
|
||||
.genesis-title {
|
||||
font-size: 40px;
|
||||
letter-spacing: 3px;
|
||||
margin-top: 75px;
|
||||
// font-family: "Fira Sans";
|
||||
font-weight: normal;
|
||||
text-transform: uppercase;
|
||||
@ -452,7 +579,7 @@ p {
|
||||
position: relative; /* 添加相对定位以便伪元素定位 */
|
||||
width: 302px;
|
||||
margin-left: 39px;
|
||||
margin-right: 167px;
|
||||
margin-right: 162px;
|
||||
}
|
||||
|
||||
.genesicard::before {
|
||||
@ -489,7 +616,7 @@ p {
|
||||
font-family: Arial;
|
||||
font-weight: 400;
|
||||
color: #ffffff;
|
||||
margin-bottom: 30px;
|
||||
margin-bottom: 26px;
|
||||
// line-height: 60px;
|
||||
}
|
||||
.disabled-claim {
|
||||
@ -589,7 +716,6 @@ p {
|
||||
height: 50px;
|
||||
margin-top: 41px;
|
||||
line-height: 50px;
|
||||
|
||||
font-size: 12px;
|
||||
font-family: "Poppins";
|
||||
font-weight: 400;
|
||||
@ -597,12 +723,12 @@ p {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid #353535;
|
||||
border-radius: 12px 0px 12px 0px;
|
||||
.msg{
|
||||
.msg {
|
||||
margin-left: 21px;
|
||||
position: relative;
|
||||
.rabbit{
|
||||
.rabbit {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
right: -6px;
|
||||
top: -24px;
|
||||
}
|
||||
}
|
||||
|
@ -1,55 +1,57 @@
|
||||
<!-- MedalApp.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<h1>可铸造的 NFT 数量:{{ mintableCount }}</h1>
|
||||
<button @click="mintNFTs">领取勋章</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue';
|
||||
import { ethers } from 'ethers';
|
||||
import NftDistributorABI from './NftDistributorABI.json'; // 从编译后的合约中导入 ABI
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const mintableCount = ref(0);
|
||||
const nftDistributorAddress = '0x123...'; // 替换为实际的合约地址
|
||||
const provider = new ethers.providers.Web3Provider(window.ethereum); // 使用 MetaMask 提供的以太坊 provider
|
||||
const nftDistributorContract = new ethers.Contract(nftDistributorAddress, NftDistributorABI, provider);
|
||||
|
||||
const loadMintableCount = async () => {
|
||||
try {
|
||||
const userAddress = await provider.getSigner().getAddress(); // 获取当前用户的地址
|
||||
const count = await nftDistributorContract.getMintableCount(userAddress);
|
||||
mintableCount.value = count.toNumber();
|
||||
} catch (error) {
|
||||
console.error('Error fetching mintable count:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const mintNFTs = async () => {
|
||||
try {
|
||||
const signer = provider.getSigner(); // 获取当前用户的签名器
|
||||
const userAddress = await signer.getAddress(); // 获取当前用户的地址
|
||||
const contractWithSigner = nftDistributorContract.connect(signer);
|
||||
|
||||
const tx = await contractWithSigner.mintToUser(userAddress, mintableCount.value);
|
||||
await tx.wait(); // 等待交易被确认
|
||||
|
||||
// 重新加载可铸造的 NFT 数量,因为用户已经铸造了 NFT
|
||||
await loadMintableCount();
|
||||
} catch (error) {
|
||||
console.error('Error minting NFTs:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 页面载入时获取可铸造的 NFT 数量
|
||||
loadMintableCount();
|
||||
|
||||
return {
|
||||
mintableCount,
|
||||
mintNFTs,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<div>
|
||||
<h1>可领取的勋章数量:{{ mintableCount }}</h1>
|
||||
<button @click="mintMedals">领取勋章</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue';
|
||||
import { ethers } from 'ethers';
|
||||
import MEDAL_REWARDS_ABI from './MEDAL_REWARDS_ABI.json'; // 从编译后的合约中导入 ABI
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const mintableCount = ref(0);
|
||||
const medalRewardsAddress = '0x123...'; // 替换为实际的合约地址
|
||||
const provider = new ethers.providers.Web3Provider(window.ethereum); // 使用 MetaMask 提供的以太坊 provider
|
||||
const medalRewardsContract = new ethers.Contract(medalRewardsAddress, MEDAL_REWARDS_ABI, provider);
|
||||
|
||||
const loadMintableCount = async () => {
|
||||
try {
|
||||
const userAddress = await provider.getSigner().getAddress(); // 获取当前用户的地址
|
||||
const count = await medalRewardsContract.getMintableCount(userAddress);
|
||||
mintableCount.value = count.toNumber();
|
||||
} catch (error) {
|
||||
console.error('Error fetching mintable count:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const mintMedals = async () => {
|
||||
try {
|
||||
const signer = provider.getSigner(); // 获取当前用户的签名器
|
||||
const userAddress = await signer.getAddress(); // 获取当前用户的地址
|
||||
const contractWithSigner = medalRewardsContract.connect(signer);
|
||||
|
||||
const tx = await contractWithSigner.mintToUser(userAddress, mintableCount.value);
|
||||
await tx.wait(); // 等待交易被确认
|
||||
|
||||
// 重新加载可领取的勋章数量,因为用户已经领取了勋章
|
||||
await loadMintableCount();
|
||||
} catch (error) {
|
||||
console.error('Error minting medals:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 页面载入时获取可领取的勋章数量
|
||||
loadMintableCount();
|
||||
|
||||
return {
|
||||
mintableCount,
|
||||
mintMedals,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
Loading…
x
Reference in New Issue
Block a user