feat: management page

This commit is contained in:
Ting-Jun Wang 2023-04-07 17:26:35 +08:00
parent caa854620a
commit 56ef570249
Signed by: snsd0805
GPG Key ID: 8DB0D22BC1217D33
7 changed files with 292 additions and 14 deletions

View File

@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" /> <meta name="description" content="" />
<meta name="author" content="" /> <meta name="author" content="" />
<title>My Goerli Faucet</title> <title>My Sepolia Faucet</title>
<!-- Favicon--> <!-- Favicon-->
<link rel="icon" type="image/x-icon" href="favicon.ico" /> <link rel="icon" type="image/x-icon" href="favicon.ico" />
<!-- Font Awesome icons (free version)--> <!-- Font Awesome icons (free version)-->

14
package-lock.json generated
View File

@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"@metamask/detect-provider": "^2.0.0", "@metamask/detect-provider": "^2.0.0",
"bootstrap": "^5.2.3", "bootstrap": "^5.2.3",
"dotenv": "^16.0.3",
"vue": "^3.2.47", "vue": "^3.2.47",
"vue-router": "^4.1.6", "vue-router": "^4.1.6",
"web3": "^1.8.2" "web3": "^1.8.2"
@ -1619,6 +1620,14 @@
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
}, },
"node_modules/dotenv": {
"version": "16.0.3",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
"engines": {
"node": ">=12"
}
},
"node_modules/ecc-jsbn": { "node_modules/ecc-jsbn": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@ -5388,6 +5397,11 @@
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
}, },
"dotenv": {
"version": "16.0.3",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ=="
},
"ecc-jsbn": { "ecc-jsbn": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",

View File

@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"@metamask/detect-provider": "^2.0.0", "@metamask/detect-provider": "^2.0.0",
"bootstrap": "^5.2.3", "bootstrap": "^5.2.3",
"dotenv": "^16.0.3",
"vue": "^3.2.47", "vue": "^3.2.47",
"vue-router": "^4.1.6", "vue-router": "^4.1.6",
"web3": "^1.8.2" "web3": "^1.8.2"

View File

@ -3,5 +3,25 @@ import { RouterLink, RouterView } from "vue-router";
</script> </script>
<template> <template>
<!-- Navigation-->
<nav class="navbar navbar-expand-lg bg-secondary text-uppercase fixed-top" id="mainNav">
<div class="container">
<router-link class="navbar-brand" to="/">Faucet</router-link>
<button class="navbar-toggler text-uppercase font-weight-bold bg-primary text-white rounded" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
Menu
<i class="fas fa-bars"></i>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ms-auto">
<li class="nav-item mx-0 mx-lg-1"><router-link class="nav-link py-3 px-0 px-lg-3 rounded" to="/">Withdraw</router-link></li>
<li class="nav-item mx-0 mx-lg-1"><router-link class="nav-link py-3 px-0 px-lg-3 rounded" to="/manage">Management</router-link></li>
</ul>
</div>
</div>
</nav>
<br><br><br>
<br><br><br>
<RouterView /> <RouterView />
</template> </template>

View File

@ -1,6 +1,6 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import FaucetView from '../views/FaucetView.vue' import FaucetView from '../views/FaucetView.vue'
import ManageView from '../views/ManageView.vue'
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
routes: [ routes: [
@ -8,6 +8,11 @@ const router = createRouter({
path: '/', path: '/',
name: 'home', name: 'home',
component: FaucetView component: FaucetView
},
{
path: '/manage',
name: 'management',
component: ManageView
} }
] ]
}) })

View File

