vue-blocklink
Version:
Vue support for the Blockchain Link browser extension
494 lines (438 loc) • 16 kB
text/typescript
import {Ori20Contract} from "./ori20";
import type {
AddEthereumChainParameter,
ContractTokenMap,
TransactionReceipt,
WatchAssetParams,
Web3ERC20Token,
WebLinkTokenMap
} from "../base/eth/types";
import {WalletSupport} from "../base/wallet";
import {Vue} from "vue/types/vue";
import CoinDetail from "./CoinDetail";
import ethUtil from "ethereumjs-util";
import sigUtil from "eth-sig-util";
import Web3 from "web3";
import {Utils} from 'web3-utils';
import {TransactionConfig} from 'web3-core';
import BN from 'bn.js'
import * as _ from "lodash";
/**
* BlockWrap extension interaction functionality
*/
export default class BlockWrap {
ethereumCore: any
tokens: WebLinkTokenMap
contracts: ContractTokenMap;
w3: Web3
debug: boolean = false
errorHandler: any;
confirmHandler: any;
boardcastHandler: any;
accounts: Array<string> = [];
gas: number = 1000000
gasPrice: number | string = 21000000000
wallet: WalletSupport
/**
* Initiates BlockWrap support object.
*
* @param {Object} ethereumCore ethereumCore entity object
* (details: https://github.com/tronprotocol/tron-web)
*/
constructor(webThree, ethereumCore) {
this.ethereumCore = ethereumCore
this.w3 = webThree as Web3
this.tokens = {}
this.contracts = {}
}
setDebug(x: boolean): void {
this.debug = x
}
setWallet(wallet_connect: WalletSupport): void {
this.wallet = wallet_connect
}
/**
* Checks if BlockWrap browser extension is installed
*/
isInstalled(): boolean {
return this.ethereumCore.isConnected()
}
/**
* Checks if user is logged in to the BlockWrap plugin
*/
isLoggedIn(): boolean {
return this.ethereumCore && this.ethereumCore.isConnected()
}
/**
*
* Is this an address?
*/
isAddress(test: any): boolean {
return this.w3.utils.isAddress(test)
}
/**
*
* Is this an address?
*/
w3Utils(): Utils {
return this.w3.utils
}
/**
* Checks if user is logged in to the BlockWrap plugin.
* Alias for isLoggedIn() method.
*/
async isUnlocked(): Promise<boolean> {
return await this.ethereumCore._metamask.isUnlocked()
}
/**
* Returns logged in user Tron address
*/
getAccountAddress(): string {
return this.accounts[0]
}
setAccounts(data): void {
if (this.debug) {
console.log("set account now", data)
}
this.accounts = _.map(data, (e) => this.w3.utils.toChecksumAddress(e))
}
setResource(gas: number, gas_price: number): void {
this.gas = gas
this.gasPrice = gas_price
//const f = this.w3.utils.toBN(1)
//const need = this.w3.utils.toWei(f, "gwei")
if (this.debug) {
// console.log(need)
}
this._setOtherRrc(gas, gas_price)
}
private _setOtherRrc(gas: number, gas_price: number): void {
for (let b in this.contracts) {
this.contracts[b].setResource(gas, gas_price)
}
}
haveAccounts(): boolean {
return this.accounts.length > 0
}
NewContractFallback(abi: any[] = [], address: string = ""): any {
const contract = this.w3.eth.Contract
// @ts-ignore
contract.setProvider(this.ethereumCore)
return new contract(abi, address, {
from: this.accounts[0], // default from address
gasPrice: String(this.gasPrice) // default gas price in wei, 20 gwei in this case
})
}
// @ts-ignore
async sendCoin(amount: any, toaddress: string): Promise<TransactionReceipt> {
const conf: TransactionConfig = {
value: amount,
to: toaddress,
gas: this.gas,
gasPrice: this.gasPrice,
from: this.accounts[0]
}
await this.w3.eth.sendTransaction(conf).on("confirmation", this.confirmHandler).catch(this.errorHandler);
//return receipt;
}
public async sendToken(amount: any, toaddress: string, erc20_address: string): Promise<void> {
const contract = await this.NewToken(erc20_address);
// @ts-ignore
const send_amount = new BN(amount);
await contract.transfer(toaddress, send_amount);
}
public async approveToken(erc20_address: string, spender_address: string, amount_sun: any): Promise<void> {
const contract = await this.NewToken(erc20_address);
//const am = new BigNumber(amount_sun)
const am = this.w3.utils.toBN(amount_sun)
await contract.approve(spender_address, am)
}
public async approveTokenUnlimited(erc20_address: string, spender_address: string) {
const contract = await this.NewToken(erc20_address);
// const am = new BigNumber({s: 1, e: 2, c: [1000000000000000000, 1000000000000000000], _isBigNumber: true});
// const am = new BigNumber("1234567891200000000000000000000000000");
// const am = new BN("1000");
// console.log(am)
let amc = "1000000000000000000000000"
// const val = this.w3.utils.toWei(am, 'ether')
const am = this.w3.utils.toBN(amc)
console.log(am)
let val = am
await contract.approve(spender_address, val);
}
public async getMyTokenBalance(trc20_coin: string): Promise<number> {
return await this.getTokenBalanceWei(this.getAccountAddress(), trc20_coin)
}
/**
* get the keccak256
* @param data
*/
public keccak256(data: any): string {
return this.w3.utils.keccak256(data)
}
/**
*
* @param data
*/
public sha(data: any): string | null {
return this.w3.utils.soliditySha3(data)
}
public async balance(): Promise<string> {
return await this.w3.eth.getBalance(this.getAccountAddress())
}
/**
* doesnt work on the older version
* @deprecated
*/
async getCoinPlatform(): Promise<number> {
// @ts-ignore
return await this.w3.eth.getBalance(this.getAccountAddress())
}
async getMyCoinDetail(trc20_coin: string): Promise<CoinDetail> {
return await this.getCoinDetail(trc20_coin, this.getAccountAddress())
}
async coinExample(): Promise<CoinDetail> {
return await this.getMyCoinDetail("TXHvwxYbqsDqTCQ9KxNFj4SkuXy7EF2AHR")
}
public async initCoinDetail(erc20: string, me: string): Promise<CoinDetail> {
const contract = await this.NewToken(erc20)
const a = await contract.balanceOf(me)
const d = await contract.decimals()
const s = await contract.symbol()
const name = await contract.name()
const detail = new CoinDetail(erc20, d, s, name)
detail.setHolder(me, a)
this.tokens[erc20] = detail
this.contracts[erc20] = contract
return detail
}
/**
* get TRC20 token in balance
* @param address
* @param erc20_address
*/
public async getCoinDetail(erc20_address: string, address: string): Promise<CoinDetail> {
if (!this.isLoggedIn()) {
throw "wallet is not login"
}
if (!this.tokens.hasOwnProperty(erc20_address)) {
// console.log("init coin detail")
await this.initCoinDetail(erc20_address, address)
} else {
let contract = this.contracts[erc20_address]
if (!contract) {
contract = await this.NewToken(erc20_address)
this.contracts[erc20_address] = contract
}
const b = await contract.balanceOf(address)
// @ts-ignore
this.tokens[erc20_address].setHolder(address, b)
}
// @ts-ignore
return this.tokens[erc20_address];
}
async getContractToken(erc20_address: string): Promise<Ori20Contract> {
let contract = this.contracts[erc20_address]
if (!contract) {
if (this.debug) {
console.log("new contract token ...")
}
contract = await this.NewToken(erc20_address)
this.contracts[erc20_address] = contract
}
return contract
}
async getTokenBalanceWei(address: string, erc20_address: string): Promise<number> {
if (!this.tokens.hasOwnProperty(erc20_address)) {
const conver = await this.getCoinDetail(erc20_address, address);
return conver.amountCode(address);
} else {
let contract = this.contracts[erc20_address]
// tokende.holder[address] = await contract.balanceOf(address)
const b = await contract.balanceOf(address)
// @ts-ignore
this.tokens[erc20_address].setHolder(address, b)
return b.toNumber()
}
}
async NewToken(erc20_address: string): Promise<Ori20Contract> {
const contr = await Ori20Contract.init(erc20_address, this.ethereumCore, this.w3)
// @ts-ignore
contr.setResource(this.gas, this.gasPrice);
contr.setBlockLink(this)
return contr
}
getListedCoins(): WebLinkTokenMap {
return this.tokens
}
explainTrc20(payload: Web3ERC20Token): number {
const me = this.getAccountAddress()
return payload.holder[me]
}
eventListener(message: any, vueInstance: Vue) {
}
setHandlers(confirm, broadcast, err): void {
this.errorHandler = err
this.boardcastHandler = broadcast
this.confirmHandler = confirm
}
metamask_decrypt(encryptedMessage, account_address, callback): void {
if (!this.ethereumCore) return;
this.ethereumCore
.request({
method: 'eth_decrypt',
params: [encryptedMessage, account_address],
})
.then((decryptedMessage) => {
if (this.debug) {
console.log('The decrypted message is:', decryptedMessage)
}
callback(decryptedMessage)
})
.catch(this.errorHandler)
}
async metamask_message_sign_v3(message, resultcb): Promise<void> {
await this.w3.eth.personal.sign(
this.w3Utils().fromUtf8(message),
this.getAccountAddress(),
"",
).then((signature) => {
resultcb(signature)
}).catch(this.errorHandler);
// await this.ethereumCore.send("eth_requestAccounts");
/* const provider = new Web3Provider(this.ethereumCore);
const signer = provider.getSigner();
const signature = await signer.signMessage(message);
const address = await signer.getAddress();
resultcb(address, signature)*/
}
metamask_message_personal_sign(message, resultcb): void {
/*
const msgParams = JSON.stringify({
domain: {
// Defining the chain aka Rinkeby testnet or Ethereum Main Net
chainId: 1,
// Give a user friendly name to the specific contract you are signing for.
name: 'Ether Mail',
// If name isn't enough add verifying contract to make sure you are establishing contracts with the proper entity
verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
// Just let's you know the latest version. Definitely make sure the field name is correct.
version: '1',
},
// Defining the message signing data content.
message: {
/!*
- Anything you want. Just a JSON Blob that encodes the data you want to send
- No required fields
- This is DApp Specific
- Be as explicit as possible when building out the message schema.
*!/
contents: 'Hello, Bob!'
},
});*/
const msg = this.w3Utils().fromUtf8(message)
const hash = this.w3.eth.accounts.hashMessage(message)
this.ethereumCore
.request({
method: 'personal_sign',
params: [this.getAccountAddress(), msg],
from: this.getAccountAddress()
}).then((rs) => {
resultcb(this.getAccountAddress(), hash, rs)
}).catch(this.errorHandler)
}
metamask_encryption(encryptionPublicKey, message): string {
return ethUtil.bufferToHex(
Buffer.from(JSON.stringify(
sigUtil.encrypt(
encryptionPublicKey,
{data: message},
'x25519-xsalsa20-poly1305'
)
), 'utf8')
);
}
metamask_add_token(token_conf: WatchAssetParams): void {
this.ethereumCore
.request({
method: 'wallet_watchAsset',
params: token_conf,
})
.then((success) => {
if (success) {
if (this.debug) {
console.log('FOO successfully added to wallet!')
}
} else {
throw new Error('Something went wrong.')
}
})
.catch(this.errorHandler)
}
ensureChainParameterPatch(conf: AddEthereumChainParameter): AddEthereumChainParameter {
const ishex = this.w3Utils().isHexStrict(conf.chainId)
let conf2 = conf
if (!ishex) {
const chainID = this.w3Utils().toHex(conf.chainId)
conf2 = Object.assign({}, conf, {
chainId: chainID,
iconUrls: ["https://i.pinimg.com/564x/3c/ee/90/3cee90ab71e45757b8f0250b79a76bd0.jpg"]
});
//console.log(chainID)
}
// console.log(conf)
//console.log(conf2)
return conf2
}
metamask_add_chain(chain_conf: AddEthereumChainParameter): void {
const conf = this.ensureChainParameterPatch(chain_conf)
this.ethereumCore
.request({
method: 'wallet_addEthereumChain',
params: [conf],
})
.then((success) => {
if (success) {
if (this.debug) {
console.log('Chain is successfully added to wallet!')
}
} else {
throw new Error('Something went wrong.')
}
})
.catch(this.errorHandler)
}
async metamask_detect_chain_process_flow(conf: AddEthereumChainParameter): Promise<void> {
const conf2 = this.ensureChainParameterPatch(conf)
if (this.wallet === WalletSupport.IMTOKEN) {
try {
await this.ethereumCore.request({
method: "wallet_addEthereumChain",
params: [conf2, this.getAccountAddress()],
});
} catch (addError) {
this.errorHandler(addError)
}
} else {
try {
await this.ethereumCore.request({
method: "wallet_switchEthereumChain",
params: [{chainId: conf2.chainId}, this.getAccountAddress()],
});
} catch (switchError) {
if (switchError.code === 4902) {
try {
await this.ethereumCore.request({
method: "wallet_addEthereumChain",
params: [conf2, this.getAccountAddress()],
});
} catch (addError) {
this.errorHandler(addError)
}
} else {
this.errorHandler(switchError)
}
}
}
}
}