transferAmount: '转账金额',
transferCost: '当前价值',
total: '总计',
- confirmTransaction:'确认发送交易',
+ confirmTransaction:'交易确认',
totalTip: '转账金额+矿工费用',
success: '交易发送成功',
from:'发送账户',
viewAll:'展示全部',
hideAll:'隐藏全部',
types:'交易类型',
- password:'请输入密码'
+ password:'请输入密码',
+ detail:'交易详情',
+ requestDetail:'请求详情',
+ amount:'交易金额'
},
listAsset: {
all:'全部',
return false;
}
- NotificationService.open(new Prompt(PromptTypes.REQUEST_SIGN, '', payload ,approved => {
- sendResponse(camelize(approved));
+ const {domain, ...txAttrs} = payload;
+
+ txAttrs.type = 'message'
+
+ NotificationService.open(new Prompt(PromptTypes.REQUEST_PROMPT, domain, txAttrs ,approved => {
+ sendResponse(camelize(approved));
}));
+
+ // NotificationService.open(new Prompt(PromptTypes.REQUEST_SIGN, '', payload ,approved => {
+ // sendResponse(camelize(approved));
+ // }));
}
transfer(sendResponse, payload) {
- var promptURL = chrome.extension.getURL('pages/prompt.html')
+ // var promptURL = chrome.extension.getURL('pages/prompt.html')
var requestBody = payload
- requestBody.type = "popup"
- var queryString = new URLSearchParams(requestBody).toString()
- console.log(promptURL, queryString)
+ // requestBody.type = "popup"
+ // var queryString = new URLSearchParams(requestBody).toString()
+ // console.log(promptURL, queryString)
if(requestBody.from === undefined){
sendResponse(Error.typeMissed('from'));
return false;
}
+ const {domain, ...txAttrs} = payload;
+
+ txAttrs.type = 'transfer'
+
+ NotificationService.open(new Prompt(PromptTypes.REQUEST_PROMPT, domain, txAttrs ,approved => {
+ sendResponse(camelize(approved));
+ }));
+
// NotificationService.open(new Prompt(PromptTypes.REQUEST_TRANSFER, '', payload ,approved => {
// sendResponse(approved);
// }));
- chrome.windows.create(
- {
- url: `${promptURL}#transfer?${queryString}`,
- type: 'popup',
- width: 420,
- height: 623,
- top: 0,
- left: 0
- },
- (window) => {
- chrome.runtime.onMessage.addListener(function(request, sender) {
- if(sender.tab.windowId === window.id){
- switch (request.method){
- case 'transfer':
- if (request.action === 'success'){
- sendResponse(camelize(request.message));
- return true;
- } else if (request.action === 'reject'){
- sendResponse(request.message);
- return false;
- }
- }
- }
- });
-
- chrome.windows.onRemoved.addListener(function(windowId){
- if(windowId === window.id) {
- sendResponse(Error.promptClosedWithoutAction());
- return false;
- }
- });
- }
- )
+ // chrome.windows.create(
+ // {
+ // url: `${promptURL}#transfer?${queryString}`,
+ // type: 'popup',
+ // width: 420,
+ // height: 623,
+ // top: 0,
+ // left: 0
+ // },
+ // (window) => {
+ // chrome.runtime.onMessage.addListener(function(request, sender) {
+ // if(sender.tab.windowId === window.id){
+ // switch (request.method){
+ // case 'transfer':
+ // if (request.action === 'success'){
+ // sendResponse(camelize(request.message));
+ // return true;
+ // } else if (request.action === 'reject'){
+ // sendResponse(request.message);
+ // return false;
+ // }
+ // }
+ // }
+ // });
+ //
+ // chrome.windows.onRemoved.addListener(function(windowId){
+ // if(windowId === window.id) {
+ // sendResponse(Error.promptClosedWithoutAction());
+ // return false;
+ // }
+ // });
+ // }
+ // )
}
advancedTransfer(sendResponse, payload) {
return false;
}
- NotificationService.open(new Prompt(PromptTypes.REQUEST_ADVANCED_TRANSFER, '', payload ,approved => {
+ const {domain, ...txAttrs} = payload;
+
+ txAttrs.type = 'advTransfer'
+
+ NotificationService.open(new Prompt(PromptTypes.REQUEST_PROMPT, domain, txAttrs ,approved => {
sendResponse(camelize(approved));
}));
}
signTransaction(sendResponse, payload) {
- NotificationService.open(new Prompt(PromptTypes.REQUEST_SIGN_TRANSACTION, '', payload ,approved => {
+ const {domain, ...txAttrs} = payload;
+
+ txAttrs.type = 'signTransaction'
+
+ NotificationService.open(new Prompt(PromptTypes.REQUEST_PROMPT, domain, txAttrs ,approved => {
sendResponse(camelize(approved));
}));
+ // NotificationService.open(new Prompt(PromptTypes.REQUEST_SIGN_TRANSACTION, '', payload ,approved => {
+ // sendResponse(camelize(approved));
+ // }));
}
requestCurrentAccount(sendResponse, payload){
case RouteNames.RESTORE_ACCOUNT:
case RouteNames.SETTING_PASSWORD:
case RouteNames.ENABLE:
+ case RouteNames.BAPP_PROMPT:
case RouteNames.PROTOCOL: return false;
default: return true;
- }
+ }
},
toggleTab(name){
case MsgTypes.SIGNTRANSACTION:
case MsgTypes.ADVTRANSFER:
case MsgTypes.SIGNMESSAGE:
+ this.prompt(msg.type, networkMessage)
+ break
case MsgTypes.SETCHAIN:
case MsgTypes.SEND:
- this.transfer(msg.type, networkMessage)
+ this.send(msg.type, networkMessage)
break
case MsgTypes.ENABLE:
case MsgTypes.DISABLE:
stream.synced = true
}
- transfer(type, message) {
+ send(type, message) {
if (!isReady) return
InternalMessage.payload(type, message.payload)
.then(res => this.respond(message, res))
}
+ prompt(type, message) {
+ if (!isReady) return
+
+ const payload = Object.assign(message.payload, {domain: strippedHost()})
+ InternalMessage.payload(type,payload)
+ .send()
+ .then(res => this.respond(message, res))
+ }
+
enable(type, networkMessage) {
networkMessage.payload ={
domain: strippedHost(),
icon: strippedFavicon()
}
- this.transfer(type, networkMessage)
+ this.send(type, networkMessage)
}
}
bytom.transaction
.buildPayment(address, to, asset, amount.toString(), confirmations)
.then(result => {
- Promise.all(result.map( (data) =>
+ return Promise.all(result.map( (data) =>
signSubmit( data, password, address, context)))
.then((ret )=>{
resolve(ret)
return bytom.keys.signMessage(message, password,address);
};
-transaction.advancedTransfer = function(guid, transaction, password, arrayData, address, context) {
+transaction.advancedTransfer = function(address, transaction, password, arrayData, context) {
let retPromise = new Promise((resolve, reject) => {
signTx(
- guid,
+ address,
JSON.stringify(snakeize(transaction)),
password,
context
import '@/assets/style.css'
import Vuelidate from "vuelidate";
+import account from "@/models/account";
+
store.dispatch(Actions.LOAD_BYTOM).then(() => {
Vue.use(VueI18n)
const i18n = new VueI18n({
}
}
+ account.setupNet(`${store.getters.net}${store.getters.netType}`)
+
+ store.watch(
+ (state, getters) => getters.netType,
+ (newValue, oldValue) => {
+ if(newValue !== oldValue){
+ account.setupNet(`${store.getters.net}${store.getters.netType}`)
+ }
+ },
+ );
+
const RouterConfig = {
routes: Routers
}
export const REQUEST_ADD_NETWORK = 'requestAddNetwork';
export const REQUEST_UNLOCK = 'requestUnlock';
export const UPDATE_VERSION = 'updateVersion';
+
+export const REQUEST_PROMPT = 'bappPrompt'
BACKUP_MNEMONIC:'backup-mnemonic',
WALLETS:'wallets',
BAPP:'bapp',
+ BAPP_PROMPT:'bapp-prompt',
// AUTO_LOCK:'autoLock',
// LANGUAGE:'language',
// KEYPAIRS:'keypairs',
require(['@/views/received.vue'], resolve)
}
},
- {
- path: '/advancedTransfer',
- name: 'advanced-transfer',
- meta: { title: '高级转账' },
- component: resolve => {
- require(['@/views/sendTransaction/advancedTransfer.vue'], resolve)
- }
- },
+
{
path: '/assetSelection',
name: RouteNames.ASSET_SELECTION,
require(['@/views/sendTransaction/signTransaction.vue'], resolve)
}
},
-
+
{
path: '/transfer/info',
name: 'transfer-info',
]
},
{
- path: '/enable',
- name: RouteNames.ENABLE,
- meta: { title: '授权' },
- component: resolve => {
- require(['@/views/prompts/authentication.vue'], resolve)
- }
- },
+ path: '/enable',
+ name: RouteNames.ENABLE,
+ meta: { title: '授权' },
+ component: resolve => {
+ require(['@/views/prompts/authentication.vue'], resolve)
+ }
+ },
+ {
+ path: '/bappPrompt',
+ name: RouteNames.BAPP_PROMPT,
+ meta: { title: 'Bapp请求' },
+ component: resolve => {
+ require(['@/views/prompts/bappPrompt.vue'], resolve)
+ }
+ },
{
path: '/wallets',
name: RouteNames.WALLETS,
children: [
{
path: '/backup/mnemonic',
- name: 'backup-mnemonic',
+ name: RouteNames.BACKUP_MNEMONIC,
meta: { title: '备份助记词' },
component: resolve => {
require(['@/views/backup/backupMnemonic.vue'], resolve)
net:state => state.bytom.settings.network,
netType:state => state.bytom.settings.netType,
language:state => state.bytom.settings.language,
+ domainsMeta:state => state.bytom.settings.domainsMeta,
vMnemonic:state => state.bytom.currentAccount.vMnemonic,
currency:state => state.bytom.settings.currency,
pairs: state => state.bytom.keychain.pairs,
--- /dev/null
+<style lang="scss" scoped>
+ .warp {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 600px;
+ }
+
+ .header {
+ display: flex;
+ justify-content: center;
+ font-weight: 600;
+ font-size: 28px;
+ color: rgba(0, 0, 0, 0.88);
+ margin-top: 60px;
+ margin-bottom: 25px;
+ }
+
+ .content {
+ padding: 20px;
+ overflow: scroll;
+ height: 160px;
+ background: #FAFAFA;
+ border: 1px solid #EBEBEB;
+ border-radius: 8px;
+ margin-bottom: 12px;
+ font-size: 14px;
+ }
+
+ .content-black{
+ color: rgba(0, 0, 0, 0.64);
+ }
+
+ .tab-group {
+ font-size: 14px;
+ line-height: 140%;
+ letter-spacing: 0.2px;
+ display: flex;
+ margin-bottom: 12px;
+ a {
+ margin-right: 24px;
+ }
+ }
+
+ .divider {
+ margin: 12px 0;
+ }
+
+ .uint {
+ margin-left: 3px;
+ }
+
+ .btn-inline .btn {
+ margin: 10px 15px;
+ }
+
+ .row {
+ display: flex;
+ align-items: center;
+ .col {
+ display: flex;
+ }
+ .col:first-child {
+ width: 15%;
+ }
+
+ .col:last-child {
+ width: 85%;
+ }
+ .value {
+ display: flex;
+ font-size: 13px;
+ justify-content: space-between;
+ }
+
+ .wallet {
+ font-size: 14px;
+ }
+
+ .logo {
+ width: 32px;
+ height: 32px;
+ -webkit-border-radius: 16px;
+ -moz-border-radius: 16px;
+ border-radius: 16px;
+ background: white;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 16px;
+ text-transform: uppercase;
+ color: black;
+ }
+ }
+
+ .form-item {
+ padding: 0;
+ margin: 0;
+ margin-bottom: 10px;
+ }
+
+ .hide {
+ width: 175px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .view-link {
+ font-size: 14px;
+ color: #035BD4;
+ width: 275px;
+ display: block;
+ }
+
+ .iconfont.icon_arrow_2 {
+ transform: rotate(90deg);
+ color: #D6D6D6;
+ font-size: 24px;
+ margin-left: 4px;
+ }
+
+ .amount-list {
+ display: flex;
+ justify-content: space-between;
+ font-size: 14px;
+ }
+
+ .info {
+ margin-bottom: 20px;
+ }
+
+ pre{
+ margin: 0;
+ width: 100%;
+ word-break: break-all;
+ white-space: pre-wrap;
+ white-space: -moz-pre-wrap;
+ white-space: -pre-wrap;
+ white-space: -o-pre-wrap;
+ word-wrap: break-word;
+ }
+
+
+ .btn-round{
+ padding: 15px 2px;
+ }
+</style>
+
+<template>
+ <div>
+ <div class="warp">
+ <section class="header">
+ <h1>{{ $t('transfer.confirmTransaction') }}</h1>
+ </section>
+
+ <section v-if="dataReady">
+ <div class="tab-group">
+ <a :class="{'color-black font-bold': tab === 'details'}" v-on:click="tab = 'details'">{{ $t('transfer.detail')
+ }}</a>
+ <a :class="{'color-black font-bold': tab === 'inout'}" v-on:click="tab = 'inout'">{{ $t('transfer.requestDetail')
+ }}</a>
+ </div>
+
+ <div v-if="tab ==='details'" class="content">
+ <div class="info">
+ <div class="row">
+ <div class="col">
+ <img class="logo" src="@/assets/logo.png" alt="">
+ </div>
+ <div class="col value">
+ <div v-if="currentWallet && currentWallet.alias" class="wallet color-black">{{currentWallet.alias}}</div>
+ <div>{{shortAddress}}</div>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col">
+ <i class="iconfont icon_arrow_2"></i>
+ </div>
+ <div class="col divider"></div>
+ </div>
+
+ <div class="row">
+ <div class="col">
+ <img v-if="prompt.domain && domainsMeta[prompt.domain] && domainsMeta[prompt.domain].icon" class="logo"
+ :src="domainsMeta[prompt.domain].icon" alt="">
+ <div v-else-if="initial" class="logo">
+ {{initial}}
+ </div>
+ </div>
+
+ <div class="col value">
+ <span class="color-black"
+ v-if="prompt.domain && domainsMeta[prompt.domain] && domainsMeta[prompt.domain].title ">{{domainsMeta[prompt.domain].title }}</span>
+ <span class="color-black" v-else-if="prompt.domain ">{{prompt.domain }}</span>
+
+ <div v-if="transaction.to">{{short(transaction.to)}}</div>
+ </div>
+ </div>
+ </div>
+
+ <div v-if="prompt.data && prompt.data.type ==='transfer'" class="amount-list">
+ <div>{{ $t('transfer.amount') }}</div>
+ <div class="color-black font-bold">{{transaction.amount}}<span class="uint uppercase">{{unit || short(transaction.asset) }}</span>
+ </div>
+ </div>
+ <div v-else v-for="(amountInput, index) in transaction.amounts" :key="index" class="amount-list">
+ <div>{{index ==0 && $t('transfer.amount') }}</div>
+ <div class="color-black font-bold">{{amountInput.amount}}<span class="uint uppercase">{{amountInput.alias || short(amountInput.asset) }}</span>
+ </div>
+ </div>
+
+ <div v-if="transaction.fee" class="amount-list">
+ <div>{{ $t('transfer.fee') }}</div>
+ <div class="color-black font-bold">{{transaction.fee}}<span class="uint">BTM</span></div>
+ </div>
+
+ </div>
+ <div v-if="tab ==='inout'" class="content content-black">
+ <pre>{{detail}}</pre>
+ </div>
+
+ <div class="form">
+ <div class="form-item">
+ <div class="form-item-content">
+ <input type="password" :placeholder="$t('transfer.password')" v-model="password" ref="password" autofocus>
+ </div>
+ </div>
+ </div>
+ <div>
+ <div class="btn btn-primary btn-round float-right" @click="transfer"><i class="iconfont icon-right-arrow"></i></div>
+ </div>
+
+ </section>
+ <section v-else>
+ loading...
+
+ </section>
+
+ </div>
+ <Footer/>
+ </div>
+</template>
+
+<script>
+ import transaction from "@/models/transaction";
+ import getLang from "@/assets/language/sdk";
+ import {apis} from '@/utils/BrowserApis';
+ import NotificationService from '../../services/NotificationService'
+ import {mapActions, mapGetters, mapState} from 'vuex'
+ import _ from 'lodash';
+ import account from "@/models/account";
+ import add from "@/utils/address";
+
+ export default {
+ add,
+ data() {
+ return {
+ dataReady: false,
+ transaction: {
+ confirmations: 1,
+ },
+ unit:null,
+ password: '',
+ prompt: '',
+ tab: 'details'
+ };
+ },
+ computed: {
+ initial() {
+ if (this.prompt && this.prompt.data && this.prompt.data.title) {
+ return this.prompt.data.title.substring(0, 1)
+ } else if (this.prompt && this.prompt.domain) {
+ return this.prompt.domain.substring(0, 1)
+ }
+ },
+ address: function () {
+ if (this.netType === 'vapor') {
+ return this.currentAccount.vpAddress
+ } else {
+ return this.currentAccount.address
+ }
+ },
+ shortAddress: function () {
+ if(this.prompt.data && this.prompt.data.type ==='transfer') {
+ return add.short(this.transaction.from);
+ }else{
+ if (this.netType === 'vapor') {
+ return add.short(this.currentAccount.vpAddress);
+ } else {
+ return add.short(this.currentAccount.address);
+ }
+ }
+ },
+ detail(){
+ return JSON.stringify(this.transaction, null, 2);
+ },
+ currentWallet(){
+ if(this.prompt.data && this.prompt.data.type ==='transfer'){
+ return this.bytom.keychain.findByAddress(this.transaction.from);
+ }else{
+ return this.currentAccount
+ }
+ },
+ ...mapState([
+ 'bytom'
+ ]),
+ ...mapGetters([
+ 'currentAccount',
+ 'net',
+ 'netType',
+ 'domainsMeta'
+ ])
+ },
+ watch: {},
+ methods: {
+ short(address){
+ return add.short(address)
+ },
+ transfer: function () {
+ if(!this.password){
+ this.$toast.error(
+ this.$t('error.BTM0008')
+ );
+ this.$refs.password.focus();
+ return;
+ }
+ let loader = this.$loading.show({
+ // Optional parameters
+ container: null,
+ canCancel: true,
+ onCancel: this.onCancel
+ });
+
+ if(this.prompt.data.type ==='advTransfer'){
+ transaction.buildTransaction(this.address, this.transaction.input, this.transaction.output, this.transaction.fee, this.transaction.confirmations).then(async (result) => {
+
+ let arrayData
+ if (this.transaction.args) {
+ arrayData = await transaction.convertArgument(this.transaction.args)
+ }
+
+ return transaction.advancedTransfer(this.address, result[0], this.password, arrayData, this)
+ .then((resp) => {
+ loader.hide();
+ this.prompt.responder(resp);
+ this.$toast.success(
+ this.$t("transfer.success")
+ );
+ NotificationService.close();
+ })
+ .catch(error => {
+ throw error
+ });
+ }).catch(error => {
+ loader.hide();
+
+ this.$toast.error(
+ getLang(error.message) || error.message || error
+ );
+ });
+ } else if(this.prompt.data.type ==='transfer'){
+ transaction.transfer(this.transaction, this.password, this.address, this).then(result => {
+ loader.hide();
+ NotificationService.close();
+
+ }).catch(error => {
+ loader.hide();
+ this.$toast.error(
+ getLang(error.message) || error.message || error
+ );
+ });
+
+ }
+ else{
+ loader.hide();
+ this.$toast.error(
+ 'Unknown popup type'
+ );
+ }
+
+ },
+ queryAsset: function (assetID) {
+ return transaction.asset(assetID)
+ }
+ }, mounted() {
+ this.prompt = window.data || apis.extension.getBackgroundPage().notification || null;
+ console.log(this.prompt)
+
+ const data = this.prompt.data
+ if (data !== undefined) {
+ switch(data.type){
+ case "advTransfer":{
+ const inout = data
+ if (inout.input !== undefined) {
+ this.transaction.input = inout.input
+ }
+ if (inout.output !== undefined) {
+ this.transaction.output = inout.output
+ }
+ if (inout.args !== undefined) {
+ this.transaction.args = inout.args
+ }
+ if (inout.gas !== undefined) {
+ this.transaction.fee = inout.gas
+ }
+ if (inout.confirmations !== undefined) {
+ this.transaction.confirmations = inout.confirmations
+ }
+
+ const array = inout.input.filter(action => action.type === 'spend_wallet')
+
+ if (array.length > 0) {
+ account.setupNet(`${this.net}${this.netType}`)
+ const promise =
+ _(array)
+ .groupBy('asset')
+ .map((objs, key) => {
+ return this.queryAsset(key).then(resp => {
+ return {
+ 'asset': key,
+ 'alias': resp.symbol,
+ 'amount': _.sumBy(objs, 'amount')
+ }
+ })
+ })
+
+ let that = this;
+ Promise.all(promise).then(function (output) {
+ that.transaction.amounts = output
+ this.dataReady = true
+ }).catch(()=>{
+ this.dataReady = true
+ })
+
+ }
+ break;
+ }
+ case "transfer":{
+ if (data.from != undefined) {
+ this.transaction.from = data.from
+ }
+ if (data.asset != undefined) {
+ this.transaction.asset= data.asset
+ }
+ if (data.to != undefined) {
+ this.transaction.to = data.to
+ }
+ if (data.amount != undefined) {
+ this.transaction.amount = data.amount
+ }
+
+ if(data.confirmations != undefined) {
+ this.transaction.confirmations = data.confirmations
+ }
+
+ const asset_amounts ={}
+ asset_amounts[data.asset] = data.amount
+
+ transaction.estimateFee( data.from, asset_amounts).then( (resp) =>{
+ this.transaction.fee = resp.fee
+ this.queryAsset(data.asset).then(resp => {
+ this.unit = resp.symbol
+ this.dataReady = true
+ }).catch((e)=>{
+ throw e
+ })
+
+ }).catch(()=>{
+ this.dataReady = true
+ })
+ break;
+ }
+ }
+ }
+ }
+ };
+</script>