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";
constructor() {
this.setupInternalMessaging()
this.setupBytom()
- window.bytomAPI = bytom
}
setupBytom(){
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
}
}
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',
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;
}
});
}
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}`,
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
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
)
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
})
}
-/***
- * 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) {
// 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)
}
}
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';
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)
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);
})
--- /dev/null
+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
+ )
+ }
+
+}
--- /dev/null
+export const MALICIOUS = 'malicious';
+export const LOCKED = 'locked';
+export const PROMPT_CLOSED = 'prompt_closed';
+export const TYPE_MISSED = 'type_missed';
output: "",
args: "",
fee: "",
- confirmations:"",
+ confirmations:1,
amounts: []
},
password:''
to: "",
asset: ASSET_BTM,
amount: "",
- fee: "",
- cost: ""
+ fee: null,
+ cost: "",
+ confirmations: 1
}
};
},
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();
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;