Initial commit

This commit is contained in:
zhl 2023-04-19 14:50:09 +08:00
commit 252aa995cd
11 changed files with 50034 additions and 0 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

166
assets/scripts/confirm.js Normal file
View File

@ -0,0 +1,166 @@
const { createApp } = Vue;
const API_BASE = "http://localhost:3002";
const TASK_INFO_URL = "/workflow/task";
const DEFAULT_CHAIN_DATA = {
name: "Matic Testnet RPC",
type: "Testnet",
rpc: "https://rpc-mumbai.maticvigil.com",
id: 80001,
symbol: "MATIC",
explorerurl: "https://mumbai.polygonscan.com/",
};
const loader = document.getElementById("loader");
// 显示加载动画
function showLoading() {
// add style display: block
loader.style.display = "block";
}
// 隐藏加载动画
function hideLoading() {
// add style display: none
loader.style.display = "none";
}
async function loadJson(url) {
return fetch(url).then((response) => response.json());
}
function toHexChainId(chainId) {
return "0x" + chainId.toString(16);
}
async function connectMetaMask() {
let provider = null;
if (typeof window.ethereum !== "undefined") {
provider = window.ethereum;
try {
await provider.request({ method: "eth_requestAccounts" });
} catch (error) {
if (error.code === -32002) {
throw new Error("MeatMask not login, Open MeatMask and login first");
} else {
throw new Error("User Rejected");
}
}
} else if (window.web3) {
provider = window.web3.currentProvider;
} else if (window.celo) {
provider = window.celo;
} else {
throw new Error("No Web3 Provider found");
}
return provider;
}
const fetchTaskInfo = function (taskId) {
const url = `${API_BASE}${TASK_INFO_URL}/${taskId}`;
return fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error("Failed to fetch task info");
}
return response.json();
})
.then((data) => {
if (data.errcode) {
throw new Error(data.errmsg);
}
return data.data;
});
};
createApp({
data() {
return {
id: "",
task: {},
subTasks: [],
address: "",
types: {},
walletConnect: false,
contract: null,
wallet: null,
disabled: false,
chainId: 0,
};
},
async created() {
let params = getAllParameter();
this.id = params.id;
console.log("taskid: ", this.id);
let result = await fetchTaskInfo(this.id);
this.task = result.chainTask;
this.subTasks = result.requestTasks;
this.address = result.address;
this.types = result.types;
console.log(result);
await this.initWallet();
},
methods: {
showType(type) {
return this.types[type];
},
async initInstance(user, address, jsonUrl) {
let json = await loadJson(jsonUrl);
return new this.web3.eth.Contract(json.abi, address, { from: user });
},
async initWallet() {
let provider = await connectMetaMask();
this.web3 = new Web3(provider);
let accounts = await this.web3.eth.getAccounts();
if (accounts.length > 0) {
this.account = accounts[0];
}
this.contract = await this.initInstance(
this.account,
this.address,
"assets/abis/BEMultiSigWallet.json"
);
this.chainId = await this.web3.eth.getChainId();
this.walletConnect = true;
console.log(this.chainId, this.account);
console.log(this.contract);
},
async confirmTask() {
let ids = this.subTasks.map((o) => o.scheduleId);
console.log("confirm task", ids);
showLoading();
try {
let gas = await this.contract.methods
.confirmTransaction(ids)
.estimateGas();
gas = gas | 0;
await this.contract.methods.confirmTransaction(ids).send({ gas });
} catch (err) {
console.log("error confirm task", err);
}
hideLoading();
},
async rejectTask() {
console.log("reject task");
let ids = this.subTasks.map((o) => o.scheduleId);
showLoading();
try {
let gas = await this.contract.methods
.revokeConfirmation(ids)
.estimateGas();
gas = gas | 0;
await this.contract.methods.revokeConfirmation(ids).send({ gas });
} catch (err) {
console.log("error confirm task", err);
}
hideLoading();
},
async querySchedule(id) {
let instance = wallet.contract;
return makeBatchRequest([
instance.methods.isOperation(id).call,
instance.methods.isOperationPending(id).call,
instance.methods.isOperationReady(id).call,
instance.methods.isOperationDone(id).call,
instance.methods.isConfirmed(id).call,
instance.methods.getTimestamp(id).call,
]);
},
},
}).mount("#app");

File diff suppressed because one or more lines are too long

20
assets/scripts/lib.js Normal file
View File

@ -0,0 +1,20 @@
function getParameter(t) {
var e = window.location.search,
i = new RegExp(t + "=([^&?]*)", "ig");
return e.match(i) ? e.match(i)[0].substr(t.length + 1) : null
}
function getAllParameter() {
var pairs = window.location.search.substring(1).split("&");
var obj = {};
for (let i in pairs ) {
if ( pairs[i] === "" ) continue;
let pair = pairs[i].split("=");
obj[ decodeURIComponent( pair[0] ) ] = decodeURIComponent( pair[1] );
}
return obj
}
function isMobile() {
return /(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent);
}

