OSDN Git Service

update the dapp development api
authorZhiting Lin <zlin035@uottawa.ca>
Wed, 8 May 2019 05:48:49 +0000 (13:48 +0800)
committerZhiting Lin <zlin035@uottawa.ca>
Wed, 8 May 2019 05:48:49 +0000 (13:48 +0800)
src/background.js
src/content.js
src/dapp.js
src/messages/types.js
src/models/account.js
src/models/transaction.js
src/utils/errors/Error.js [new file with mode: 0644]
src/utils/errors/ErrorTypes.js [new file with mode: 0644]
src/views/sendTransaction/advancedTransfer.vue
src/views/sendTransaction/transfer.vue

index 8c575e7..c685b58 100644 (file)
@@ -2,6 +2,7 @@ import { LocalStream } from 'extension-streams'
 import InternalMessage from '@/messages/internal'
 import * as MsgTypes from './messages/types'
 
+import Error from './utils/errors/Error'
 import accountAction from "@/models/account";
 import bytom from "@/models/bytom";
 
@@ -9,7 +10,6 @@ export default class Background {
   constructor() {
     this.setupInternalMessaging()
     this.setupBytom()
-    window.bytomAPI = bytom
   }
 
   setupBytom(){
@@ -43,6 +43,15 @@ export default class Background {
       case MsgTypes.SEND:
         this.send(sendResponse, message.payload)
         break
+      case MsgTypes.REQUEST_CURRENT_ACCOUNT:
+        this.requestCurrentAccount(sendResponse)
+        break
+      case MsgTypes.REQUEST_CURRENT_NETWORK:
+        this.requestCurrentNetwork(sendResponse)
+        break
+      case MsgTypes.REQUEST_ACCOUNT_LIST:
+        this.requestAccountList(sendResponse)
+        break
     }
   }
 
@@ -52,7 +61,27 @@ export default class Background {
     requestBody.type = "popup"
     var queryString = new URLSearchParams(requestBody).toString()
     console.log(promptURL, queryString)
-    chrome.windows.create(
+    payload.asset
+
+    if(requestBody.from === undefined){
+      sendResponse(Error.typeMissed('from'));
+      return false;
+    }
+    if(requestBody.to === undefined){
+      sendResponse(Error.typeMissed('to'));
+      return false;
+    }
+    if(requestBody.asset === undefined){
+      sendResponse(Error.typeMissed('asset'));
+      return false;
+    }
+    if(requestBody.amount === undefined){
+      sendResponse(Error.typeMissed('amount'));
+      return false;
+    }
+
+
+      chrome.windows.create(
       {
         url: `${promptURL}#transfer?${queryString}`,
         type: 'popup',
@@ -66,15 +95,21 @@ export default class Background {
           if(sender.tab.windowId === window.id){
             switch (request.method){
               case 'transfer':
-                sendResponse(request);
-                break
+                if (request.action === 'success'){
+                  sendResponse(request.message.result.data);
+                  return true;
+                } else if (request.action === 'reject'){
+                  sendResponse(request.message);
+                  return false;
+                }
             }
           }
         });
 
         chrome.windows.onRemoved.addListener(function(windowId){
           if(windowId === window.id) {
-            sendResponse({method:'transfer',action:'reject'})
+            sendResponse(Error.promptClosedWithoutAction());
+            return false;
           }
         });
       }
@@ -85,6 +120,23 @@ export default class Background {
     var promptURL = chrome.extension.getURL('pages/prompt.html')
     var queryString = 'object='+JSON.stringify(payload)
     console.log(promptURL, queryString)
+
+    if(payload.input === undefined){
+      sendResponse(Error.typeMissed('input'));
+      return false;
+    }
+    if(payload.output === undefined){
+      sendResponse(Error.typeMissed('output'));
+      return false;
+    }
+    if(payload.gas === undefined){
+      sendResponse(Error.typeMissed('gas'));
+      return false;
+    }
+    if(payload.args === undefined){
+      sendResponse(Error.typeMissed('args'));
+      return false;
+    }
     chrome.windows.create(
       {
         url: `${promptURL}#advancedTransfer?${queryString}`,
@@ -99,39 +151,68 @@ export default class Background {
           if(sender.tab.windowId === window.id){
             switch (request.method){
               case 'advanced-transfer':
-                sendResponse(request);
-                break
+                if (request.action === 'success'){
+                  sendResponse(request.message.result.data);
+                  return true;
+                } else if (request.action === 'reject'){
+                  sendResponse(request.message);
+                  return false;
+                }
             }
           }
         });
         chrome.windows.onRemoved.addListener(function(windowId){
           if(windowId === window.id) {
-            sendResponse({method:'advanced-transfer',action:'reject'})
+            sendResponse(Error.promptClosedWithoutAction());
+            return false;
           }
         });
       }
     )
   }
 
+  requestCurrentAccount(sendResponse){
+    const currentAccount = JSON.parse(localStorage.currentAccount)
+    delete(currentAccount['label'])
+    delete(currentAccount['net'])
+    currentAccount['accountId'] = currentAccount['guid']
+    delete(currentAccount['guid'])
+    currentAccount['balance'] = {
+      'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' : {
+        amount: currentAccount['balance']
+      }
+    }
+
+    sendResponse(currentAccount)
+  }
+
+  requestCurrentNetwork(sendResponse){
+    sendResponse(localStorage.bytomNet)
+  }
+
+  requestAccountList(sendResponse){
+    accountAction.list().then(resp=>{
+      const accountList = resp
+      accountList.forEach(function(account) {
+        delete(account['label'])
+        delete(account['net'])
+        account['accountId'] = account['guid']
+        delete(account['guid'])
+        account['balance'] = {
+          'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff': {
+            amount: account['balance']
+          }
+        }
+      })
+      sendResponse(accountList)
+    })
+  }
+
   send(sendResponse, payload) {
     const action = payload.action
-    const body = payload.body
     if(action){
       let promise
       switch (action){
-        case 'balance':
-          const id = body.id
-          const guid = body.guid
-          promise = accountAction.balance(guid, id)
-          break
-        case 'currentAccount':
-          const account = JSON.parse(localStorage.currentAccount)
-          sendResponse(account)
-          break
-        case 'currentNetwork':
-          const network = JSON.parse(localStorage.bytomNet)
-          sendResponse(network)
-          break
         case 'listAllAccount':
           promise = accountAction.list()
           break
index 62ffe61..ccae4f4 100644 (file)
@@ -28,14 +28,14 @@ class Content {
     stream = new EncryptedStream(EventNames.BYTOM, IdGenerator.text(256))
     stream.listenWith(msg => this.contentListener(msg))
 
-    stream.onSync(() => {
-      const version = this.getVersion()
-      // const version = await this.getVersion();
-      // const identity = await this.identityFromPermissions();
+    stream.onSync(async () => {
+      const defaultAccount = await this.getDefaultAccount();
+      const net = await this.getDefaultNetwork();
+      const accountList = await this.getAccountList();
 
-      // Pushing an instance of Scatterdapp to the web application
+      // Pushing an instance of Bytomdapp to the web application
       stream.send(
-        NetworkMessage.payload(MsgTypes.PUSH_BYTOM, {}),
+        NetworkMessage.payload(MsgTypes.PUSH_BYTOM, {defaultAccount, net, accountList}),
         EventNames.INJECT
       )
 
@@ -70,6 +70,21 @@ class Content {
 
   getVersion() {}
 
+  getDefaultAccount(){
+    return InternalMessage.signal(MsgTypes.REQUEST_CURRENT_ACCOUNT)
+      .send()
+  }
+
+  getDefaultNetwork(){
+    return InternalMessage.signal(MsgTypes.REQUEST_CURRENT_NETWORK)
+      .send()
+  }
+
+  getAccountList(){
+    return InternalMessage.signal(MsgTypes.REQUEST_ACCOUNT_LIST)
+      .send()
+  }
+
   respond(message, payload) {
     if (!isReady) return
 
index d703ef0..6a93b68 100644 (file)
@@ -54,20 +54,6 @@ const _send = (_type, _payload) => {
   })
 }
 
-/***
- * Turns message sending between the application
- * and the content script into async promises
- * @param _type
- * @param _payload
- */
-const _sendSync = (_type, _payload) => {
-  return new Promise((resolve, reject) => {
-    let id = IdGenerator.numeric(24)
-    let message = new NetworkMessage(_type, _payload, id)
-    resolvers.push(new DanglingResolver(id, resolve, reject))
-    stream.send(message, EventNames.BYTOM)
-  })
-}
 
 export default class Bytomdapp {
   constructor(_stream, _options) {
@@ -75,33 +61,18 @@ export default class Bytomdapp {
     // this.useIdentity(_options.identity)
     stream = _stream
     resolvers = []
-
-    // setupSigProviders(this)
+    this.default_account = _options.defaultAccount
+    this.net = _options.net
+    this.accounts = _options.accountList
 
     _subscribe()
   }
 
-  transfer(to, amount) {
-    return _send(MsgTypes.TRANSFER, {
-      to: to,
-      amount: amount
-    })
-  }
-
-  advancedTransfer(input, output, gas, args, confirmations) {
-    return _send(MsgTypes.ADVTRANSFER, {
-      input,
-      output,
-      gas,
-      args,
-      confirmations
-    })
+  send_transaction(params) {
+    return _send(MsgTypes.TRANSFER, params)
   }
 
-  request(action, body=''){
-    return _send(MsgTypes.SEND,{
-      action,
-      body
-    })
+  send_advanced_transaction(params) {
+    return _send(MsgTypes.ADVTRANSFER, params)
   }
 }
index 30ccd3f..6319bfa 100644 (file)
@@ -5,3 +5,8 @@ export const AUTHENTICATE = 'authenticate'
 export const TRANSFER = 'transfer'
 export const ADVTRANSFER = 'advTransfer'
 export const SEND = 'send'
+
+
+export const REQUEST_CURRENT_ACCOUNT = 'defaultAccount';
+export const REQUEST_CURRENT_NETWORK = 'currentNetwork';
+export const REQUEST_ACCOUNT_LIST = 'accountList';
index dcce2b1..f446c61 100644 (file)
@@ -62,12 +62,12 @@ account.list = function() {
     bytom.accounts
       .listAccountUseServer()
       .then(accounts => {
-        accounts.forEach(account => {
-          this.balance(account.guid).then(balance => {
-            account.balance = balance
-          })
+        Promise.all(accounts.map(async (account) => {
+          const balance = await this.balance(account.guid)
+          account.balance = balance
+        })).then(()=>{
+          resolve(accounts)
         })
-        resolve(accounts)
       })
       .catch(error => {
         reject(error)
index 6f23d5c..90a18cc 100644 (file)
@@ -27,10 +27,10 @@ transaction.asset = function(asset_id) {
   return bytom.query.asset(asset_id);
 };
 
-transaction.build = function(guid, to, asset, amount, fee) {
+transaction.build = function(guid, to, asset, amount, fee, confirmations) {
   let retPromise = new Promise((resolve, reject) => {
     bytom.transaction
-      .buildPayment(guid, to, asset, Number(amount * 100000000))
+      .buildPayment(guid, to, asset, Number(amount), Number(fee*100000000), confirmations)
       .then(res => {
         resolve(res);
       })
diff --git a/src/utils/errors/Error.js b/src/utils/errors/Error.js
new file mode 100644 (file)
index 0000000..1c69768
--- /dev/null
@@ -0,0 +1,57 @@
+import * as ErrorTypes from './ErrorTypes'
+
+export const ErrorCodes = {
+  NO_SIGNATURE:402,
+  FORBIDDEN:403,
+  TIMED_OUT:408,
+  LOCKED:423,
+  TOO_MANY_REQUESTS:429,
+  TYPE_MISSED:411
+};
+
+export default class Error {
+
+  constructor(_type, _message, _code = ErrorCodes.LOCKED){
+    this.type = _type;
+    this.message = _message;
+    this.code = _code;
+    this.isError = true;
+  }
+
+  static locked(){
+    return new Error(ErrorTypes.LOCKED, "The user's Scatter is locked. They have been notified and should unlock before continuing.")
+  }
+
+  static promptClosedWithoutAction(){
+    return new Error(ErrorTypes.PROMPT_CLOSED, "The user closed the prompt without any action.", ErrorCodes.TIMED_OUT)
+  }
+
+  static signatureError(_type, _message){
+    return new Error(_type, _message, ErrorCodes.NO_SIGNATURE)
+  }
+
+  static typeMissed(_type){
+    return new Error(ErrorTypes.TYPE_MISSED, `Parameter '${_type}' is missing, please add the Parameter '${_type}'.`)
+  }
+
+  static identityMissing(){
+    return this.signatureError("identity_missing", "Identity no longer exists on the user's keychain");
+  }
+
+  static signatureAccountMissing(){
+    return this.signatureError("account_missing", "Missing required accounts, repull the identity");
+  }
+
+  static malformedRequiredFields(){
+    return this.signatureError("malformed_requirements", "The requiredFields you passed in were malformed");
+  }
+
+  static usedKeyProvider(){
+    return new Error(
+      ErrorTypes.MALICIOUS,
+      "Do not use a `keyProvider` with a Scatter. Use a `signProvider` and return only signatures to this object. A malicious person could retrieve your keys otherwise.",
+      ErrorCodes.NO_SIGNATURE
+    )
+  }
+
+}
diff --git a/src/utils/errors/ErrorTypes.js b/src/utils/errors/ErrorTypes.js
new file mode 100644 (file)
index 0000000..63c9725
--- /dev/null
@@ -0,0 +1,4 @@
+export const MALICIOUS = 'malicious';
+export const LOCKED = 'locked';
+export const PROMPT_CLOSED = 'prompt_closed';
+export const TYPE_MISSED = 'type_missed';
index 7dc31a3..b5d18c1 100644 (file)
@@ -149,7 +149,7 @@ export default {
                 output: "",
                 args: "",
                 fee: "",
-                confirmations:"",
+                confirmations:1,
                 amounts: []
             },
             password:''
index a33e307..ab474d6 100644 (file)
@@ -152,8 +152,9 @@ export default {
                 to: "",
                 asset: ASSET_BTM,
                 amount: "",
-                fee: "",
-                cost: ""
+                fee: null,
+                cost: "",
+                confirmations: 1
             }
         };
     },
@@ -219,9 +220,11 @@ export default {
                 canCancel: true,
                 onCancel: this.onCancel
             });
-            transaction.build(this.account.guid, this.transaction.to, this.transaction.asset, this.transaction.amount, this.transaction.fee).then(ret => {
+            transaction.build(this.account.guid, this.transaction.to, this.transaction.asset, this.transaction.amount*100000000, this.transaction.fee, this.transaction.confirmations).then(ret => {
                 loader.hide();
-                this.transaction.fee = Number(ret.result.data.fee / 100000000);
+                if(!this.transaction.fee){
+                    this.transaction.fee = Number(ret.result.data.fee / 100000000);
+                }
                 this.$router.push({ name: 'transfer-confirm', params: { account: this.account, transaction: this.transaction, rawData: ret.result.data, type: this.$route.query.type } })
             }).catch(error => {
                 loader.hide();
@@ -235,13 +238,32 @@ export default {
             this.account = this.$route.params.account;
         }
 
-        if (this.$route.query.to != undefined) {
-            this.transaction.to = this.$route.query.to
-        }
-        if (this.$route.query.amount != undefined) {
-            this.transaction.amount = this.$route.query.amount
+        //detect injection
+        if(this.$route.query.type === 'popup'){
+          if (this.$route.query.from != undefined) {
+              this.guid = this.$route.query.from
+          }else{
+              this.account = JSON.parse(localStorage.currentAccount);
+          }
+
+          if (this.$route.query.asset != undefined) {
+              this.transaction.asset= this.$route.query.asset
+          }
+          if (this.$route.query.to != undefined) {
+              this.transaction.to = this.$route.query.to
+          }
+          if (this.$route.query.amount != undefined) {
+              this.transaction.amount = this.$route.query.amount /100000000
+          }
+          if (this.$route.query.gas != undefined) {
+              this.transaction.fee = this.$route.query.gas /100000000
+          }
+          if(this.$route.query.confirmations != undefined) {
+              this.transaction.confirmations = this.$route.query.confirmations
+          }
         }
 
+
         account.setupNet(localStorage.bytomNet);
         account.list().then(accounts => {
             this.accounts = accounts;