import { Message } from 'element-ui';
import { ethers } from "ethers"; //版本号为 "ethers": "^4.0.47",
import Tabi from './Tabi.json'; //后端给
import { infoChain } from '@/api/require'
let provider = new ethers.providers.Web3Provider(window[sessionStorage.getItem('ethereumType')] || window.ethereum);
function renewProvider() {
provider = new ethers.providers.Web3Provider(window[sessionStorage.getItem('ethereumType')] || window.ethereum);
}
/**
* 查询主网络资产余额
* @param {*} address 钱包地址
* @param {*} tokenDecimals token精度
*/
export async function getMainNetworkBalance(address ,tokenDecimals=18){
const balancePromise = provider.getBalance(address)
return balancePromise.then((balance) => {
return ethers.utils.formatUnits(balance, tokenDecimals);
}).catch(e => {
Message({
type: 'error',
showClose: true,
message: 'Failed to get balance.'
})
throw new Error("获取余额失败" + e)
});
}
// 查询余额,固定不变的
const erc20BalanceAbiFragment = [{
"constant": true,
"inputs": [{ "name": "", "type": "address" }],
"name": "balanceOf",
"outputs": [{ "name": "", "type": "uint256" }],
"type": "function"
}]
// token授权,固定不变的
const ERC20_ABI = [
"function allowance(address owner, address spender) external view returns (uint256)",
"function approve(address spender, uint256 amount) external returns (bool)"
]
/**
* 添加metamask网络
*/
async function addChain() {
try {
// infoChain 获取要添加的链的 {chainId,chainName,nativeCurrency,rpcUrls,blockExplorerUrls}
const res = await infoChain()
if (res.code === 0) {
await window[sessionStorage.getItem('ethereumType') || 'ethereum'].request({
method: "wallet_addEthereumChain",
params: [{
chainId: '0x' + res.data.chainId.toString(16),
chainName: res.data.chainName,
nativeCurrency: {
name: res.data.suisse.symbol,
symbol: res.data.suisse.symbol,
decimals: 18,
},
rpcUrls: [res.data.rpcUrl],
blockExplorerUrls: [res.data.scanUrl],
}],
});
}
} catch (error) {
console.log(error)
throw error
}
}
/**
* 切换到指定网络
* @param {*} chainId 要切换的链id
*/
export async function toSwitch(chainId) {
try {
window[sessionStorage.getItem('ethereumType') || 'ethereum'] && await window[sessionStorage.getItem('ethereumType') || 'ethereum'].request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: '0x' + chainId.toString(16) }]
}, (err, result) => {
console.log(err, '添加失败')
if (err) {
Message({
message: err.message,
type: 'error'
})
return false
}
});
} catch (error) {
if (error.code === 4902) {
addChain()
} else {
throw error
}
}
}
/**
* 检查当前metamask 链接网络是否正确
* @param {*} chainId 传入链id
* @returns {Boolean}
*/
export async function chainIdJudgment(chainId) {
try {
let eth_chainId = await window[sessionStorage.getItem('ethereumType') || 'ethereum'].request({ method: 'eth_chainId' }); //16进制
// 将16进制转为10进制
eth_chainId = parseInt(eth_chainId, 16)
if (eth_chainId != chainId) {
toSwitch(chainId)
} else {
return true
}
} catch (error) {
console.log(error)
return false
}
}
/**
* 发起交易
* @param {multySignAddress} String 后端部署合约地址
* @param {String} numbers 交易数量
* @param {Number} decimals token精度
*/
export async function payMoney(multySignAddress,pid,numbers, decimals=18) {
// new ethers.utils.BigNumber
// numbers 交易数量
// decimals token精度
// functions后面的方法 调什么方法在 Tabi.json找对应的name(问后端用那个)
// encode 传几个参数在 Tabi 里面inputs数组有几个传几个,类型看internalType,值看internalType值
/**
* 使用条件:购买5个面包,一个面包价值6.89元 priceView 当面包的价格
* ethers.utils.parseEther(new BigNumber(numbers).multipliedBy(new BigNumber(priceView)).toString())
* 如何使用: 将value: '0x00' 改为 value: ethers.utils.parseEther(new BigNum................
*/
const numberOfTokens = ethers.utils.parseUnits(numbers.toString(), decimals);
const pidTokens = ethers.utils.parseUnits(pid.toString(), 0);
const iface = new ethers.utils.Interface(Tabi);
const data = iface.functions.deposit.encode([pidTokens,numberOfTokens]);
const address = window[sessionStorage.getItem('ethereumType') || window.ethereum].selectedAddress
let transactionParameters = {
to: multySignAddress,
from: address, //验证合约调用需要from,必传
value: '0x00',
data: data
};
const failed = await validate(transactionParameters);
if (failed) {
console.error('failed approveERC20' + failed);
return { success: false, msg: 'failed crossIn' + failed }
}
delete transactionParameters.from; //etherjs 4.0 from参数无效 报错
return sendTransaction(transactionParameters)
}
//验证交易参数
async function validate(tx) {
renewProvider()
try {
const result = await provider.call(tx);
return ethers.utils.toUtf8String("0x" + result.substr(138));
} catch (e) {
// 金额不够提示
if(e.code == -32000){
if(e.message.indexOf('err: insufficient funds for gas') > -1){
Message({
type: 'error',
showClose: true,
message: 'You do not have enough Balance in your account to pay for transaction fees on network.'
})
}else{
Message({
type: 'error',
showClose: true,
message: e.message
})
}
}else{
Message({
type: 'error',
showClose: true,
message: e.message
})
}
return false;
}
}
async function sendTransaction(tx) {
renewProvider()
const wallet = provider.getSigner();
return await wallet.sendTransaction(tx);
}
/**
* 进行授权
* @param {*} contractAddress 支付币的合约地址
* @param {*} multySignAddress 要收到支付的合约地址
* @param {*} address 钱包地址
*/
export async function approveERC20(contractAddress, multySignAddress, address) {
const iface = new ethers.utils.Interface(ERC20_ABI);
const data = iface.functions.approve.encode([multySignAddress, new ethers.utils.BigNumber('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')]);
const transactionParameters = {
to: contractAddress,
from: address,
value: '0x00',
data: data,
};
const failed = await validate(transactionParameters);
if (failed) {
console.error('failed approveERC20' + failed);
return { success: false, msg: 'failed approveERC20' + failed }
}
delete transactionParameters.from; //etherjs 4.0 from参数无效 报错
return sendTransaction(transactionParameters)
// const res ={} const r = await wait()
}
/**
* 查询是否需要授权
* @param contractAddress 支付币的合约地址
* @param multySignAddress 要收到支付的合约地址
* @param address 钱包账户地址
* 参数里面的contractAddress 是erc20资产的合约地址 multySignAddress是要后端他们部署的那个合约地址
*/
export async function getERC20Allowance(contractAddress, multySignAddress, address) {
renewProvider()
const contract = new ethers.Contract(contractAddress, ERC20_ABI, provider);
const allowancePromise = contract.allowance(address, multySignAddress);
return allowancePromise
.then(allowance => {
const baseAllowance = "39600000000000000000000000000";
//已授权额度小于baseAllowance,则需要授权
return allowance.lte(baseAllowance)
})
.catch(e => {
// this.$mes.closeLoading()
Message({
type: 'error',
showClose: true,
message: 'Failed to get balance.'
})
console.error("获取erc20资产授权额度失败" + e);
return true;
});
}
/**
* 查询账户余额或者查询合约余额
* @param contractAddress ERC20合约地址
* @param tokenDecimals token小数位数
* @param address 账户地址
*/
export function getERC20Balance(contractAddress, tokenDecimals, address) {
renewProvider()
let contract = new ethers.Contract(contractAddress, erc20BalanceAbiFragment, provider);
let balancePromise = contract.balanceOf(address);
return balancePromise.then((balance) => {
return ethers.utils.formatUnits(balance, tokenDecimals);
}).catch(e => {
// this.$mes.closeLoading()
Message({
type: 'error',
showClose: true,
message: 'Failed to get balance.'
})
throw new Error("获取余额失败" + e)
});
}
// 获取gas的单价
export async function getGasPrice() {
renewProvider()
const gasPrice = await provider.getGasPrice();
return gasPrice.toString();
}
// 预估最大会消耗多少gas
export async function estimateGas(tx) {
try {
renewProvider()
const failed = await validate(tx);
if (failed) {
console.error('failed approveERC20' + failed);
return { success: false, msg: 'failed approveERC20' + failed }
}
const gasLimit = await provider.estimateGas(tx);
return gasLimit.add(10000).toString();
} catch (e) {
console.log(e, 'fail to estimateGas, use the defaultGasLimit');
return '150000';
}
}
/**
* 查询gas费(交易手续费)
* @param tx 参数是发交易的transactionParameters参数
* @returns gas费
*/
export async function getFee(multySignAddress,pid,numbers, _this) {
const numberOfTokens = ethers.utils.parseUnits(numbers.toString(), 18);
const pidTokens = ethers.utils.parseUnits(pid.toString(), 0);
const iface = new ethers.utils.Interface(Tabi);
const data = iface.functions.deposit.encode([pidTokens,numberOfTokens]);
const address = window[sessionStorage.getItem('ethereumType') || window.ethereum].selectedAddress
let transactionParameters = {
to: multySignAddress,
from: address, //验证合约调用需要from,必传
value: '0x00',
data: data
};
const gasPrice = await getGasPrice();
const gasLimit = await estimateGas(transactionParameters);
// accMul 乘法
const bigNumberFee = _this.$tool.accMul(gasPrice, gasLimit);
return ethers.utils.formatEther(bigNumberFee);
}