View File

@ -0,0 +1,12 @@
(function() {
var params = getAllParameter()
console.log(params)
console.log(location)
var next = `confirm.html?id=${params.id}`
if (isMobile()) {
var url = `https://metamask.app.link/dapp/${location.host}/ct/${next}`
document.getElementById('href').setAttribute('href', url)
} else {
// location.href = url
}
})()

10
assets/scripts/vconsole.min.js vendored Normal file

File diff suppressed because one or more lines are too long

16159
assets/scripts/vue.global.js Normal file

File diff suppressed because it is too large Load Diff

3
assets/scripts/web3.min.js vendored Normal file

File diff suppressed because one or more lines are too long

105
confirm.html Normal file
View File

@ -0,0 +1,105 @@
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>crypto test</title>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Expires" content="0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-control" content="no-cache">
<meta http-equiv="Cache" content="no-cache">
<meta name="viewport" content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, minimal-ui" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="full-screen" content="true" />
<meta name="screen-orientation" content="portrait" />
<meta name="x5-fullscreen" content="true" />
<meta name="360-fullscreen" content="true" />
<meta name="apple-mobile-web-app-title" content="WJTX">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<style>
.small-address{
font-size: 0.8rem;
}
</style>
</head>
<body>
<div id="app" class="container">
<div class="page-header">
<h1>
{{task.name}} - <small>{{task.starterName}}</small>
</h1>
<p>{{task.desc}}</p>
<p>本次申请包含<b>{{subTasks.length}}</b>个链操作任务</p>
</div>
<div class="hstack gap-3 mb-1">
<template v-if="!walletConnect">
<button type="button" class="btn btn-info" @click="initWallet">连接钱包</button>
<div class="vr"></div>
</template>
<button type="button" class="btn btn-primary" :disabled="disabled" @click="confirmTask">确认</button>
<div class="vr"></div>
<button type="button" class="btn btn-danger" :disabled="disabled">拒绝</button>
</div>
<div class="row">
<div class="col-md-12">
<div class="accordion" id="accordionExample">
<div class="accordion-item" v-for="(item, i) in subTasks" >
<h2 class="accordion-header" id="heading{{i}}">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapse{{i}}" aria-expanded="true" aria-controls="collapse{{i}}">
任务{{item.index}}: {{item.reqDatas.length}}个子任务
</button>
</h2>
<div id="collapse{{i}}" class="accordion-collapse collapse show" aria-labelledby="heading{{i}}" data-bs-parent="#accordionExample">
<div class="accordion-body">
<div v-for="sub in item.reqDatas" class="border-bottom">
<p><label class="text-secondary">类型:</label> {{showType(sub.type)}}</p>
<p class="small-address"><label class="text-secondary">合约地址: </label>{{sub.address}}</p>
<p class="small-address"><label class="text-secondary">目标钱包: </label>{{sub.to}}</p>
<p v-if="sub.amount"><label class="text-secondary">数量: </label>{{sub.amount}}</p>
<p v-if="sub.tokenId"><label class="text-secondary">NFT ID: </label>{{sub.tokenId}}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="loader" id="loader">
<div class="loader-inner">
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
</div>
</div>
<script src="assets/scripts/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<script src="assets/scripts/vconsole.min.js"></script>
<script src="assets/scripts/web3.min.js"></script>
<script src="assets/scripts/lib.js"></script>
<script src="assets/scripts/vue.global.js"></script>
<script src="assets/scripts/confirm.js"></script>
</body>
</html>

60
redirect.html Normal file
View File

@ -0,0 +1,60 @@
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>crypto test</title>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Expires" content="0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-control" content="no-cache">
<meta http-equiv="Cache" content="no-cache">
<meta name="viewport" content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, minimal-ui" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="full-screen" content="true" />
<meta name="screen-orientation" content="portrait" />
<meta name="x5-fullscreen" content="true" />
<meta name="360-fullscreen" content="true" />
<meta name="apple-mobile-web-app-title" content="WJTX">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<style>
body {
}
.main-btn {
width: 100%;
display: flex;
justify-content: center;
margin-top: 8rem;
}
.main-btn a {
text-decoration: none;
padding: 0.5rem 1rem;
margin: 0.25rem 0.125rem;
cursor: pointer;
background-color: #198754;
vertical-align: middle;
border: 1px solid #198754;
border-radius: 5px;
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
font-size: 1.0rem;
color: white;
}
</style>
</head>
<body>
<div id="app">
<div class="main-btn"><a href="" id="href">点击跳转至操作页面</a></div>
</div>
<script src="assets/scripts/lib.js"></script>
<script src="assets/scripts/redirect.js"></script>
</body>
</html>