@ -18,22 +18,17 @@ export default {
bankBalance: -1, bankBalance: -1,
} }
}, },
mounted() { async mounted() {
var web3 = new Web3(window.ethereum); var web3 = new Web3(window.ethereum);
this.bankAddr = import.meta.env.VITE_BANK_ADDR; this.bankAddr = import.meta.env.VITE_BANK_ADDR;
var bank = new web3.eth.Contract(bankABI, this.bankAddr); var bank = new web3.eth.Contract(bankABI, this.bankAddr);
bank.methods.getATMs().call((err, result) => { var atms = await bank.methods.getATMs().call();
if(err){ this.atms = atms;
alert(err); if(ethereum.isConnected()){
}else{ this.linked = true;
this.atms = result; this.detectMetamask();
}
// console.log(result);
}).then(() => {
console.log(this.atms)
}).then(() => {
this.update(); this.update();
}); }
}, },
methods: { methods: {
@ -54,6 +49,7 @@ export default {
this.atmsBalance[i] = web3.utils.fromWei(result); this.atmsBalance[i] = web3.utils.fromWei(result);
}) })
} }
console.log("update");
}, },
async detectMetamask() { async detectMetamask() {
@ -165,6 +161,7 @@ export default {
<template v-for="i in atms.length"> <template v-for="i in atms.length">
<div class="divider-custom-icon">ATM {{i}} ({{atms[i-1]}}) 還有 {{ atmsBalance[i-1]}} ETH 可以提領</div> <div class="divider-custom-icon">ATM {{i}} ({{atms[i-1]}}) 還有 {{ atmsBalance[i-1]}} ETH 可以提領</div>
</template> </template>
<button v-on:click='update' class='btn btn-info'>Update</button>
<br><br> <br><br>
<hr> <hr>

241
src/views/ManageView.vue Normal file
View File

@ -0,0 +1,241 @@
<script>
import detectEthereumProvider from '@metamask/detect-provider'
import Web3 from 'web3';
import bankABI from '@/assets/bank_abi.json';
export default {
name: 'ManageView',
data() {
return {
msg: "",
linked: false,
account: "",
owner: "",
atms: [],
atmsBalance: [],
bankAddr: "",
bankBalance: -1,
show: false,
amount: 1
}
},
async mounted() {
var web3 = new Web3(window.ethereum);
this.bankAddr = import.meta.env.VITE_BANK_ADDR;
var bank = new web3.eth.Contract(bankABI, this.bankAddr);
var owner = await bank.methods.owner().call();
this.owner = owner.toLowerCase();
var atms = await bank.methods.getATMs().call();
this.atms = atms;
if(ethereum.isConnected()){
this.linked = true;
this.detectMetamask();
}
this.update();
},
methods: {
update() {
var web3 = new Web3(window.ethereum);
var contin = true;
web3.eth.getBalance(this.bankAddr, (err, result) => {
if(web3.utils.fromWei(result) != this.bankBalance)
contin = false;
this.bankBalance = web3.utils.fromWei(result);
})
for(let i=0; i<this.atms.length; i++){
web3.eth.getBalance(this.atms[i], (err, result) => {
if(web3.utils.fromWei(result) != this.atmsBalance[i])
contin = false;
this.atmsBalance[i] = web3.utils.fromWei(result);
})
}
},
async detectMetamask() {
this.msg = "Detecting..."
const provider = await detectEthereumProvider()
if (provider) {
this.msg = "Detect Metamask. "
const chainId = await ethereum.request({method: 'eth_chainId'})
if(chainId == 1337){
const account = await ethereum.request({ method: 'eth_requestAccounts' });
this.account = account[0];
this.msg += "> Network which you connected is Sepolia.";
this.linked = true
}else{
this.msg += "> But the network which you connected isn't Sepolia, this faucet only accept Sepolia address"
}
} else {
this.msg = "ERROR: no Metamask"
}
},
async destroyBank() {
var web3 = new Web3(window.ethereum);
const encodeFunctionCall = web3.eth.abi.encodeFunctionCall({
name: "destroy",
type: "function",
inputs: []
}, []);
console.log(encodeFunctionCall);
const transactionParameters = {
from: ethereum.selectedAddress,
to: this.bankAddr, // smart contract's address
data: encodeFunctionCall,
value: '0x00',
};
const txHash = await ethereum.request({
method: 'eth_sendTransaction',
params: [transactionParameters]
});
console.log(txHash);
},
async destroyATM(index){
console.log(index)
var web3 = new Web3(window.ethereum);
const encodeFunctionCall = web3.eth.abi.encodeFunctionCall({
name: "destroy",
type: "function",
inputs: []
}, []);
const transactionParameters = {
from: ethereum.selectedAddress,
to: this.atms[index], // smart contract's address
data: encodeFunctionCall,
value: '0x00',
};
const txHash = await ethereum.request({
method: 'eth_sendTransaction',
params: [transactionParameters]
});
},
async transfer() {
var eth = this.amount.toString();
var web3 = new Web3(window.ethereum);
var wei = web3.utils.toWei(eth, 'ether');
const transactionParameters = {
from: ethereum.selectedAddress,
to: this.bankAddr, // smart contract's address
value: '0x'+BigInt(wei).toString(16),
};
const txHash = await ethereum.request({
method: 'eth_sendTransaction',
params: [transactionParameters]
});
},
showModel() {
if(this.show == false){
this.show = true;
}else{
this.show = false;
this.transfer()
}
}
},
}
</script>
<template>
<section class="page-section portfolio" id="portfolio">
<div class="container">
<!-- Portfolio Section Heading-->
<h2 class="page-section-heading text-center text-uppercase text-secondary mb-0">Management</h2>
<!-- Icon Divider-->
<div class="divider-custom">
<div class="divider-custom-line"></div>
<div class="divider-custom-icon"><i class="fa-brands fa-ethereum"></i></div>
<div class="divider-custom-line"></div>
</div>
<!-- Portfolio Grid Items-->
<div class="row justify-content-center">
<p>{{ msg }}</p>
<template v-if='!linked'>
<button class='btn btn-info' v-on:click="detectMetamask"> link to Metamask </button>
</template>
<template v-else>
<div>
<div class="container">
<div class="row">
<div class="col-sm-5">
Your address: {{ this.account }}
Bank Owner: {{ this.owner }}
<template v-if="this.account == this.owner">
<p style="color: blue">You are owner</p>
</template>
<template v-else>
<p style="color: red">You are not owner</p>
</template>
</div>
</div>
</div>
</div>
</template>
</div>
<br><br>
<hr>
<br><br>
<template v-if='linked && this.account == this.owner'>
<div class="row justify-content-center">
<h2 class="page-section-heading text-center text-uppercase text-secondary mb-0">Bank</h2>
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">Address</th>
<th scope="col">Balance</th>
<th scope="col">Destroy</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ bankAddr }}</td>
<td>{{ bankBalance }} ETH</td>
<td><button class="btn btn-danger" v-on:click="destroyBank">Destroy</button>
<input type="number" v-if="show" v-model="amount" placeholder="ETH">
<button class="btn btn-primary" v-on:click="showModel">Transfer</button></td>
</tr>
</tbody>
</table>
</div>
<br><br>
<br><br>
<div class="row justify-content-center">
<h2 class="page-section-heading text-center text-uppercase text-secondary mb-0">ATM List</h2>
<table class="table table-bordered">
<thead>
<tr>
<th scope="col">Address</th>
<th scope="col">Balance</th>
<th scope="col">Destroy</th>
</tr>
</thead>
<tbody>
<template v-for="i in atms.length">
<tr>
<td>{{ atms[i-1] }}</td>
<td>{{ atmsBalance[i-1] }} ETH</td>
<td><button class="btn btn-danger" v-on:click="destroyATM(i-1)">Destroy</button></td>
</tr>
</template>
</tbody>
</table>
</div>
<br><button class='btn btn-info' v-on:click='update'>Update</button>
</template>
</div>
</section>
</template>