diff --git a/resources/sql/queries.sql b/resources/sql/queries.sql index 8a518ff..8379717 100644 --- a/resources/sql/queries.sql +++ b/resources/sql/queries.sql @@ -296,7 +296,7 @@ SELECT i.tokens AS tokens, i.value_usd AS value_usd, u.login AS winner_login, - u.address AS payout_address + u.address AS winner_address FROM issues i, pull_requests p, users u, repositories r WHERE p.issue_id = i.issue_id @@ -405,23 +405,6 @@ SET payout_receipt = :payout_receipt::jsonb, updated = timezone('utc'::text, now()) WHERE issue_id = :issue_id; - --- :name update-token-balances :! :n --- :doc updates issue with given token balances -UPDATE issues -SET tokens = :token_balances::jsonb, -updated = timezone('utc'::text, now()) -WHERE contract_address = :contract_address; - - --- :name update-usd-value :! :n --- :doc updates issue with given USD value -UPDATE issues -SET value_usd = :usd_value, -value_usd_updated = timezone('utc'::text, now()) -WHERE contract_address = :contract_address; - - -- :name update-issue-open :! :n -- :doc updates issue's open status UPDATE issues @@ -455,12 +438,23 @@ SELECT i.issue_number AS issue_number, i.is_open AS is_open, i.winner_login AS winner_login, + i.transaction_hash AS transaction_hash, + i.contract_address AS contract_address, + i.confirm_hash AS confirm_hash, + i.execute_hash AS execute_hash, + i.payout_hash AS payout_hash, + i.watch_hash AS watch_hash, + i.payout_receipt AS payout_receipt, i.commit_sha AS commit_sha, u.address AS owner_address, + u.login AS owner_login, i.contract_address AS contract_address, i.confirm_hash AS confirm_hash, i.title AS title, i.comment_id AS comment_id, + i.balance_eth AS balance_eth, + i.tokens AS tokens, + i.value_usd AS value_usd, i.repo_id AS repo_id, r.owner AS owner, r.repo AS repo @@ -601,10 +595,12 @@ AND r.repo_id = i.repo_id AND r.owner = :owner AND r.repo = :repo; --- :name update-eth-balance :! :n +-- :name update-balances :! :n -- :doc updates balance of a wallet attached to a given issue UPDATE issues SET balance_eth = :balance_eth, + tokens = :token_balances::jsonb, + value_usd = :usd_value, updated = timezone('utc'::text, now()) WHERE contract_address = :contract_address; @@ -658,8 +654,8 @@ SELECT pr_id, issue_number, issue_id, - user_name, - user_avatar_url, + user_name as display_name, + user_avatar_url as avatar_url, balance_eth, tokens, value_usd, diff --git a/src/clj/commiteth/bounties.clj b/src/clj/commiteth/bounties.clj index 2898adc..cd348b0 100644 --- a/src/clj/commiteth/bounties.clj +++ b/src/clj/commiteth/bounties.clj @@ -1,14 +1,14 @@ (ns commiteth.bounties (:require [commiteth.db.issues :as issues] + [commiteth.db.bounties :as db-bounties] [commiteth.db.users :as users] [commiteth.db.repositories :as repos] - [commiteth.db.comment-images :as comment-images] [commiteth.eth.core :as eth] [commiteth.eth.tracker :as tracker] [commiteth.github.core :as github] + [commiteth.util.util :refer [to-map]] [commiteth.eth.multisig-wallet :as multisig] - [commiteth.model.bounty :as bnt] - [commiteth.util.png-rendering :as png-rendering] + [commiteth.model.bounty :as bnt] [clojure.tools.logging :as log])) @@ -22,7 +22,58 @@ (let [labels (:labels issue)] (some #(= label-name (:name %)) labels))) -(defn deploy-contract [owner-address issue-id] +(def last-states (atom {})) + +(defn transition [{:keys [issue-id tx-info] :as bounty} state] + (let [bounty-not= (fn [current db] + (some #(not= (%1 current) (%1 db)) + (disj (set (keys current)) :tx-info))) + bounty-from-db (issues/get-issue-by-id issue-id) + bounty (and (or + (and (= state :pending-contributor-address) + (not= state (get @last-states issue-id))) + (bounty-not= bounty bounty-from-db)) + (merge bounty-from-db bounty))] + (when bounty + (case state + :deploying + (tracker/track-tx! tx-info) + + :opened + (do + (tracker/untrack-tx! {:issue-id (:issue-id bounty) + :tx-hash (:transaction-hash bounty) + :result (:contract-address bounty) + :type :deploy}) + (github/update-bounty-comment-image bounty)) + + :pending-sob-confirmation + (tracker/track-tx! tx-info) + + :pending-maintainer-confirmation + (tracker/untrack-tx! tx-info) + + :paid + (db-bounties/update-payout-receipt issue-id (:payout-receipt bounty)) + + :watch-set + (tracker/track-tx! tx-info) + + :watch-reset + (tracker/untrack-tx! tx-info) + + :update-balances + (do + (github/update-bounty-comment-image bounty) + (issues/update-balances (:contract-address bounty) + (:balance-eth bounty) + (:tokens bounty) + (:value-usd bounty))) + nil) + (github/update-comment bounty state))) + (swap! last-states assoc issue-id state)) + +(defn deploy-contract [owner-address issue-id] (if (empty? owner-address) (log/errorf "issue %s: Unable to deploy bounty contract because repo owner has no Ethereum addres" issue-id) (try @@ -31,23 +82,36 @@ :internal-tx-id [:deploy issue-id]})] (do (log/infof "issue %s: Contract deployed, transaction-hash: %s" issue-id (:tx-hash tx-info)) - (github/post-deploying-comment issue-id - (:tx-hash tx-info)) - (tracker/track-tx! tx-info)) + (transition {:issue-id issue-id + :transaction-hash (:tx-hash tx-info) + :tx-info tx-info} :deploying)) (log/errorf "issue %s Failed to deploy contract to %s" issue-id owner-address)) (catch Exception ex (log/errorf ex "issue %s: deploy-contract exception" issue-id))))) +(defn execute-payout [issue-id contract-address payout-address] + (if (empty? payout-address) + (do + (log/warn "issue %s: Cannot sign pending bounty - winner has no payout address" issue-id) + (transition {:issue-id issue-id} :pending-contributor-address)) + (let [tx-info (multisig/send-all {:contract contract-address + :payout-address payout-address + :internal-tx-id [:execute issue-id]})] + (log/infof "issue %s: Payout self-signed, called sign-all(%s) tx: %s" issue-id contract-address payout-address (:tx-hash tx-info)) + (transition {:execute-hash (:tx-hash tx-info) + :issue-id issue-id + :tx-info tx-info} :pending-sob-confirmation) + tx-info))) + (defn add-bounty-for-issue [repo repo-id issue] (let [{issue-id :id issue-number :number issue-title :title} issue created-issue (issues/create repo-id issue-id issue-number issue-title) - {owner-address :address - owner :owner} (users/get-repo-owner repo-id)] + {:keys [address owner]} (users/get-repo-owner repo-id)] (log/debug "issue %s: Adding bounty for issue %s/%s - owner address: %s" - issue-id repo issue-number owner-address) + issue-id repo issue-number address) (if (= 1 created-issue) - (deploy-contract owner-address issue-id) + (deploy-contract address issue-id) (log/debug "issue %s: Issue already exists in DB, ignoring")))) (defn maybe-add-bounty-for-issue [repo repo-id issue] @@ -63,9 +127,8 @@ ;; We have a max-limit to ensure people can't add more issues and ;; drain bot account until we have economic design in place (defn add-bounties-for-existing-issues [full-name] - (let [{repo-id :repo_id - owner :owner - repo :repo} (repos/get-repo full-name) + (let [{:keys [repo-id + owner repo] } (repos/get-repo full-name) issues (github/get-issues owner repo) bounty-issues (filter has-bounty-label? issues) max-bounties (take max-issues-limit bounty-issues)] @@ -75,30 +138,13 @@ (map (partial maybe-add-bounty-for-issue repo repo-id) max-bounties)))) -(defn update-bounty-comment-image [issue-id owner repo issue-number contract-address eth-balance eth-balance-str tokens] - (let [hash (github/github-comment-hash owner repo issue-number eth-balance) - issue-url (str owner "/" repo "/issues/" (str issue-number)) - png-data (png-rendering/gen-comment-image - contract-address - eth-balance-str - tokens - issue-url)] - (log/debug "update-bounty-comment-image" issue-id owner repo issue-number) - (log/debug contract-address eth-balance-str) - (log/debug "hash" hash) - - (if png-data - (comment-images/save-image! issue-id hash png-data) - (log/error "Failed ot generate PNG")))) - - (defn update-bounty-issue-titles "Update stored titles for bounty issues if changed on Github side" [] (log/debug "update-bounty-issue-titles") - (for [{:keys [title issue_number repo owner]} + (for [{:keys [title issue-number repo owner]} (issues/get-issue-titles)] - (let [gh-issue (github/get-issue owner repo issue_number)] + (let [gh-issue (github/get-issue owner repo issue-number)] (if-not (= title (:title gh-issue)) (issues/update-issue-title (:id gh-issue) (:title gh-issue)))))) @@ -118,29 +164,31 @@ - :pending-contributor-address - :pending-maintainer-confirmation" [bounty] - (assert-keys bounty [:winner_login :payout_address :confirm_hash :payout_hash - :claims :tokens :contract_address]) + (assert-keys bounty [:winner-login :payout-address :confirm-hash :payout-hash + :claims :tokens :contract-address]) ;; Some bounties have been paid out manually, the payout hash - ;; was set properly but winner_login was not + ;; was set properly but winner-login was not (let [open-claims (fn open-claims [bounty] (filter bnt/open? (:claims bounty)))] - (if-let [merged-or-paid? (or (:winner_login bounty) - (:payout_receipt bounty))] + (if-let [merged-or-paid? (or (:winner-login bounty) + (:payout-receipt bounty))] (cond - (:payout_receipt bounty) :paid - (nil? (:payout_address bounty)) :pending-contributor-address - ;; `confirm_hash` is set by us as soon as a PR is merged and the + (:payout-receipt bounty) :paid + (nil? (:payout-address bounty)) :pending-contributor-address + ;; `confirm-hash` is set by us as soon as a PR is merged and the ;; contributor address is known. Usually end users should not need ;; to be aware of this step. - (nil? (:confirm_hash bounty)) :pending-sob-confirmation - ;; `payout_hash` is set when the bounty issuer signs the payout - (nil? (:payout_hash bounty)) :pending-maintainer-confirmation + (nil? (:confirm-hash bounty)) :pending-sob-confirmation + ;; `payout-hash` is set when the bounty issuer signs the payout + (nil? (:payout-hash bounty)) :pending-maintainer-confirmation :else :merged) (cond ; not yet merged (< 1 (count (open-claims bounty))) :multiple-claims (= 1 (count (open-claims bounty))) :claimed (seq (:tokens bounty)) :funded - (:contract_address bounty) :opened)))) + (:contract-address bounty) :opened)))) + + (comment (def user 97496) diff --git a/src/clj/commiteth/db/bounties.clj b/src/clj/commiteth/db/bounties.clj index 2a6dacb..f76d37a 100644 --- a/src/clj/commiteth/db/bounties.clj +++ b/src/clj/commiteth/db/bounties.clj @@ -1,5 +1,7 @@ (ns commiteth.db.bounties (:require [commiteth.db.core :refer [*db*] :as db] + [commiteth.util.util :refer [to-db-map]] + [clojure.tools.logging :as log] [clojure.java.jdbc :as jdbc] [clojure.set :refer [rename-keys]])) @@ -58,7 +60,7 @@ (defn update-payout-hash [issue-id payout-hash] (jdbc/with-db-connection [con-db *db*] - (db/update-payout-hash con-db {:issue_id issue-id :payout_hash payout-hash}))) + (db/update-payout-hash con-db (to-db-map issue-id payout-hash)))) (defn reset-payout-hash [issue-id] @@ -66,29 +68,29 @@ (db/reset-payout-hash con-db {:issue_id issue-id}))) (def payout-receipt-keys - [:issue_id - :payout_hash - :contract_address + [:issue-id + :payout-hash + :contract-address :repo :owner - :comment_id - :issue_number - :balance_eth + :comment-id + :issue-number + :balance-eth :tokens - :confirm_hash - :payee_login + :confirm-hash + :payee-login :updated]) (defn update-payout-receipt [issue-id payout-receipt] (jdbc/with-db-connection [con-db *db*] - (db/update-payout-receipt con-db {:issue_id issue-id - :payout_receipt payout-receipt}))) + (db/update-payout-receipt con-db (to-db-map issue-id payout-receipt)))) (defn get-bounty [owner repo issue-number] (jdbc/with-db-connection [con-db *db*] - (db/get-bounty con-db {:owner owner :repo repo :issue_number issue-number}))) + (log/info "get-bounty params:" (to-db-map owner repo issue-number)) + (db/get-bounty con-db (to-db-map owner repo issue-number)))) (defn open-bounty-contracts [] diff --git a/src/clj/commiteth/db/core.clj b/src/clj/commiteth/db/core.clj index 2ca5ff7..6e03c04 100644 --- a/src/clj/commiteth/db/core.clj +++ b/src/clj/commiteth/db/core.clj @@ -7,6 +7,7 @@ [mount.core :refer [defstate]] [migratus.core :as migratus] [mpg.core :as mpg] + [hugsql.core] [clojure.string :as str]) (:import org.postgresql.util.PGobject java.sql.Array @@ -92,3 +93,30 @@ (defn update! [& args] (apply jdbc/update! *db* args)) + +(defn convert-keys-to-lisp-case [res] + (->> res + (map #(vector (keyword (str/replace (name (first %1)) "_" "-")) + (second %1))) + (into {}))) + +(defn result-one-sql->lisp + [this result options] + (convert-keys-to-lisp-case (first result))) + +(defn result-many-sql->lisp + [this result options] + (map convert-keys-to-lisp-case result)) + +(defmethod hugsql.core/hugsql-result-fn :1 [sym] + 'commiteth.db.core/result-one-sql->lisp) + +(defmethod hugsql.core/hugsql-result-fn :one [sym] + 'commiteth.db.core/result-one-sql->lisp) + +(defmethod hugsql.core/hugsql-result-fn :* [sym] + 'commiteth.db.core/result-many-sql->lisp) + +(defmethod hugsql.core/hugsql-result-fn :many [sym] + 'commiteth.db.core/result-many-sql->lisp) + diff --git a/src/clj/commiteth/db/issues.clj b/src/clj/commiteth/db/issues.clj index 91e33b8..d1415cf 100644 --- a/src/clj/commiteth/db/issues.clj +++ b/src/clj/commiteth/db/issues.clj @@ -1,6 +1,7 @@ (ns commiteth.db.issues (:require [commiteth.db.core :refer [*db*] :as db] [clojure.java.jdbc :as jdbc] + [commiteth.util.util :refer [to-db-map]] [clojure.set :refer [rename-keys]] [clojure.tools.logging :as log])) @@ -71,23 +72,13 @@ (jdbc/with-db-connection [con-db *db*] (db/list-pending-deployments con-db))) -(defn update-eth-balance - [contract-address balance-eth] +(defn update-balances + [contract-address balance-eth token-balances usd-value] (jdbc/with-db-connection [con-db *db*] - (db/update-eth-balance con-db {:contract_address contract-address - :balance_eth balance-eth}))) - -(defn update-token-balances - [contract-address balances] - (jdbc/with-db-connection [con-db *db*] - (db/update-token-balances con-db {:contract_address contract-address - :token_balances balances}))) - -(defn update-usd-value - [contract-address usd-value] - (jdbc/with-db-connection [con-db *db*] - (db/update-usd-value con-db {:contract_address contract-address - :usd_value usd-value}))) + (db/update-balances con-db (to-db-map contract-address + balance-eth + token-balances + usd-value)))) (defn update-open-status [issue-id is-open] diff --git a/src/clj/commiteth/eth/core.clj b/src/clj/commiteth/eth/core.clj index 37db1db..9fa3112 100644 --- a/src/clj/commiteth/eth/core.clj +++ b/src/clj/commiteth/eth/core.clj @@ -85,10 +85,10 @@ response @(post (eth-rpc-url) options) result (safe-read-str (:body response))] (when internal-tx-id - (log/infof "%s: eth-rpc %s" tx-id-str method)) + (log/debugf "%s: eth-rpc %s" tx-id-str method)) (log/debugf "%s: eth-rpc req(%s) body: %s" tx-id-str request-id body) (if tx-id-str - (log/infof "%s: eth-rpc req(%s) result: %s" tx-id-str request-id result) + (log/debugf "%s: eth-rpc req(%s) result: %s" tx-id-str request-id result) (log/debugf "no-tx-id: eth-rpc req(%s) result: %s" request-id result)) (cond ;; Ignore any responses that have mismatching request ID @@ -228,7 +228,7 @@ (hex->big-integer gas) contract (:data params) - nonce) + (biginteger nonce)) tx-hash (try (eth-rpc {:method "eth_sendRawTransaction" diff --git a/src/clj/commiteth/eth/tracker.clj b/src/clj/commiteth/eth/tracker.clj index 9f77185..fc304c7 100644 --- a/src/clj/commiteth/eth/tracker.clj +++ b/src/clj/commiteth/eth/tracker.clj @@ -62,9 +62,44 @@ (:tx-hash @current-tx) (:type @current-tx)) (reset! current-tx nil))) + ) + +(defrecord ParallelTxTracker [current-txs] + ITxTracker + (try-reserve-nonce [this] + (let [nonce (get-nonce) + monitored-nonces (set (keys @current-txs)) + first-available-nonce (some #(if (monitored-nonces %1) nil %1) (iterate inc nonce))] + (swap! current-txs assoc first-available-nonce nil) + first-available-nonce)) + + (drop-nonce [this nonce] + (swap! current-txs dissoc nonce)) + + (track-tx [this tx-info] + (swap! current-txs update (:nonce tx-info) merge tx-info)) + + (untrack-tx [this tx-info] + (when (contains? (set (keys @current-txs)) (:nonce tx-info)) + (swap! current-txs dissoc (:nonce tx-info)))) + + (prune-txs [this unmined-txs] + (swap! current-txs + (fn [txs] + (let [unmined-tx-hashes (set (map :tx-hash unmined-txs)) + time-threshold (t/minus (t/now) (t/minutes 10)) + nonces-to-remove + (->> txs + vals + (filter #(or (unmined-tx-hashes (:tx-hash %1)) + (and (:timestamp %1) + (t/before? (:timestamp %1) time-threshold)))) + (map :nonce))] + (apply dissoc txs nonces-to-remove))))) ) -(def tx-tracker (SequentialTxTracker. (atom nil))) + +(def tx-tracker (ParallelTxTracker. (atom nil))) (defn try-reserve-nonce! [] (try-reserve-nonce tx-tracker)) diff --git a/src/clj/commiteth/github/core.clj b/src/clj/commiteth/github/core.clj index ba0c89b..25a792d 100644 --- a/src/clj/commiteth/github/core.clj +++ b/src/clj/commiteth/github/core.clj @@ -15,6 +15,10 @@ [commiteth.db.issues :as db-issues] [clojure.tools.logging :as log] [cheshire.core :as json] + [commiteth.util.png-rendering :as png-rendering] + [commiteth.db.issues :as db-issues] + [commiteth.db.bounties :as db-bounties] + [commiteth.db.comment-images :as comment-images] [clojure.string :as str]) (:import [java.util UUID])) @@ -230,7 +234,7 @@ (str "Contract address: [" addr "](" url-base "/address/" addr ")\n"))) (defn generate-open-comment - [owner repo issue-number contract-address eth-balance eth-balance-str tokens] + [owner repo issue-number contract-address eth-balance tokens] (let [image-url (md-image "QR Code" (get-qr-url owner repo issue-number eth-balance)) site-url (md-url (server-address) (server-address))] (format (str "Current balance: %s ETH\n" @@ -243,14 +247,14 @@ (if (on-testnet?) "To fund it, send test ETH or test ERC20/ERC223 tokens to the contract address." "To fund it, send ETH or ERC20/ERC223 tokens to the contract address.")) - eth-balance-str image-url site-url))) + (.toPlainString (bigdec eth-balance)) image-url site-url))) (defn learn-more-text [] (let [site-url (md-url (server-address) (server-address))] (format "Visit %s to learn more.\n" site-url))) (defn generate-merged-comment - [contract-address eth-balance-str tokens winner-login winner-address-missing?] + [contract-address eth-balance tokens winner-login winner-address-missing?] (format (str "Balance: %s ETH\n" (token-balances-text tokens) (contract-addr-text contract-address) @@ -260,17 +264,17 @@ "Pending maintainer confirmation") "\n") "Winner: %s\n" (learn-more-text)) - eth-balance-str winner-login)) + (.toPlainString (bigdec eth-balance)) winner-login)) (defn generate-paid-comment - [contract-address eth-balance-str tokens payee-login] + [contract-address eth-balance tokens payee-login] (format (str "Balance: %s ETH\n" (token-balances-text tokens) (contract-addr-text contract-address) (network-text) "Paid to: %s\n" (learn-more-text)) - eth-balance-str payee-login)) + (.toPlainString (bigdec eth-balance)) payee-login)) (defn make-patch-request [end-point positional query] (let [{:keys [auth oauth-token] @@ -290,6 +294,22 @@ :otp))] (assoc req :body (json/generate-string (or raw-query proper-query))))) +(defn update-bounty-comment-image [{:keys [issue-id owner repo issue-number contract-address balance-eth tokens]}] + (let [hash (github-comment-hash owner repo issue-number balance-eth) + issue-url (str owner "/" repo "/issues/" (str issue-number)) + png-data (png-rendering/gen-comment-image + contract-address + (.toPlainString (bigdec balance-eth)) + tokens + issue-url)] + (log/debug "update-bounty-comment-image" issue-id owner repo issue-number) + (log/debug contract-address balance-eth) + (log/debug "hash" hash) + + (if png-data + (comment-images/save-image! issue-id hash png-data) + (log/error "Failed ot generate PNG")))) + (defn post-deploying-comment [issue-id tx-id] (let [{owner :owner @@ -310,52 +330,51 @@ (defn update-comment "Update comment for an open bounty issue" - [owner repo comment-id issue-number contract-address eth-balance eth-balance-str tokens] - (let [comment (generate-open-comment owner - repo - issue-number - contract-address - eth-balance - eth-balance-str - tokens)] - (log/debug (str "Updating " owner "/" repo "/" issue-number - " comment #" comment-id " with contents: " comment)) - (let [req (make-patch-request "repos/%s/%s/issues/comments/%s" - [owner repo comment-id] - (assoc (self-auth-params) :body comment))] - (tentacles/safe-parse (http/request req))))) - - - -(defn update-merged-issue-comment - "Update comment for a bounty issue with winning claim (waiting to be - signed off by maintainer/user ETH address missing)" - [owner repo comment-id contract-address eth-balance-str tokens winner-login winner-address-missing?] - (let [comment (generate-merged-comment contract-address - eth-balance-str + [{:keys [issue-id owner repo comment-id issue-number contract-address + balance-eth tokens + payout-receipt + owner-login + winner-login transaction-hash] :as issue} + state] + (let [comment (case state + :deploying + (generate-deploying-comment owner repo issue-number transaction-hash) + (:opened :update-balances) + (generate-open-comment owner + repo + issue-number + contract-address + balance-eth + tokens) + :pending-sob-confirmation + (generate-merged-comment contract-address + balance-eth + tokens + (or winner-login owner-login) + false) + :pending-contributor-address + (generate-merged-comment contract-address + balance-eth + tokens + (or winner-login owner-login) + true) + :paid + (generate-paid-comment contract-address + balance-eth tokens - winner-login - winner-address-missing?)] - (log/debug (str "Updating merged bounty issue (" owner "/" repo ")" - " comment#" comment-id " with contents: " comment)) - (let [req (make-patch-request "repos/%s/%s/issues/comments/%s" - [owner repo comment-id] - (assoc (self-auth-params) :body comment))] - (tentacles/safe-parse (http/request req))))) - -(defn update-paid-issue-comment - "Update comment for a paid out bounty issue" - [owner repo comment-id contract-address eth-balance-str tokens payee-login] - (let [comment (generate-paid-comment contract-address - eth-balance-str - tokens - payee-login)] - (log/debug (str "Updating paid bounty (" owner "/" repo ")" - " comment#" comment-id " with contents: " comment)) - (let [req (make-patch-request "repos/%s/%s/issues/comments/%s" - [owner repo comment-id] - (assoc (self-auth-params) :body comment))] - (tentacles/safe-parse (http/request req))))) + (or winner-login owner-login)) + nil)] + (log/info (str "Updating " owner "/" repo "/" issue-number + " comment #" comment-id " with contents: " comment)) + (if (= state :deploying) + (let [resp (issues/create-comment owner repo issue-number comment (self-auth-params)) + comment-id (:id resp)] + (db-issues/update-comment-id issue-id comment-id)) + (when comment + (let [req (make-patch-request "repos/%s/%s/issues/comments/%s" + [owner repo comment-id] + (assoc (self-auth-params) :body comment))] + (tentacles/safe-parse (http/request req))))))) (defn get-issue [owner repo issue-number] diff --git a/src/clj/commiteth/routes/qrcodes.clj b/src/clj/commiteth/routes/qrcodes.clj index 1519077..1831ed0 100644 --- a/src/clj/commiteth/routes/qrcodes.clj +++ b/src/clj/commiteth/routes/qrcodes.clj @@ -12,21 +12,18 @@ (context "/qr" [] (GET "/:owner/:repo/bounty/:issue{[0-9]{1,9}}/:hash/qr.png" [owner repo issue hash] (log/debug "qr PNG GET" owner repo issue hash) - (if-let [{address :contract_address - repo :repo - issue-id :issue_id - balance-eth :balance_eth} + (if-let [{:keys [contract-address repo issue-id balance-eth]} (bounties/get-bounty owner repo (Integer/parseInt issue))] (do - (log/debug "address:" address) + (log/debug "address:" contract-address) (log/debug owner repo issue balance-eth) (log/debug hash (github/github-comment-hash owner repo issue balance-eth)) - (if address - (if-let [{png-data :png_data} + (if contract-address + (if-let [{:keys [png-data]} (comment-images/get-image-data - issue-id hash)] + issue-id hash)] (do (log/debug "PNG found") {:status 200 :content-type "image/png" diff --git a/src/clj/commiteth/routes/redirect.clj b/src/clj/commiteth/routes/redirect.clj index 654d5fa..3249afa 100644 --- a/src/clj/commiteth/routes/redirect.clj +++ b/src/clj/commiteth/routes/redirect.clj @@ -27,10 +27,10 @@ [token] (let [user (github/get-user token) {email :email - user-id :id} user] - (log/debug "get-or-create-user" user) - (or - (users/get-user user-id) + user-id :id} user + db-user (users/get-user user-id)] + (if (:id db-user) + db-user (create-user token user)))) (defroutes redirect-routes diff --git a/src/clj/commiteth/routes/services.clj b/src/clj/commiteth/routes/services.clj index ea4ca0f..e4624d3 100644 --- a/src/clj/commiteth/routes/services.clj +++ b/src/clj/commiteth/routes/services.clj @@ -19,7 +19,8 @@ [clojure.tools.logging :as log] [commiteth.config :refer [env]] [commiteth.util.util :refer [usd-decimal->str - eth-decimal->str]] + eth-decimal->str + to-db-map]] [crypto.random :as random] [clojure.set :refer [rename-keys]] [clojure.string :as str] @@ -67,27 +68,14 @@ (def bounty-renames ;; TODO this needs to go away ASAP we need to be super consistent ;; about keys unless we will just step on each others toes constantly - {:user_name :display-name - :user_avatar_url :avatar-url - :issue_title :issue-title - :pr_title :pr-title - :pr_number :pr-number - :pr_id :pr-id - :type :item-type - :repo_name :repo-name - :repo_owner :repo-owner - :owner_login :owner-login - :issue_number :issue-number - :issue_id :issue-id - :value_usd :value-usd - :claim_count :claim-count - :balance_eth :balance-eth - :user_has_address :user-has-address}) + {:user-name :display-name + :user-avatar-url :avatar-url + :type :item-type}) (defn ^:private enrich-owner-bounties [owner-bounty] (let [claims (map - #(update % :value_usd usd-decimal->str) - (bounties-db/bounty-claims (:issue_id owner-bounty))) + #(update % :value-usd usd-decimal->str) + (bounties-db/bounty-claims (:issue-id owner-bounty))) with-claims (assoc owner-bounty :claims claims)] (-> with-claims (rename-keys bounty-renames) @@ -103,9 +91,7 @@ (into {})))) (defn top-hunters [] - (let [renames {:user_name :display-name - :avatar_url :avatar-url - :total_usd :total-usd}] + (let [renames {:user-name :display-name}] (map #(-> % (rename-keys renames) (update :total-usd usd-decimal->str)) @@ -163,11 +149,8 @@ (defn execute-revocation [issue-id contract-address payout-address] (log/info (str "executing revocation for " issue-id "at" contract-address)) (try - (let [tx-info (multisig/send-all {:contract contract-address - :payout-address payout-address - :internal-tx-id [:execute issue-id]})] - (tracker/track-tx! tx-info) - {:execute-hash (:tx-hash tx-info)}) + (let [tx-info (bounties/execute-payout issue-id contract-address payout-address)] + (:tx-hash tx-info)) (catch Throwable ex (log/errorf ex "error revoking funds for %s" issue-id)))) @@ -212,11 +195,11 @@ :auth-rules authenticated? :current-user user :body [body {:address s/Str - :is_hidden_in_hunters s/Bool}] + :is-hidden-in-hunters s/Bool}] :summary "Updates user's fields." (let [user-id (:id user) - {:keys [address]} body] + {:keys [address is-hidden-in-hunters]} body] (when-not (eth/valid-address? address) (log/debugf "POST /user: Wrong address %s" address) @@ -225,7 +208,8 @@ (db/with-tx (when-not (db/user-exists? {:id user-id}) (not-found! "No such a user.")) - (db/update! :users body ["id = ?" user-id])) + (db/update! :users (to-db-map address is-hidden-in-hunters) + ["id = ?" user-id])) (ok))) @@ -261,9 +245,9 @@ (POST "/revoke" {{issue-id :issue-id} :params} :auth-rules authenticated? :current-user user - (let [{contract-address :contract_address owner-address :owner_address} (issues/get-issue-by-id issue-id)] + (let [{:keys [contract-address owner-address]} (issues/get-issue-by-id issue-id)] (do (log/infof "calling revoke-initiate for %s with %s %s" issue-id contract-address owner-address) - (if-let [{:keys [execute-hash]} (execute-revocation issue-id contract-address owner-address)] + (if-let [execute-hash (execute-revocation issue-id contract-address owner-address)] (ok {:issue-id issue-id :execute-hash execute-hash :contract-address contract-address}) diff --git a/src/clj/commiteth/routes/webhooks.clj b/src/clj/commiteth/routes/webhooks.clj index dff53a7..f6b9351 100644 --- a/src/clj/commiteth/routes/webhooks.clj +++ b/src/clj/commiteth/routes/webhooks.clj @@ -125,8 +125,8 @@ :pr_number pr-number :title pr-title :user_id user-id - :issue_number (:issue_number issue) - :issue_id (:issue_id issue) + :issue_number (:issue-number issue) + :issue_id (:issue-id issue) :state event-type}] ;; TODO: in the opened case if the submitting user has no ;; Ethereum address stored, we could post a comment to the @@ -134,17 +134,17 @@ ;; merged (cond open-or-edit? (do - (log/infof "issue %s: PR with reference to bounty issue opened" (:issue_number issue)) + (log/infof "issue %s: PR with reference to bounty issue opened" (:issue-number issue)) (pull-requests/save (merge pr-data {:state :opened :commit_sha head-sha}))) close? (if merged? - (do (log/infof "issue %s: PR with reference to bounty issue merged" (:issue_number issue)) + (do (log/infof "issue %s: PR with reference to bounty issue merged" (:issue-number issue)) (pull-requests/save (merge pr-data {:state :merged :commit_sha head-sha})) - (issues/update-commit-sha (:issue_id issue) head-sha) - (db-bounties/update-winner-login (:issue_id issue) login)) - (do (log/infof "issue %s: PR with reference to bounty issue closed with no merge" (:issue_number issue)) + (issues/update-commit-sha (:issue-id issue) head-sha) + (db-bounties/update-winner-login (:issue-id issue) login)) + (do (log/infof "issue %s: PR with reference to bounty issue closed with no merge" (:issue-number issue)) (pull-requests/save (merge pr-data {:state :closed :commit_sha head-sha}))))))) @@ -177,7 +177,7 @@ (doseq [issue issues] (if-not (:commit_sha issue) ; no PR has been merged yet referencing this issue (do - (log/info "Referenced bounty issue found" owner repo (:issue_number issue)) + (log/info "Referenced bounty issue found" owner repo (:issue-number issue)) (handle-claim issue user-id login name diff --git a/src/clj/commiteth/scheduler.clj b/src/clj/commiteth/scheduler.clj index 27d5412..f823721 100644 --- a/src/clj/commiteth/scheduler.clj +++ b/src/clj/commiteth/scheduler.clj @@ -2,9 +2,10 @@ (:require [commiteth.eth.core :as eth] [commiteth.eth.multisig-wallet :as multisig] [commiteth.eth.token-data :as token-data] - [commiteth.eth.tracker :as tracker] [commiteth.github.core :as github] [commiteth.db.issues :as issues] + [commiteth.eth.tracker :as tracker] + [commiteth.util.util :refer [to-map]] [taoensso.tufte :as tufte :refer (defnp p profiled profile)] [commiteth.db.bounties :as db-bounties] [commiteth.bounties :as bounties] @@ -12,6 +13,7 @@ [commiteth.util.util :as util] [clojure.tools.logging :as log] [mount.core :as mount] + [clojure.string :as str] [clj-time.core :as t] [clj-time.coerce :as time-coerce] [clj-time.periodic :refer [periodic-seq]] @@ -30,12 +32,10 @@ (profile {} (update-watch-hash)) (profile {} (update-payout-receipt)) (profile {} (update-contract-internal-balances)) - (profile {} (update-open-issue-usd-values)) (profile {} (update-balances)) (profile {} (doseq [i (range 5)] (update-contract-internal-balances) - (update-open-issue-usd-values) (update-balances))) ) @@ -46,43 +46,16 @@ [] (log/info "In update-issue-contract-address") (p :update-issue-contract-address - (doseq [{issue-id :issue_id - transaction-hash :transaction_hash} (issues/list-pending-deployments)] + (doseq [{:keys [issue-id transaction-hash] :as issue} (issues/list-pending-deployments)] (log/infof "issue %s: pending deployment: %s" issue-id transaction-hash) (try (when-let [receipt (eth/get-transaction-receipt transaction-hash)] (log/infof "issue %s: update-issue-contract-address: tx receipt: %s" issue-id receipt) (if-let [contract-address (multisig/find-created-multisig-address receipt)] - (let [_ (tracker/untrack-tx! {:issue-id issue-id - :tx-hash transaction-hash - :result contract-address - :type :deploy}) - {owner :owner - repo :repo - comment-id :comment_id - issue-number :issue_number} (issues/get-issue-by-id issue-id) - balance-eth-str (eth/get-balance-eth contract-address 6) - balance-eth (read-string balance-eth-str)] - (log/infof "issue %s: Updating comment image" issue-id) - (bounties/update-bounty-comment-image issue-id - owner - repo - issue-number - contract-address - balance-eth - balance-eth-str - {}) - (log/infof "issue %s: Updating comment" issue-id) - (github/update-comment owner - repo - comment-id - issue-number - contract-address - balance-eth - balance-eth-str - {})) + (bounties/transition (assoc issue :contract-address contract-address) + :opened) (log/errorf "issue %s: Failed to find contract address in tx logs" issue-id))) - (catch Throwable ex + (catch Throwable ex (log/errorf ex "issue %s: update-issue-contract-address exception:" issue-id))))) (log/info "Exit update-issue-contract-address")) @@ -93,8 +66,8 @@ label is addded to an issue. This function deploys such contracts." [] (p :deploy-pending-contracts - (doseq [{issue-id :issue_id - owner-address :owner_address} (db-bounties/pending-contracts)] + (doseq [{:keys [issue-id owner-address]} + (db-bounties/pending-contracts)] (log/infof "issue %s: Trying to re-deploy failed bounty contract deployment" issue-id) (try (bounties/deploy-contract owner-address issue-id) @@ -106,72 +79,48 @@ [] (log/info "In self-sign-bounty") (p :self-sign-bounty - (doseq [{contract-address :contract_address - issue-id :issue_id - payout-address :payout_address - repo :repo - owner :owner - comment-id :comment_id - issue-number :issue_number - balance-eth :balance_eth - tokens :tokens - winner-login :winner_login} (db-bounties/pending-bounties)] + (doseq [{:keys [contract-address winner-address issue-id] :as issue} + (db-bounties/pending-bounties)] (try ;; TODO(martin) delete this shortly after org-dashboard deploy ;; as we're now setting `winner_login` when handling a new claims ;; coming in via webhooks (see `commiteth.routes.webhooks/handle-claim`) - (db-bounties/update-winner-login issue-id winner-login) - (let [value (eth/get-balance-hex contract-address)] - (if (empty? payout-address) - (do - (log/warn "issue %s: Cannot sign pending bounty - winner (%s) has no payout address" issue-id winner-login) - (github/update-merged-issue-comment owner - repo - comment-id - contract-address - (util/eth-decimal->str balance-eth) - tokens - winner-login - true)) - (let [tx-info (multisig/send-all {:contract contract-address - :payout-address payout-address - :internal-tx-id [:execute issue-id]})] - (log/infof "issue %s: Payout self-signed, called sign-all(%s) tx: %s" issue-id contract-address payout-address (:tx-hash tx-info)) - (tracker/track-tx! tx-info) - (github/update-merged-issue-comment owner - repo - comment-id - contract-address - (util/eth-decimal->str balance-eth) - tokens - winner-login - false)))) - (catch Throwable ex - (log/errorf ex "issue %s: self-sign-bounty exception" issue-id))))) + ;(db-bounties/update-winner-login issue-id winner-login) + (bounties/execute-payout issue-id contract-address winner-address) + (catch Throwable ex + (log/error ex "issue %s: self-sign-bounty exception" issue-id))))) (log/info "Exit self-sign-bounty")) (defn update-confirm-hash + "Gets transaction receipt for each pending payout and updates DB confirm_hash with tranaction ID of commiteth bot account's confirmation." [issue-id execute-hash] - (log/infof "issue %s: pending payout: %s" issue-id execute-hash) - (try - (when-let [receipt (eth/get-transaction-receipt execute-hash)] - (log/infof "issue %s: execution receipt for issue " issue-id receipt) - (when-let [confirm-hash (multisig/find-confirmation-tx-id receipt)] - (log/infof "issue %s: confirm hash:%s" issue-id confirm-hash) - (tracker/untrack-tx! {:issue-id issue-id - :tx-hash execute-hash - :result confirm-hash - :type :execute}))) - (catch Throwable ex - (log/errorf ex "issue %s: update-confirm-hash exception:" issue-id)))) + (log/info "In update-confirm-hash") + (p :update-confirm-hash + (try + (log/infof "issue %s: pending payout: %s" issue-id execute-hash) + (when-let [receipt (eth/get-transaction-receipt execute-hash)] + (log/infof "issue %s: execution receipt for issue " issue-id receipt) + (when-let [confirm-hash (multisig/find-confirmation-tx-id receipt)] + (log/infof "issue %s: confirm hash: %s" issue-id confirm-hash) + (bounties/transition {:issue-id issue-id + :confirm-hash confirm-hash + :tx-info {:issue-id issue-id + :tx-hash execute-hash + :result confirm-hash + :type :execute}} + :pending-maintainer-confirmation) + + )) + (catch Throwable ex + (log/errorf ex "issue %s: update-confirm-hash exception:" issue-id))) + (log/info "Exit update-confirm-hash"))) (defn update-confirm-hashes "Gets transaction receipt for each pending payout and updates DB confirm_hash with tranaction ID of commiteth bot account's confirmation." [] (log/info "In update-confirm-hashes") (p :update-confirm-hash - (doseq [{issue-id :issue_id - execute-hash :execute_hash} (db-bounties/pending-payouts)] + (doseq [{:keys [issue-id execute-hash]} (db-bounties/pending-payouts)] (update-confirm-hash issue-id execute-hash))) (log/info "Exit update-confirm-hashes")) @@ -180,17 +129,19 @@ "Sets watch-hash to NULL for bounties where watch tx has been mined. Used to avoid unneeded watch transactions in update-bounty-token-balances" [] (p :update-watch-hash - (doseq [{issue-id :issue_id - watch-hash :watch_hash} (db-bounties/pending-watch-calls)] + (doseq [{:keys [issue-id watch-hash]} (db-bounties/pending-watch-calls)] (log/infof "issue %s: pending watch call %s" issue-id watch-hash) - (try + (try (when-let [receipt (eth/get-transaction-receipt watch-hash)] - (tracker/untrack-tx! {:issue-id issue-id - :tx-hash watch-hash - :result nil - :type :watch})) + (bounties/transition {:issue-id issue-id + :tx-info + {:issue-id issue-id + :tx-hash watch-hash + :result nil + :type :watch}} :watch-reset)) (catch Throwable ex - (log/errorf ex "issue %s: update-watch-hash exception:" issue-id)))))) + (log/errorf ex "issue %s: update-watch-hash exception:" issue-id)) + )))) (defn older-than-3h? @@ -201,50 +152,34 @@ (println "hour diff:" diff) (> diff 3))) -(defn update-payout-receipt [bounty] +(defn update-payout-receipt + "Gets transaction receipt for each confirmed payout and updates payout_hash" + [{:keys [payout-hash contract-address confirm-hash issue-id updated] :as bounty}] {:pre [(util/contains-all-keys bounty db-bounties/payout-receipt-keys)]} - (let [{issue-id :issue_id - payout-hash :payout_hash - contract-address :contract_address - repo :repo - owner :owner - comment-id :comment_id - issue-number :issue_number - balance-eth :balance_eth - tokens :tokens - confirm-hash :confirm_hash - payee-login :payee_login - updated :updated} bounty] - (log/infof "issue %s: confirmed payout: %s" issue-id payout-hash) - (try - (if-let [receipt (eth/get-transaction-receipt payout-hash)] - (let [contract-tokens (multisig/token-balances contract-address) - contract-eth-balance (eth/get-balance-wei contract-address)] - (if (or - (some #(> (second %) 0.0) contract-tokens) - (> contract-eth-balance 0)) - (do - (log/infof "issue %s: Contract (%s) still has funds" issue-id contract-address) - (when (multisig/is-confirmed? contract-address confirm-hash) - (log/infof "issue %s: Detected bounty with funds and confirmed payout, calling executeTransaction" issue-id) - (let [execute-tx-hash (multisig/execute-tx contract-address confirm-hash)] - (log/infof "issue %s: execute tx: %s" issue-id execute-tx-hash)))) - - (do - (log/infof "issue %s: Payout has succeeded, payout receipt %s" issue-id receipt) - (db-bounties/update-payout-receipt issue-id receipt) - (github/update-paid-issue-comment owner - repo - comment-id - contract-address - (util/eth-decimal->str balance-eth) - tokens - payee-login)))) - (when (older-than-3h? updated) - (log/warn "issue %s: Resetting payout hash for issue as it has not been mined in 3h" issue-id) - (db-bounties/reset-payout-hash issue-id))) - (catch Throwable ex - (log/error ex "issue %s: update-payout-receipt exception" issue-id))))) + (log/info "In update-payout-receipt") + (p :update-payout-receipt + (try + (log/infof "issue %s: confirmed payout: %s" issue-id payout-hash) + (if-let [receipt (eth/get-transaction-receipt payout-hash)] + (let [contract-tokens (multisig/token-balances contract-address) + contract-eth-balance (eth/get-balance-wei contract-address)] + (if (or + (some #(> (second %) 0.0) contract-tokens) + (> contract-eth-balance 0)) + (do + (log/infof "issue %s: Contract (%s) still has funds" issue-id contract-address) + (when (multisig/is-confirmed? contract-address confirm-hash) + (log/infof "issue %s: Detected bounty with funds and confirmed payout, calling executeTransaction" issue-id) + (let [execute-tx-hash (multisig/execute-tx contract-address confirm-hash)] + (log/infof "issue %s: execute tx: %s" issue-id execute-tx-hash)))) + (do + (log/infof "issue %s: Payout has succeeded, payout receipt %s" issue-id receipt) + (bounties/transition (assoc bounty :payout-receipt receipt) :paid)))) + (when (older-than-3h? updated) + (log/warn "issue %s: Resetting payout hash for issue as it has not been mined in 3h" issue-id) + (db-bounties/reset-payout-hash issue-id))) + (catch Throwable ex + (log/error ex "issue %s: update-payout-receipt exception" issue-id))))) (defn update-payout-receipts "Gets transaction receipt for each confirmed payout and updates payout_hash" @@ -274,7 +209,6 @@ (neg? n) (- n) :else n)) - (defn update-bounty-token-balances "Helper function for updating internal ERC20 token balances to token multisig contract. Will be called periodically for all open bounty @@ -294,7 +228,9 @@ (let [tx-info (multisig/watch-token {:bounty-addr bounty-addr :token tla :internal-tx-id [:watch issue-id]})] - (tracker/track-tx! tx-info))))))) + (bounties/transition {:issue-id issue-id + :tx-info tx-info} + :watch-set))))))) (catch Throwable ex (log/error ex "bounty %s: update-bounty-token-balances exception" bounty-addr)))) (log/info "Exit update-bounty-token-balances")) @@ -305,39 +241,11 @@ [] (log/info "In update-contract-internal-balances") (p :update-contract-internal-balances - (doseq [{issue-id :issue_id - bounty-address :contract_address - watch-hash :watch_hash} + (doseq [{:keys [issue-id contract-address watch-hash]} (db-bounties/open-bounty-contracts)] - (update-bounty-token-balances issue-id bounty-address watch-hash))) + (update-bounty-token-balances issue-id contract-address watch-hash))) (log/info "Exit update-contract-internal-balances")) -(defn get-bounty-funds - "Get funds in given bounty contract. - Returns map of asset -> balance - + key total-usd -> current total USD value for all funds" - [bounty-addr] - (let [token-balances (multisig/token-balances bounty-addr) - eth-balance (read-string (eth/get-balance-eth bounty-addr 6)) - all-funds - (merge token-balances - {:ETH eth-balance})] - (merge all-funds {:total-usd (fiat-util/bounty-usd-value all-funds)}))) - - -(defn update-issue-usd-value - [bounty-addr] - (let [funds (get-bounty-funds bounty-addr)] - (issues/update-usd-value bounty-addr - (:total-usd funds)))) - -(defn update-open-issue-usd-values - "Sum up current USD values of all crypto assets in a bounty and store to DB" - [] - (p :update-open-issue-usd-values - (doseq [{bounty-addr :contract_address} - (db-bounties/open-bounty-contracts)] - (update-issue-usd-value bounty-addr)))) (defn float= ([x y] (float= x y 0.0000001)) @@ -350,58 +258,45 @@ (and (= (set (keys m1)) (set (keys m2))) (every? #(float= (get m1 %1) (get m2 %1)) (keys m1)))) + (defn update-balances [] (log/info "In update-balances") (p :update-balances - (doseq [{contract-address :contract_address - owner :owner - repo :repo - comment-id :comment_id - issue-id :issue_id - db-balance-eth :balance_eth - db-tokens :tokens - issue-number :issue_number} (db-bounties/open-bounty-contracts)] - (try - (when comment-id - (let [balance-eth-str (eth/get-balance-eth contract-address 6) - balance-eth (read-string balance-eth-str) - token-balances (multisig/token-balances contract-address)] - (log/debug "issue" issue-id ": update-balances" balance-eth - balance-eth-str token-balances owner repo issue-number) + (doseq [{:keys [contract-address owner + repo balance-eth tokens + issue-id + issue-number + comment-id] :as issue} + (db-bounties/open-bounty-contracts)] + (try + (when comment-id + (let [balance-eth-str (eth/get-balance-eth contract-address 6) + current-balance-eth (read-string balance-eth-str) + token-balances (multisig/token-balances contract-address)] + (log/debug "update-balances" balance-eth + balance-eth-str token-balances owner repo issue-number) - (when (or - (not (float= db-balance-eth balance-eth)) - (not (map-float= db-tokens token-balances))) - (log/info "balances differ") - (log/info "ETH (db):" db-balance-eth (type db-balance-eth) ) - (log/info "ETH (chain):" balance-eth (type balance-eth) ) - (log/info "ETH cmp:" (float= db-balance-eth balance-eth)) - (log/info "tokens (db):" db-tokens (type db-tokens) (type (:SNT db-tokens))) - (log/info "tokens (chain):" token-balances (type token-balances) (type (:SNT token-balances))) - (log/debug "tokens cmp:" (= db-tokens token-balances)) + (when (or + (not (float= current-balance-eth balance-eth)) + (not (map-float= tokens token-balances))) + (log/info "balances differ") + (log/info "ETH (db):" balance-eth (type balance-eth) ) + (log/info "ETH (chain):" current-balance-eth (type current-balance-eth) ) + (log/info "ETH cmp:" (float= balance-eth current-balance-eth)) + (log/info "tokens (db):" tokens (type tokens) (type (:SNT tokens))) + (log/info "tokens (chain):" token-balances (type token-balances) (type (:SNT token-balances))) + (log/debug "tokens cmp:" (= tokens token-balances)) + (bounties/transition {:issue-id issue-id + :balance-eth current-balance-eth + :tokens token-balances + :value-usd (fiat-util/bounty-usd-value + (merge token-balances {:ETH current-balance-eth}))} :update-balances) - (issues/update-eth-balance contract-address balance-eth) - (issues/update-token-balances contract-address token-balances) - (bounties/update-bounty-comment-image issue-id - owner - repo - issue-number - contract-address - balance-eth - balance-eth-str - token-balances) - (github/update-comment owner - repo - comment-id - issue-number - contract-address - balance-eth - balance-eth-str - token-balances) - (update-issue-usd-value contract-address)))) - (catch Throwable ex - (log/error ex "issue %s: update-balances exception" issue-id))))) + + ))) + (catch Throwable ex + (log/error ex "issue %s: update-balances exception" issue-id))))) (log/info "Exit update-balances")) (defn check-tx-receipts @@ -446,8 +341,7 @@ (log/info "run-10-min-interval-tasks" time) (run-tasks [update-contract-internal-balances - update-balances - update-open-issue-usd-values]) + update-balances]) (log/info "run-10-min-interval-tasks done"))) diff --git a/src/clj/commiteth/util/png_rendering.clj b/src/clj/commiteth/util/png_rendering.clj index 997ad5a..1bd31aa 100644 --- a/src/clj/commiteth/util/png_rendering.clj +++ b/src/clj/commiteth/util/png_rendering.clj @@ -1,7 +1,6 @@ (ns commiteth.util.png-rendering (:require [commiteth.layout :refer [render]] [commiteth.config :refer [env]] - [commiteth.github.core :as github] [commiteth.db.comment-images :as db] [commiteth.db.bounties :as db-bounties] [clj.qrgen :as qr] @@ -58,21 +57,6 @@ nil)))) -(defn export-comment-image - "Retrieve image PNG from DB and write to file" - [owner repo issue-number filename] - (let [{owner :owner - repo :repo - issue-id :issue_id - balance-eth :balance_eth} (db-bounties/get-bounty owner repo issue-number) - hash (github/github-comment-hash - owner - repo - issue-number - balance-eth)] - (with-open [w (io/output-stream filename)] - (.write w (:png_data (db/get-image-data issue-id hash)))))) - (comment (with-open [w (io/output-stream "foo.png")] diff --git a/src/clj/commiteth/util/util.clj b/src/clj/commiteth/util/util.clj index e4f3f6d..9fd8483 100644 --- a/src/clj/commiteth/util/util.clj +++ b/src/clj/commiteth/util/util.clj @@ -1,6 +1,7 @@ (ns commiteth.util.util (:require [clj-http.client :as http] + [clojure.string :as str] [clojure.data.json :as json])) @@ -15,7 +16,13 @@ (:body) (json/read-str))) +(defmacro to-map [& vars] + (into {} (map #(vector (keyword %1) %1) vars))) + +(defmacro to-db-map [& vars] + (into {} (map #(vector (keyword (str/replace (name %1) "-" "_")) %1) vars))) + (defn contains-all-keys [m ks] {:pre [(map? m) [(vector? ks)]]} (every? - #(contains? m %) ks)) + #(contains? m %) ks)) diff --git a/src/cljc/commiteth/model/bounty.cljc b/src/cljc/commiteth/model/bounty.cljc index e55579f..6141a33 100644 --- a/src/cljc/commiteth/model/bounty.cljc +++ b/src/cljc/commiteth/model/bounty.cljc @@ -11,20 +11,20 @@ ;; to communicate what datatypes are returned where. (defn open? [claim] - (assert (find claim :pr_state)) - (= 0 (:pr_state claim))) + (assert (find claim :pr-state)) + (= 0 (:pr-state claim))) (defn merged? [claim] - (assert (find claim :pr_state)) - (= 1 (:pr_state claim))) + (assert (find claim :pr-state)) + (= 1 (:pr-state claim))) (defn paid? [claim] - (assert (find claim :payout_hash)) - (not-empty (:payout_hash claim))) + (assert (find claim :payout-hash)) + (not-empty (:payout-hash claim))) (defn bot-confirm-unmined? [bounty] - (assert (find bounty :confirm_hash)) - (empty? (:confirm_hash bounty))) + (assert (find bounty :confirm-hash)) + (empty? (:confirm-hash bounty))) (defn confirming? [bounty] (:confirming? bounty)) diff --git a/src/cljs/commiteth/bounties.cljs b/src/cljs/commiteth/bounties.cljs index cd6d596..0970cc4 100644 --- a/src/cljs/commiteth/bounties.cljs +++ b/src/cljs/commiteth/bounties.cljs @@ -45,7 +45,7 @@ (defn bounty-item [bounty] (let [open-bounty-claims (rf/subscribe [::subs/open-bounty-claims])] (fn [bounty] - (let [{avatar-url :repo_owner_avatar_url + (let [{avatar-url :repo-owner-avatar-url owner :repo-owner repo-name :repo-name issue-title :issue-title diff --git a/src/cljs/commiteth/handlers.cljs b/src/cljs/commiteth/handlers.cljs index 56bef55..76bb1ef 100644 --- a/src/cljs/commiteth/handlers.cljs +++ b/src/cljs/commiteth/handlers.cljs @@ -484,10 +484,11 @@ (reg-event-fx :confirm-payout interceptors - (fn [{:keys [db]} [_ {issue-id :issue_id - owner-address :owner_address - contract-address :contract_address - confirm-hash :confirm_hash} issue]] + (fn [{:keys [db]} [_ {:keys [issue-id + owner-address + contract-address + confirm-hash] + :as issue}]] (println (:web3 db)) (let [w3 (:web3 db) pending-revocations (::db/pending-revocations db) diff --git a/src/cljs/commiteth/interceptors.cljs b/src/cljs/commiteth/interceptors.cljs index 9016329..0f639af 100644 --- a/src/cljs/commiteth/interceptors.cljs +++ b/src/cljs/commiteth/interceptors.cljs @@ -12,10 +12,7 @@ (defn dispatch-confirm-payout [bounty] "dispatches a bounty via reframe dispatch" - (rf/dispatch [:confirm-payout {:issue_id (:issue-id bounty) - :owner_address (:owner_address bounty) - :contract_address (:contract_address bounty) - :confirm_hash (:confirm_hash bounty)}])) + (rf/dispatch [:confirm-payout bounty])) (defn dispatch-set-pending-revocation [bounty] "update the currently confirming account to owner" @@ -45,7 +42,7 @@ updated-bounties (get-in context [:effects :db :owner-bounties]) confirming-issue-id (get-confirming-issue-id :commiteth pending-revocations)] (when-let [revoking-bounty (get updated-bounties confirming-issue-id)] - (if (:confirm_hash revoking-bounty) + (if (:confirm-hash revoking-bounty) (do (dispatch-confirm-payout revoking-bounty) (dispatch-set-pending-revocation revoking-bounty)) (println (str "currently revoking " confirming-issue-id " but confirm hash has not been set yet.")))) @@ -72,7 +69,7 @@ updated-bounties (get-in context [:effects :db :owner-bounties]) confirming-issue-id (get-confirming-issue-id :owner pending-revocations)] (when-let [revoking-bounty (get updated-bounties confirming-issue-id)] - (if (:payout_receipt revoking-bounty) + (if (:payout-receipt revoking-bounty) (dispatch-remove-pending-revocation revoking-bounty) (println (str "currently revoking " confirming-issue-id " but payout receipt has not been set yet.")))) ;; interceptor must return context diff --git a/src/cljs/commiteth/manage_payouts.cljs b/src/cljs/commiteth/manage_payouts.cljs index a9e48ac..fad64e7 100644 --- a/src/cljs/commiteth/manage_payouts.cljs +++ b/src/cljs/commiteth/manage_payouts.cljs @@ -9,9 +9,9 @@ [commiteth.config :as config] [commiteth.common :as common :refer [human-time]])) -(defn pr-url [{owner :repo_owner - pr-number :pr_number - repo :repo_name}] +(defn pr-url [{owner :repo-owner + pr-number :pr-number + repo :repo-name}] (str "https://github.com/" owner "/" repo "/pull/" pr-number)) (defn etherscan-tx-url [tx-id] @@ -57,7 +57,7 @@ (when (and merged? (not paid?)) [primary-button-button (merge {:on-click #(rf/dispatch [:confirm-payout claim])} - (if (and merged? (not paid?) (:payout_address bounty)) + (if (and merged? (not paid?) (:payout-address bounty)) {} {:disabled true}) (when (and (or (bnt/confirming? bounty) @@ -71,11 +71,11 @@ (defn confirm-row [bounty claim] - (let [payout-address-available? (:payout_address bounty)] + (let [payout-address-available? (:payout-address bounty)] [:div (when-not payout-address-available? [:div.bg-sob-blue-o-20.pv2.ph3.br3.mb3.f6 - [:p [:span.pg-med (or (:user_name claim) (:user_login claim)) + [:p [:span.pg-med (or (:user-name claim) (:user-login claim)) "’s payment address is pending."] " You will be able to confirm the payment once the address is provided."]]) [:div.cf [:div.dt.fr @@ -97,10 +97,10 @@ "View Pull Request"]) (defn claim-card [bounty claim {:keys [render-view-claim-button?] :as opts}] - (let [{user-name :user_name - user-login :user_login - avatar-url :user_avatar_url} claim - winner-login (:winner_login bounty)] + (let [{user-name :user-name + user-login :user-login + avatar-url :user-avatar-url} claim + winner-login (:winner-login bounty)] [:div.pv2 [:div.flex {:class (when (and (bnt/paid? claim) (not (= user-login winner-login))) @@ -118,7 +118,7 @@ [:span "No payout"]))] [:div.f6.gray "Submitted a claim via " [:a.gray {:href (pr-url claim)} - (str (:repo_owner claim) "/" (:repo_name claim) " PR #" (:pr_number claim))]] + (str (:repo-owner claim) "/" (:repo-name claim) " PR #" (:pr-number claim))]] ;; We render the button twice for difference screen sizes, first button is for small screens: ;; 1) db + dn-ns: `display: block` + `display: none` for not-small screens ;; 2) dn + db-ns: `display: none` + `display: block` for not-small screens @@ -139,7 +139,7 @@ ;; FIXME we remove all bounties that Andy 'won' as this basically ;; has been our method for revocations. This needs to be cleaned up ASAP. ;; https://github.com/status-im/open-bounty/issues/284 - (for [bounty (filter #(not= "andytudhope" (:winner_login %)) bounties) + (for [bounty (filter #(not= "andytudhope" (:winner-login %)) bounties) ;; Identifying the winning claim like this is a bit ;; imprecise if there have been two PRs for the same ;; bounty by the same contributor @@ -147,8 +147,8 @@ ;; ignore this edge case for a first version :let [winning-claim (->> (:claims bounty) (filter #(and (bnt/merged? %) - (= (:user_login %) - (:winner_login bounty)))) + (= (:user-login %) + (:winner-login bounty)))) util/assert-first)]] ^{:key (:issue-id bounty)} [:div.mb3.br3.shadow-6.bg-white @@ -176,7 +176,7 @@ (str "Current Claims (" (count claims) ")") "Current Claim")] (for [[idx claim] (zipmap (range) claims)] - ^{:key (:pr_id claim)} + ^{:key (:pr-id claim)} [:div {:class (when (> idx 0) "bt b--light-gray pt2")} [claim-card bounty claim {:render-view-claim-button? true}]])]])))) @@ -275,7 +275,7 @@ (let [bounty @(rf/subscribe [:revoke-modal-bounty])] (fn [] (when bounty - (let [owner-address (:owner_address bounty)] + (let [owner-address (:owner-address bounty)] ;; width requires a deliberate override of semantic.min.css [:div.ui.active.modal.br3 {:style {:top 100 :width 650}} @@ -325,7 +325,7 @@ [:div [bounty-title-link bounty {:show-date? false :max-length 60}] [:div.f6.mt1.gray - "Paid out to " [:span.pg-med.fw5 "@" (or (:winner_login bounty) + "Paid out to " [:span.pg-med.fw5 "@" (or (:winner-login bounty) ;; use repo owner for revoked bounties ;; where no winner login is set (:owner-login bounty))]]] @@ -358,17 +358,17 @@ (when @banner-info (into [:div] (for [revoking-bounty @banner-info] - ^{:key (:contract_address revoking-bounty)} + ^{:key (:contract-address revoking-bounty)} [:div.relative.pa3.pr4.bg-sob-green.br3.nt1 [:div (case (:confirming-account revoking-bounty) :commiteth [:p.v-mid [check-box "ic-check-circle-black-24dp-2x.png"] [:span.pg-med "Transaction sent."] " Your refund requires two confirmations. After the first one " - [:a.sob-blue.pg-med {:href (etherscan-address-url (:contract_address revoking-bounty)) :target "_blank"} " completes "] + [:a.sob-blue.pg-med {:href (etherscan-address-url (:contract-address revoking-bounty)) :target "_blank"} " completes "] "you'll be prompted to sign the second via metamask."] :owner [:p.v-mid [check-box "ic-check-circle-black-24dp-2x.png"] [:span.pg-med "Transaction sent."] " Once your metamask transaction is confirmed your revocation will be complete. Follow the final step " - [:a.sob-blue.pg-med {:href (etherscan-address-url (:contract_address revoking-bounty)) :target "_blank"} " here. "]])]])))))) + [:a.sob-blue.pg-med {:href (etherscan-address-url (:contract-address revoking-bounty)) :target "_blank"} " here. "]])]])))))) (defn salute [] (let [msg-info (rf/subscribe [:dashboard/banner-msg])] diff --git a/src/cljs/commiteth/update_address.cljs b/src/cljs/commiteth/update_address.cljs index 870cec4..2484a0d 100644 --- a/src/cljs/commiteth/update_address.cljs +++ b/src/cljs/commiteth/update_address.cljs @@ -10,7 +10,7 @@ (let [db (rf/subscribe [:db]) updating-user (rf/subscribe [:get-in [:updating-user]]) address (r/atom @(rf/subscribe [:get-in [:user :address]])) - hidden (r/atom @(rf/subscribe [:get-in [:user :is_hidden_in_hunters]]))] + hidden (r/atom @(rf/subscribe [:get-in [:user :is-hidden-in-hunters]]))] (fn [] (let [web3 (:web3 @db) @@ -64,7 +64,7 @@ [:button (merge {:on-click #(rf/dispatch [:save-user-fields {:address @address - :is_hidden_in_hunters @hidden}]) + :is-hidden-in-hunters @hidden}]) :disabled (str/blank? @address) :class (str "ui button small update-address-button" (when @updating-user diff --git a/test/clj/commiteth/test/db/core.clj b/test/clj/commiteth/test/db/core.clj index c45b777..6a7cdac 100644 --- a/test/clj/commiteth/test/db/core.clj +++ b/test/clj/commiteth/test/db/core.clj @@ -36,5 +36,5 @@ :address "address" :created nil :welcome_email_sent 0 - :is_hidden_in_hunters false} + :is-hidden-in-hunters false} (db/get-user t-conn {:id 1})))))