Merge pull request #359 from status-im/feature/#218

Rework transactions sending
This commit is contained in:
Roman Volosovskyi 2016-10-19 09:40:13 +03:00 committed by GitHub
commit 8011213ee9
20 changed files with 348 additions and 159 deletions

View File

@ -14,5 +14,5 @@ android {
dependencies {
compile 'com.facebook.react:react-native:+'
compile(group: 'status-im', name: 'status-go', version: '0.1.1', ext: 'aar')
compile(group: 'status-im', name: 'status-go', version: 'test-jcp6', ext: 'aar')
}

View File

@ -5,12 +5,15 @@ import android.content.Intent;
import android.os.*;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.concurrent.Callable;
import java.lang.ref.WeakReference;
import com.github.status_im.status_go.cmd.Statusgo;
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class StatusService extends Service {
@ -19,6 +22,8 @@ public class StatusService extends Service {
private static boolean isNodeInitialized = false;
private final Handler handler = new Handler();
private ExecutorService executor = null;
private static String dataFolder;
private static Messenger applicationMessenger = null;
@ -74,6 +79,9 @@ public class StatusService extends Service {
public void onDestroy() {
super.onDestroy();
if (executor != null) {
executor.shutdownNow();
}
//TODO: stop geth
stopNode(null);
//isNodeInitialized = false;
@ -83,6 +91,9 @@ public class StatusService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (executor == null) {
executor = Executors.newCachedThreadPool();
}
return Service.START_STICKY;
}
@ -155,7 +166,11 @@ public class StatusService extends Service {
Statusgo.StartNode(dataFolder);
Log.d(TAG, "Geth node started");
Log.w(TAG, "adding peer");
Statusgo.AddPeer("enode://e15869ba08a25e49be7568b951e15af5d77a472c8e4104a14a4951f99936d65f91240d5b5f23674aee44f1ac09d8adfc6a9bff75cd8c2df73a26442f313f2da4@162.243.63.248:30303");
Statusgo.AddPeer("enode://efe4e6899e05237180c0970aedb81cb5aecf5b200779c7c9e1f955783e8299b364c0b981c03f4c36ad5328ef972b417afde260bbf2c5a8db37ba7f5738033952@198.199.105.122:30303");
Statusgo.AddPeer("enode://5a5839435f48d1e3f2f907e4582f0a134e0b7857afe507073978ca32cf09ea54989dac433605047d0bc4cd19a8c80affac6876069014283aa7c7bb4954d0e623@95.85.40.211:30303");
Statusgo.AddPeer("enode://2f05d430b4cb1c0e2a0772d48da3a034f1b596ea7163ab80d3404802d10b7d55bde323897c2be0d36026181e1a68510ea1f42a646ef9494c27e61f61e4088b7d@188.166.229.119:30303");
Statusgo.AddPeer("enode://ad61a21f83f12b0ca494611650f5e4b6427784e7c62514dcb729a3d65106de6f12836813acf39bdc35c12ecfd0e230723678109fd4e7091ce389697bd7da39b4@139.59.212.114:30303");
isNodeInitialized = true;
}
createAndSendReply(message, StatusMessages.MSG_START_NODE, null);
@ -256,12 +271,45 @@ public class StatusService extends Service {
String chatId = data.getString("chatId");
String path = data.getString("path");
String params = data.getString("params");
String callbackIdentifier = data.getString(StatusConnector.CALLBACK_IDENTIFIER);
Log.d(TAG, "Before StatusGo.Call");
Callable<String> callable = new JailRequest(message.replyTo, chatId, path, params, callbackIdentifier);
executor.submit(callable);
}
public class JailRequest implements Callable<String> {
String chatId;
String path;
String params;
String callbackIdentifier;
Messenger messenger;
JailRequest(Messenger messenger, String chatId, String path, String params, String callbackIdentifier) {
this.messenger = messenger;
this.chatId = chatId;
this.path = path;
this.params = params;
this.callbackIdentifier = callbackIdentifier;
}
public String call() throws Exception {
Log.d(TAG, "StatusGo.Call");
String result = Statusgo.Call(chatId, path, params);
Bundle replyData = new Bundle();
replyData.putString("data", result);
createAndSendReply(message, StatusMessages.MSG_JAIL_CALL, replyData);
Message replyMessage = Message.obtain(null, StatusMessages.MSG_JAIL_CALL, 0, 0, null);
Log.d(TAG, "Callback identifier: " + callbackIdentifier);
replyData.putString(StatusConnector.CALLBACK_IDENTIFIER, callbackIdentifier);
replyMessage.setData(replyData);
sendReply(messenger, replyMessage);
return result;
}
}
public static boolean isNodeInitialized() {

View File

@ -1,12 +1,22 @@
#import "RCTStatus.h"
#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
#import <Statusgo/Statusgo.h>
static bool isStatusInitialized;
static RCTBridge *bridge;
@implementation Status{
}
-(RCTBridge *)bridge
{
return bridge;
}
-(void)setBridge:(RCTBridge *)newBridge
{
bridge = newBridge;
}
RCT_EXPORT_MODULE();
@ -41,8 +51,12 @@ RCT_EXPORT_METHOD(callJail:(NSString *)chatId
#if DEBUG
NSLog(@"CallJail() method called");
#endif
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
char * result = Call((char *) [chatId UTF8String], (char *) [path UTF8String], (char *) [params UTF8String]);
dispatch_async( dispatch_get_main_queue(), ^{
callback(@[[NSString stringWithUTF8String: result]]);
});
});
}
////////////////////////////////////////////////////////////////////
@ -69,7 +83,8 @@ RCT_EXPORT_METHOD(startNode:(RCTResponseSenderBlock)onResultCallback) {
}else
NSLog(@"folderName: %@", folderName);
NSString *peer = @"enode://e15869ba08a25e49be7568b951e15af5d77a472c8e4104a14a4951f99936d65f91240d5b5f23674aee44f1ac09d8adfc6a9bff75cd8c2df73a26442f313f2da4@162.243.63.248:30303";
NSString *peer1 = @"enode://e15869ba08a25e49be7568b951e15af5d77a472c8e4104a14a4951f99936d65f91240d5b5f23674aee44f1ac09d8adfc6a9bff75cd8c2df73a26442f313f2da4@162.243.63.248:30303";
NSString *peer2 = @"enode://ad61a21f83f12b0ca494611650f5e4b6427784e7c62514dcb729a3d65106de6f12836813acf39bdc35c12ecfd0e230723678109fd4e7091ce389697bd7da39b4@139.59.212.114:30303";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^(void) {
StartNode((char *) [folderName.path UTF8String]);
@ -77,7 +92,8 @@ RCT_EXPORT_METHOD(startNode:(RCTResponseSenderBlock)onResultCallback) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)),
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^(void) {
AddPeer((char *) [peer UTF8String]);
AddPeer((char *) [peer1 UTF8String]);
AddPeer((char *) [peer2 UTF8String]);
});
onResultCallback(@[[NSNull null]]);
return;
@ -161,4 +177,15 @@ RCT_EXPORT_METHOD(setSoftInputMode: (NSInteger) i) {
#endif
}
+ (void)signalEvent:(char *) signal
{
NSString *sig = [NSString stringWithUTF8String:signal];
#if DEBUG
NSLog(@"SignalEvent");
NSLog(sig);
#endif
[bridge.eventDispatcher sendAppEventWithName:@"gethEvent"
body:@{@"jsonEvent": sig}];
}
@end

View File

@ -25,7 +25,7 @@
<artifactItem>
<groupId>status-im</groupId>
<artifactId>status-go-ios</artifactId>
<version>0.1.2</version>
<version>ios-signals</version>
<type>zip</type>
<overWrite>true</overWrite>
<outputDirectory>./</outputDirectory>

View File

@ -3,7 +3,7 @@
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.9.0-alpha12"]
:dependencies [[org.clojure/clojure "1.9.0-alpha13"]
[org.clojure/clojurescript "1.9.229"]
[reagent "0.5.1" :exclusions [cljsjs/react]]
[re-frame "0.7.0"]

View File

@ -62,8 +62,8 @@ status.command({
}]
});
function validateBalance(params) {
if(!params.value){
function validateBalance(params, context) {
if (!params.amount) {
return {
errors: [
status.components.validationMessage(
@ -75,19 +75,19 @@ function validateBalance(params) {
}
try {
var val = web3.toWei(params.value, "ether");
var val = web3.toWei(params.amount, "ether");
} catch (err) {
return {
errors: [
status.components.validationMessage(
"Amount",
"Amount is not valid number"//err.message
"Amount is not valid number"
)
]
};
}
var balance = web3.eth.getBalance(params.command.address);
var balance = web3.eth.getBalance(context.from);
if (bn(val).greaterThan(bn(balance))) {
return {
errors: [
@ -102,15 +102,18 @@ function validateBalance(params) {
}
}
function sendTransaction(params) {
function sendTransaction(params, context) {
var data = {
from: params.command.from,
to: params.command.to,
value: web3.toWei(params.value, "ether")
from: context.from,
to: context.to,
value: web3.toWei(params.amount, "ether")
};
var hash = web3.eth.sendTransaction(data);
return {"transaction-hash": hash};
try {
return web3.eth.sendTransaction(data);
} catch (err) {
return {error: err};
}
}
status.command({
@ -124,7 +127,7 @@ status.command({
preview: function (params) {
return status.components.text(
{},
params.value + " ETH"
params.amount + " ETH"
);
},
handler: sendTransaction,

View File

@ -1,7 +1,8 @@
var _status_catalog = {
commands: {},
responses: {}
};
},
status = {};
function Command() {
}
@ -44,10 +45,25 @@ Response.prototype.onReceiveResponse = function (handler) {
this.onReceive = handler;
};
var context = {}
function addContext(ns, key, value) {
context[ns][key] = value;
}
function call(pathStr, paramsStr) {
var params = JSON.parse(paramsStr),
path = JSON.parse(pathStr),
fn, res;
fn, callResult, message_id;
if (typeof params.context !== "undefined" &&
typeof params.context["message-id"] !== "undefined") {
message_id = params.context["message-id"];
} else {
message_id = null;
}
context[message_id] = {};
status.message_id = message_id;
fn = path.reduce(function (catalog, name) {
if (catalog && catalog[name]) {
@ -61,9 +77,13 @@ function call(pathStr, paramsStr) {
return null;
}
res = fn(params.parameters, params.context);
callResult = fn(params.parameters, params.context);
result = {
returned: callResult,
context: context[message_id]
};
return JSON.stringify(res);
return JSON.stringify(result);
}
function text(options, s) {

View File

@ -275,11 +275,13 @@
[{:keys [current-chat-id] :as db} [_ _ id]]
(let [chat-id (or id current-chat-id)
messages (get-in db [:chats chat-id :messages])
db' (assoc db :current-chat-id chat-id)]
db' (assoc db :current-chat-id chat-id)
commands-loaded? (get-in db [:chats chat-id :commands-loaded])]
(when (= current-chat-id wallet-chat-id)
(dispatch [:cancel-command]))
(dispatch [:load-requests! chat-id])
(dispatch [:load-commands! chat-id])
(when-not commands-loaded?
(dispatch [:load-commands! chat-id]))
(if (and (seq messages)
(not= (count messages) 1))
db'

View File

@ -91,7 +91,7 @@
(fn [_ [_ {:keys [chat-id handler]} {:keys [error result]}]]
;; todo handle error
(when-not error
(let [{:keys [errors validationHandler parameters]} result]
(let [{:keys [errors validationHandler parameters]} (:returned result)]
(cond errors
(dispatch [::add-validation-errors chat-id errors])
@ -128,6 +128,7 @@
:id (random/id)}]
(-> db
(commands/stage-command command-info)
(assoc-in [:command->chat (:id command-info)] chat-id)
(assoc :staged-command command-info)
(assoc-in [:disable-staging chat-id] true)))))
@ -225,7 +226,7 @@
(register-handler ::start-command-validation!
(u/side-effect!
(fn [db [_ {:keys [command-input chat-id] :as data}]]
(fn [db [_ {:keys [command-input chat-id address] :as data}]]
(let [command-input' (or command-input (commands/get-command-input db))
{:keys [parameter-idx params command]} command-input'
{:keys [name type]} command
@ -233,7 +234,8 @@
:params
(get parameter-idx)
:name)
context {:current-parameter current-parameter}
context {:current-parameter current-parameter
:from address}
path [(if (= :command type) :commands :responses)
name
:validator]

View File

@ -16,14 +16,16 @@
[taoensso.timbre :refer-macros [debug]]))
(defn prepare-command
[identity chat-id {:keys [preview preview-string params command to-message]}]
[identity chat-id
{:keys [id preview preview-string params command to-message handler-data]}]
(let [content {:command (command :name)
:params params}]
{:message-id (random/id)
{:message-id id
:from identity
:to chat-id
:timestamp (time/now-ms)
:content (assoc content :preview preview-string)
:content (assoc content :preview preview-string
:handler-data handler-data)
:content-type content-type-command
:outgoing true
:preview preview-string
@ -55,7 +57,9 @@
(fn [_ [_ {:keys [commands message] :as params}]]
(doseq [{:keys [command] :as message} commands]
(let [params' (assoc params :staged-command message)]
(if (:sending message)
(if (:sent-to-jail? message)
;; todo there could be other reasons for "long-running"
;; hanling of the command besides sendTransaction
(dispatch [:navigate-to :confirm])
(if (:has-handler command)
(dispatch [::invoke-command-handlers! params'])
@ -71,16 +75,18 @@
(register-handler :prepare-command!
(u/side-effect!
(fn [{:keys [current-public-key] :as db}
[_ {:keys [chat-id staged-command] :as params}]]
(let [command' (->> staged-command
[_ {:keys [chat-id staged-command handler-data] :as params}]]
(let [command' (->> (assoc staged-command :handler-data handler-data)
(prepare-command current-public-key chat-id)
(cu/check-author-direction db chat-id))]
(dispatch [::clear-command chat-id (:id staged-command)])
(dispatch [:clear-command chat-id (:id staged-command)])
(dispatch [::send-command! (assoc params :command command')])))))
(register-handler ::clear-command
(register-handler :clear-command
(fn [db [_ chat-id id]]
(update-in db [:chats chat-id :staged-commands] dissoc id)))
(if chat-id
(update-in db [:chats chat-id :staged-commands] dissoc id)
db)))
(register-handler ::send-command!
(u/side-effect!
@ -112,8 +118,9 @@
(register-handler ::invoke-command-handlers!
(u/side-effect!
(fn [db [_ {:keys [chat-id address staged-command] :as parameters}]]
(let [{:keys [command params]} staged-command
(fn [db [_ {:keys [chat-id address staged-command]
:as parameters}]]
(let [{:keys [id command params]} staged-command
{:keys [type name]} command
path [(if (= :command type) :commands :responses)
name
@ -121,12 +128,19 @@
to (get-in db [:contacts chat-id :address])
params {:parameters params
:context {:from address
:to to}}]
(status/call-jail chat-id
:to to
:message-id id}}]
(dispatch [::command-in-processing chat-id id])
(status/call-jail
chat-id
path
params
#(dispatch [:command-handler! chat-id parameters %]))))))
(register-handler ::command-in-processing
(fn [db [_ chat-id id]]
(assoc-in db [:chats chat-id :staged-commands id :sent-to-jail?] true)))
(register-handler ::prepare-message
(u/side-effect!
(fn [db [_ {:keys [chat-id identity message] :as params}]]

View File

@ -10,11 +10,6 @@
[status-im.constants :refer [console-chat-id]]
[taoensso.timbre :as log]))
(defn init-render-command!
[_ [chat-id command message-id data]]
(status/call-jail chat-id [command :render] data
#(dispatch [::render-command chat-id message-id %])))
(defn render-command
[db [chat-id message-id markup]]
(let [hiccup (generate-hiccup markup)]
@ -31,14 +26,24 @@
(def regular-events {})
(defn command-hadler!
[_ [chat-id {:keys [command] :as parameters} {:keys [result error]}]]
[_ [chat-id
{:keys [staged-command] :as parameters}
{:keys [result error]}]]
(let [{:keys [context returned]} result
{:keys [event params]
handler-error :error} returned]
(cond
handler-error
(log/debug :error-from-handler handler-error
:chat-id chat-id
:command staged-command)
result
(let [{:keys [event params transaction-hash]} result
command' (assoc command :handler-data result)
(let [{:keys [event params]} returned
command' (assoc staged-command :handler-data returned)
parameters' (assoc parameters :command command')]
(if transaction-hash
(dispatch [:wait-for-transaction transaction-hash parameters'])
(if (:eth_sendTransaction context)
(dispatch [:wait-for-transaction (:id staged-command) parameters'])
(let [events (if (= console-chat-id chat-id)
(merge regular-events console-events)
regular-events)
@ -46,13 +51,15 @@
(assoc parameters' :handler #(handler params command'))
parameters')]
(dispatch [:prepare-command! parameters'']))))
(not error)
(not (or error handler-error))
(dispatch [:prepare-command! parameters])
:else nil))
:else nil)))
(defn suggestions-handler!
[db [{:keys [chat-id]} {:keys [result]}]]
(let [{:keys [markup webViewUrl]} result
(let [{:keys [markup webViewUrl]} (:returned result)
hiccup (generate-hiccup markup)]
(-> db
(assoc-in [:suggestions chat-id] (generate-hiccup markup))
@ -68,12 +75,13 @@
(defn command-preview
[db [chat-id command-id {:keys [result]}]]
(if result
(let [result' (:returned result)]
(if result'
(let [path [:chats chat-id :staged-commands command-id]]
(update-in db path assoc
:preview (generate-hiccup result)
:preview-string (str result)))
db))
:preview (generate-hiccup result')
:preview-string (str result')))
db)))
(defn print-error-message! [message]
(fn [_ params]
@ -81,7 +89,6 @@
(show-popup "Error" (s/join "\n" [message params]))
(log/debug message params))))
(reg-handler :init-render-command! init-render-command!)
(reg-handler ::render-command render-command)
(reg-handler :command-handler!
@ -93,6 +100,8 @@
(after (print-error-message! "Error on param suggestions"))
(after (fn [_ [{:keys [command]}]]
(when (= :on-send (keyword (:suggestions-trigger command)))
#_(when (:webViewUrl (:returned result))
(dispatch [:set-soft-input-mode :pan]))
(r/dismiss-keyboard!))))]
suggestions-handler!)
(reg-handler :suggestions-event! (u/side-effect! suggestions-events-handler!))

View File

@ -35,6 +35,7 @@
(defn complete-transaction
[hash password callback]
(log/debug :complete-transaction (boolean status) hash password)
(when status
(.completeTransaction status hash password callback)))

View File

@ -102,6 +102,7 @@
(register-handler :signal-event
(u/side-effect!
(fn [_ [_ event-str]]
(log/debug :event-str event-str)
(let [{:keys [type event]} (t/json->clj event-str)]
(case type
"transaction.queued" (dispatch [:transaction-queued event])

View File

@ -15,6 +15,7 @@
[status-im.chat.screen :refer [chat]]
[status-im.accounts.login.screen :refer [login]]
[status-im.accounts.screen :refer [accounts]]
[status-im.transactions.screen :refer [confirm]]
[status-im.chats-list.screen :refer [chats-list]]
[status-im.new-group.screen :refer [new-group]]
[status-im.participants.views.add :refer [new-participants]]
@ -83,6 +84,7 @@
:profile-photo-capture profile-photo-capture
:accounts accounts
:login login
:confirm confirm
:my-profile my-profile)]
[component]))))})))

View File

@ -6,45 +6,62 @@
[status-im.utils.types :as t]
[status-im.components.status :as status]
cljsjs.web3
[clojure.string :as s]))
[clojure.string :as s]
[taoensso.timbre :as log]))
;; flow:
;; :accept-transactions
;; ↓
;; :transaction-completed
;; ↓
;; ::remove-transaction && [:set :wrong-password? false] <- on error
;; ::remove-transaction <- when transaction is
;; not from the jail
;; ::add-transactions-hash
;; && ::check-completed-transaction!
;; && :navigation-replace <- on success
(defmethod nav/preload-data! :confirm
[{:keys [transactions-queue] :as db} _]
(assoc db :transactions transactions-queue))
(defn on-unlock
[hashes password]
;; todo: add message about wrong password
(do
;(dispatch [:set :wrong-password? false])
(doseq [hash hashes]
[ids password previous-view-id]
(dispatch [:set :wrong-password? false])
(doseq [id ids]
(status/complete-transaction
hash
id
password
#(dispatch [:transaction-completed hash %])))
(dispatch [:navigate-back])))
;(dispatch [:set :wrong-password? true])
#(dispatch [:transaction-completed
{:id id
:response %
:previous-view-id previous-view-id}]))))
(register-handler :accept-transactions
(u/side-effect!
(fn [{:keys [transactions current-account-id]} [_ password]]
(let [hashes (keys transactions)]
(on-unlock hashes password)))))
(fn [{:keys [transactions navigation-stack]} [_ password]]
(let [ids (keys transactions)
previous-view-id (second navigation-stack)]
(on-unlock ids password previous-view-id)))))
(register-handler :deny-transactions
(u/side-effect!
(fn [{:keys [transactions]}]
(let [hashes (keys transactions)]
(dispatch [::remove-pending-messages hashes])
(dispatch [::remove-trqqansactions hashes])
(let [transactions' (vals transactions)
messages-ids (map :message-id transactions')
ids (map :id transactions')]
(dispatch [::remove-pending-messages messages-ids])
(dispatch [::remove-transactions ids])
(dispatch [:navigate-back])))))
(register-handler :deny-transaction
(u/side-effect!
(fn [_ [_ hash]]
(dispatch [::remove-pending-message hash])
(dispatch [::remove-transaction hash]))))
(fn [{:keys [transactions]} [_ id]]
(let [{:keys [message-id] :as transaction} (get transactions id)]
(when transaction
(dispatch [::remove-pending-message message-id])
(dispatch [::remove-transaction id]))))))
(register-handler ::remove-transactions
(fn [db [_ hashes]]
@ -58,55 +75,101 @@
(update :transactions dissoc hash)
(update :transactions-queue dissoc hash))))
(defn mark-command-as-pending [db chat-id id]
(let [path [:chats chat-id :staged-commands id]]
(if (get-in db path)
(update-in db path assoc :pending true)
db)))
(register-handler :wait-for-transaction
(fn [db [_ hash {:keys [chat-id command] :as params}]]
(after (fn [_ [_ message-id]]
(dispatch [::check-completed-transaction!
{:message-id message-id}])))
(fn [db [_ message-id {:keys [chat-id command] :as params}]]
(let [id (:id command)]
(-> db
(update-in [:chats chat-id :staged-commands id] assoc :pending true)
(assoc-in [:transaction-subscribers hash] params)))))
(mark-command-as-pending chat-id id)
(assoc-in [:transaction-subscribers message-id] params)))))
(defn remove-pending-message [db hash]
(let [{:keys [chat-id command]} (get-in db [:transaction-subscribers hash])
(defn remove-pending-message
[{:keys [command->chat] :as db} message-id]
(let [chat-id (get command->chat message-id)
path [:chats chat-id :staged-commands]]
(if chat-id
(-> db
(update :transaction-subscribers dissoc hash)
(update-in path dissoc (:id command)))))
(update :transaction-subscribers dissoc message-id)
(update-in path dissoc message-id))
db)))
(register-handler ::remove-pending-messages
(fn [db [_ hashes]]
(reduce remove-pending-message db hashes)))
(fn [db [_ ids]]
(log/debug :message-ids ids)
(reduce remove-pending-message db ids)))
(register-handler ::remove-pending-message
(fn [db [_ hash]]
(remove-pending-message db hash)))
(fn [db [_ message-id]]
(remove-pending-message db message-id)))
(register-handler :transaction-queued
(after #(dispatch [:navigate-to :confirm]))
(fn [db [_ {:keys [hash args]}]]
(fn [db [_ {:keys [id message_id args]}]]
(let [{:keys [from to value]} args
transaction {:hash hash
transaction {:id id
:from from
:to to
:value (.toDecimal js/Web3.prototype value)}]
(assoc-in db [:transactions-queue hash] transaction))))
:value (.toDecimal js/Web3.prototype value)
:message-id message_id}]
(assoc-in db [:transactions-queue id] transaction))))
(register-handler :transaction-completed
(u/side-effect!
(fn [db [_ old-hash result-str]]
(let [{:keys [hash error]} (t/json->clj result-str)]
;; todo: handle error
(when hash
(dispatch [::send-pending-message old-hash hash])
(dispatch [::remove-transaction old-hash]))))))
(fn [{:keys [transactions command->chat]} [_ {:keys [id response previous-view-id]}]]
(let [{:keys [hash error] :as parsed-response} (t/json->clj response)
{:keys [message-id]} (transactions id)]
(log/debug :parsed-response parsed-response)
(if (and error (string? error) (not (s/blank? error)))
;; todo: revisit this
;; currently transaction is removed after attempt
;; to complete it with wrong password
(do
(dispatch [::remove-transaction id])
(dispatch [:set :wrong-password? true])
(when-let [chat-id (get command->chat message-id)]
(dispatch [:clear-command chat-id message-id])))
(if message-id
(do (dispatch [::add-transactions-hash {:id id
:hash hash
:message-id message-id}])
(dispatch [::check-completed-transaction!
{:message-id message-id}])
(dispatch [:navigation-replace previous-view-id]))
(dispatch [::remove-transaction id])))))))
(register-handler ::add-transactions-hash
(fn [db [_ {:keys [id hash message-id]}]]
(-> db
(assoc-in [:transactions id :hash] hash)
(assoc-in [:message-id->transaction-id message-id] id))))
(register-handler ::send-pending-message
(u/side-effect!
(fn [{:keys [transaction-subscribers] :as db} [_ old-hash new-hash]]
(when-let [params (transaction-subscribers old-hash)]
(let [params' (assoc-in params [:handler-data :transaction-hash] new-hash)]
(fn [{:keys [transaction-subscribers]} [_ message-id hash]]
(when-let [params (transaction-subscribers message-id)]
(let [params' (assoc-in params [:handler-data :transaction-hash] hash)]
(dispatch [:prepare-command! params']))
(dispatch [::remove-transaction-subscriber old-hash])))))
(dispatch [::remove-transaction-subscriber message-id])))))
(register-handler ::remove-transaction-subscriber
(fn [db [_ old-hash]]
(update db :transaction-subscribers dissoc old-hash)))
(register-handler ::check-completed-transaction!
(u/side-effect!
(fn [{:keys [message-id->transaction-id transactions transaction-subscribers]}
[_ {:keys [message-id]}]]
(let [id (get message-id->transaction-id message-id)
{:keys [hash]} (get transactions id)
pending-message (get transaction-subscribers message-id)]
(when (and pending-message id hash)
(dispatch [::send-pending-message message-id hash])
(dispatch [::remove-transaction id]))))))

View File

@ -57,6 +57,3 @@
:value password
:label (label :t/password)
:on-change-text #(dispatch [:set-in [:confirm-transactions :password] %])}]]])
;(re-frame.core/dispatch [:set :view-id :confirm])

View File

@ -14,11 +14,11 @@
[status-im.i18n :refer [label label-pluralize]]
cljsjs.web3))
(defn title-bar [title hash]
(defn title-bar [title id]
[view st/title-bar
[text {:style st/title-bar-text} title]
[touchable-highlight {:style st/icon-close-container
:on-press #(dispatch [:deny-transaction hash])}
:on-press #(dispatch [:deny-transaction id])}
[view [image {:source {:uri :icon_close_gray}
:style st/icon-close}]]]])
@ -31,7 +31,7 @@
[view st/transaction-info-column-value
[text {:style st/transaction-info-value} value]]]])
(defview transaction-page [{:keys [hash from to value] :as transaction}]
(defview transaction-page [{:keys [id from to value] :as transaction}]
[{:keys [name] :as contact} [:contact-by-address to]]
(let [eth-value (.fromWei js/Web3.prototype value "ether")
title (str eth-value " ETH to " name)
@ -39,8 +39,8 @@
[(label :t/recipient) name]
[(label :t/value) (str eth-value " ETH")]]]
[view {:style st/transaction-page
:key hash}
[title-bar title hash]
:key id}
[title-bar title id]
[view st/scroll-view-container
[scroll-view {:style st/scroll-view
:contentContainerStyle st/scroll-view-content

View File

@ -46,8 +46,8 @@
(let [diff (t/in-seconds (t/interval time (t/now)))]
(if (< diff 60)
(label :t/active-online)
(let [unit (first (drop-while #(or (>= diff (:limit %))
(not (:limit %)))
(let [unit (first (drop-while #(and (>= diff (:limit %))
(:limit %))
units))]
(-> (/ diff (:in-second unit))
Math/floor