From 401f8dcf8cb50dbba936fc30ac7b07aed02fad73 Mon Sep 17 00:00:00 2001 From: kagel Date: Sat, 1 Oct 2016 15:29:18 +0300 Subject: [PATCH] Fix multisig wallet payout flow --- .../20160905235051-contracts.down.sql | 2 ++ .../20160905235051-contracts.up.sql | 2 ++ resources/sql/queries.sql | 25 +++++++++++++-- src/clj/commiteth/db/bounties.clj | 10 ++++++ src/clj/commiteth/eth/multisig_wallet.clj | 11 +++++++ src/clj/commiteth/scheduler.clj | 32 +++++++++++++------ 6 files changed, 71 insertions(+), 11 deletions(-) diff --git a/resources/migrations/20160905235051-contracts.down.sql b/resources/migrations/20160905235051-contracts.down.sql index b4f2c4f..afdc5bc 100644 --- a/resources/migrations/20160905235051-contracts.down.sql +++ b/resources/migrations/20160905235051-contracts.down.sql @@ -9,3 +9,5 @@ ALTER TABLE public.issues ADD address VARCHAR(256); ALTER TABLE public.issues DROP COLUMN comment_id; +ALTER TABLE public.issues + DROP COLUMN execute_hash; diff --git a/resources/migrations/20160905235051-contracts.up.sql b/resources/migrations/20160905235051-contracts.up.sql index fae02f6..ebbb758 100644 --- a/resources/migrations/20160905235051-contracts.up.sql +++ b/resources/migrations/20160905235051-contracts.up.sql @@ -6,6 +6,8 @@ ALTER TABLE public.issues ADD confirm_hash VARCHAR(128) NULL; ALTER TABLE public.issues ADD comment_id INTEGER NULL; +ALTER TABLE public.issues + ADD execute_hash VARCHAR(128) NULL; -- noinspection SqlResolve ALTER TABLE public.issues DROP COLUMN address; diff --git a/resources/sql/queries.sql b/resources/sql/queries.sql index f5abc6b..2276fd1 100644 --- a/resources/sql/queries.sql +++ b/resources/sql/queries.sql @@ -175,14 +175,35 @@ FROM issues i AND p.repo_id = i.repo_id INNER JOIN users u ON u.id = p.user_id -WHERE i.confirm_hash IS NULL; +WHERE i.execute_hash IS NULL; + +-- :name pending-payouts-list :? :* +-- :doc lists all recently closed issues awaiting to be confirmed +SELECT + i.contract_address AS contract_address, + i.issue_id AS issue_id, + i.execute_hash AS execute_hash +FROM issues i + INNER JOIN pull_requests p + ON (p.commit_id = i.commit_id OR coalesce(p.issue_number, -1) = i.issue_number) + AND p.repo_id = i.repo_id + INNER JOIN users u + ON u.id = p.user_id +WHERE i.confirm_hash IS NULL + AND i.execute_hash IS NOT NULL; -- :name update-confirm-hash :! :n --- :doc updates issue with transaction hash +-- :doc updates issue with confirmation hash UPDATE issues SET confirm_hash = :confirm_hash WHERE issue_id = :issue_id; +-- :name update-execute-hash :! :n +-- :doc updates issue with execute transaction hash +UPDATE issues +SET execute_hash = :execute_hash +WHERE issue_id = :issue_id; + -- :name all-bounties-list :? :* -- :doc lists all issues labeled as 'bounty' SELECT diff --git a/src/clj/commiteth/db/bounties.clj b/src/clj/commiteth/db/bounties.clj index f11b497..c30ffa5 100644 --- a/src/clj/commiteth/db/bounties.clj +++ b/src/clj/commiteth/db/bounties.clj @@ -24,11 +24,21 @@ (jdbc/with-db-connection [con-db *db*] (db/pending-bounties-list con-db))) +(defn pending-payouts-list + [] + (jdbc/with-db-connection [con-db *db*] + (db/pending-payouts-list con-db))) + (defn update-confirm-hash [issue-id confirm-hash] (jdbc/with-db-connection [con-db *db*] (db/update-confirm-hash con-db {:issue_id issue-id :confirm_hash confirm-hash}))) +(defn update-execute-hash + [issue-id execute-hash] + (jdbc/with-db-connection [con-db *db*] + (db/update-execute-hash con-db {:issue_id issue-id :execute_hash execute-hash}))) + (defn get-bounty-address [user repo issue-number] (jdbc/with-db-connection [con-db *db*] diff --git a/src/clj/commiteth/eth/multisig_wallet.clj b/src/clj/commiteth/eth/multisig_wallet.clj index 623bfd2..935ea55 100644 --- a/src/clj/commiteth/eth/multisig_wallet.clj +++ b/src/clj/commiteth/eth/multisig_wallet.clj @@ -2,6 +2,8 @@ (:require [commiteth.eth.core :as eth] [clojure.tools.logging :as log])) +(def confirmation-topic "0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda") + (defn get-owner [contract index] (eth/call contract "0xc41a360a" index)) @@ -10,3 +12,12 @@ [contract to value] (log/debug "multisig.execute(contract, to, value)" contract to value) (eth/execute (eth/eth-account) contract "0xb61d27f6" to value "0x60" "0x0" "0x0")) + +(defn find-confirmation-hash + [receipt] + (let [logs (:logs receipt) + has-confirmation-event #(some (fn [topic] (= topic confirmation-topic)) (:topics %)) + confirmation-event (first (filter has-confirmation-event logs)) + confirmation-data (:data confirmation-event)] + (when confirmation-data + (subs confirmation-data 66)))) diff --git a/src/clj/commiteth/scheduler.clj b/src/clj/commiteth/scheduler.clj index f43535a..2b4a9e4 100644 --- a/src/clj/commiteth/scheduler.clj +++ b/src/clj/commiteth/scheduler.clj @@ -36,7 +36,18 @@ :let [value (eth/get-balance-hex contract-address)]] (->> (wallet/execute contract-address payout-address value) - (bounties/update-confirm-hash issue-id)))) + (bounties/update-execute-hash issue-id)))) + +(defn update-confirm-hash + "Gets transaction receipt for each pending payout and updates confirm_hash" + [] + (doseq [{issue-id :issue_id + execute-hash :execute_hash} (bounties/pending-payouts-list)] + (log/debug "pending payout:" execute-hash) + (when-let [receipt (eth/get-transaction-receipt execute-hash)] + (log/info "execution receipt for issue #" issue-id ": " receipt) + (when-let [confirm-hash (wallet/find-confirmation-hash receipt)] + (bounties/update-confirm-hash issue-id confirm-hash))))) (defn update-balance [] @@ -64,7 +75,7 @@ (first (filter #(= name (.getName %)) threads)))) (defn every - [ms do-fn] + [ms tasks] (.start (new Thread (fn [] (while (not (.isInterrupted (Thread/currentThread))) @@ -72,7 +83,9 @@ (Thread/sleep ms) (catch InterruptedException _ (.interrupt (Thread/currentThread)))) - (do-fn)))) + (doseq [task tasks] + (try (task) + (catch Exception e (log/error e))))))) scheduler-thread-name))) (defn stop-scheduler [] @@ -80,16 +93,17 @@ (log/debug "Stopping scheduler thread") (.interrupt scheduler))) -(defn restart-scheduler [ms task] +(defn restart-scheduler [ms tasks] (stop-scheduler) (log/debug "Starting scheduler thread") (while (get-thread-by-name scheduler-thread-name) (Thread/sleep 1)) - (every ms task)) + (every ms tasks)) (mount/defstate scheduler - :start (restart-scheduler 60000 (fn [] - (update-issue-contract-address) - (self-sign-bounty) - (update-balance))) + :start (restart-scheduler 60000 + [update-issue-contract-address + update-confirm-hash + self-sign-bounty + update-balance]) :stop (stop-scheduler))