mirror of
https://github.com/status-im/open-bounty.git
synced 2025-01-12 10:34:30 +00:00
Re-execute watch if max attempt count exceeded;
block multiple execute tx attempts in case when there are funds still on account (probably due to missing watch invocation); invoke watch synchronously prior to confirming transactions
This commit is contained in:
parent
c1158a187f
commit
90dc8a7534
@ -348,6 +348,7 @@ WHERE issue_id = :issue_id;
|
||||
-- :doc issues with a pending watch transaction
|
||||
SELECT
|
||||
issue_id,
|
||||
contract_address,
|
||||
watch_hash
|
||||
FROM issues
|
||||
WHERE watch_hash IS NOT NULL;
|
||||
|
@ -3,7 +3,9 @@
|
||||
[commiteth.db.users :as users]
|
||||
[commiteth.db.repositories :as repos]
|
||||
[commiteth.db.comment-images :as comment-images]
|
||||
[commiteth.db.bounties :as db-bounties]
|
||||
[commiteth.eth.core :as eth]
|
||||
[commiteth.eth.token-data :as token-data]
|
||||
[commiteth.github.core :as github]
|
||||
[commiteth.eth.multisig-wallet :as multisig]
|
||||
[commiteth.util.png-rendering :as png-rendering]
|
||||
@ -40,6 +42,26 @@
|
||||
(issues/update-transaction-hash issue-id transaction-hash))
|
||||
(log/error "Failed to deploy contract to" owner-address)))))
|
||||
|
||||
(defn watch-tokens [issue-id contract-address watch-hash]
|
||||
"Helper function for updating internal ERC20 token balances to token multisig contract.
|
||||
Will be called periodically for all open bounty contracts, or on-demand via /api/watchTokens endpoint."
|
||||
(try
|
||||
(doseq [[tla token-data] (token-data/as-map)]
|
||||
(let [balance (multisig/token-balance contract-address tla)]
|
||||
(log/info "balance for " tla ":" balance)
|
||||
(when (> balance 0)
|
||||
(do
|
||||
(log/info "bounty at" contract-address "has" balance "of token" tla)
|
||||
(let [internal-balance (multisig/token-balance-in-bounty contract-address tla)]
|
||||
(when (and (nil? watch-hash)
|
||||
(not= balance internal-balance))
|
||||
(log/info "balances not in sync, calling watch")
|
||||
(let [watch-hash (multisig/watch-token contract-address tla)]
|
||||
(db-bounties/update-watch-hash issue-id watch-hash))))))))
|
||||
(catch Throwable ex
|
||||
(log/error "watch-tokens exception:" ex)
|
||||
(clojure.stacktrace/print-stack-trace ex))))
|
||||
|
||||
(defn add-bounty-for-issue [repo repo-id issue]
|
||||
(let [{issue-id :id
|
||||
issue-number :number
|
||||
|
@ -171,6 +171,8 @@
|
||||
(do
|
||||
(log/debug "/usage-metrics" user)
|
||||
(ok (usage-metrics/usage-metrics-by-day))))
|
||||
(POST "/watchTokens" {:keys [params]}
|
||||
(ok (bounties/watch-tokens (:issue_id params) (:contract_address params))))
|
||||
|
||||
(context "/user" []
|
||||
|
||||
|
@ -38,6 +38,8 @@
|
||||
(update-balances)))
|
||||
|
||||
)
|
||||
|
||||
|
||||
(defn update-issue-contract-address
|
||||
"For each pending deployment: gets transaction receipt, updates db
|
||||
state (contract-address, comment-id) and posts github comment"
|
||||
@ -157,15 +159,25 @@
|
||||
(db-bounties/update-confirm-hash issue-id confirm-hash)))))
|
||||
(log/info "Exit update-confirm-hash"))
|
||||
|
||||
;; These define a (contract_addr -> attempt_cnt) map
|
||||
;; used for tracking how many times we have checked for the particular
|
||||
;; watch tx to be mined. If it hasn't been mined after a predefined number of checks,
|
||||
;; reset the counter and schedule it for re-execution in update-contract-internal-balances
|
||||
(def watch-attempts (atom {}))
|
||||
(def max-watch-attempts 5)
|
||||
|
||||
(defn update-watch-hash
|
||||
"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
|
||||
contract-address :contract_address
|
||||
watch-hash :watch_hash} (db-bounties/pending-watch-calls)]
|
||||
(log/info "pending watch call" watch-hash)
|
||||
(when-let [receipt (eth/get-transaction-receipt watch-hash)]
|
||||
(swap! watch-attempts update contract-address #(inc (or %1 0)))
|
||||
(when (or (< max-watch-attempts (get @watch-attempts contract-address 0))
|
||||
(eth/get-transaction-receipt watch-hash))
|
||||
(swap! watch-attempts dissoc contract-address)
|
||||
(db-bounties/update-watch-hash issue-id nil)))))
|
||||
|
||||
|
||||
@ -177,6 +189,13 @@
|
||||
(println "hour diff:" diff)
|
||||
(> diff 3)))
|
||||
|
||||
;; These define a (contract_addr -> attempt_cnt) map
|
||||
;; used for tracking how many times we attempted to withdraw funds from
|
||||
;; a particular account. All attempts above a predefined threshold are blocked,
|
||||
;; as this may ensue in excessive bot fund drainage
|
||||
(def execute-attempts (atom {}))
|
||||
(def max-execute-attempts 3)
|
||||
|
||||
(defn update-payout-receipt
|
||||
"Gets transaction receipt for each confirmed payout and updates payout_hash"
|
||||
[]
|
||||
@ -204,13 +223,17 @@
|
||||
(> contract-eth-balance 0))
|
||||
(do
|
||||
(log/info "Contract still has funds")
|
||||
(if (< (get @execute-attempts contract-address 0) max-execute-attempts)
|
||||
(when (multisig/is-confirmed? contract-address confirm-id)
|
||||
(log/info "Detected bounty with funds and confirmed payout, calling executeTransaction")
|
||||
(let [execute-tx-hash (multisig/execute-tx contract-address confirm-id)]
|
||||
(log/info "execute tx:" execute-tx-hash))))
|
||||
(swap! execute-attempts update contract-address #(inc (or %1 0)))
|
||||
(log/info "execute tx:" execute-tx-hash)))
|
||||
(log/error "Max execute attempt count for " contract-address ", blocked")))
|
||||
|
||||
(do
|
||||
(log/info "Payout has succeeded, saving payout receipt for issue #" issue-id ": " receipt)
|
||||
(swap! execute-attempts dissoc contract-address)
|
||||
(db-bounties/update-payout-receipt issue-id receipt)
|
||||
(github/update-paid-issue-comment owner
|
||||
repo
|
||||
@ -238,28 +261,6 @@
|
||||
: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 contracts."
|
||||
[issue-id bounty-addr watch-hash]
|
||||
#_(log/info "In update-bounty-token-balances for issue" issue-id)
|
||||
(doseq [[tla token-data] (token-data/as-map)]
|
||||
(try
|
||||
(let [balance (multisig/token-balance bounty-addr tla)]
|
||||
(when (> balance 0)
|
||||
(do
|
||||
(log/info "bounty at" bounty-addr "has" balance "of token" tla)
|
||||
(let [internal-balance (multisig/token-balance-in-bounty bounty-addr tla)]
|
||||
(when (and (nil? watch-hash)
|
||||
(not= balance internal-balance))
|
||||
(log/info "balances not in sync, calling watch")
|
||||
(let [hash (multisig/watch-token bounty-addr tla)]
|
||||
(db-bounties/update-watch-hash issue-id hash)))))))
|
||||
(catch Throwable ex
|
||||
(do (log/error "update-bounty-token-balances exception:" ex)
|
||||
(clojure.stacktrace/print-stack-trace ex)))))
|
||||
#_(log/info "Exit update-bounty-token-balances"))
|
||||
|
||||
|
||||
(defn update-contract-internal-balances
|
||||
"It is required in our current smart contract to manually update it's internal balance when some tokens have been added."
|
||||
[]
|
||||
@ -269,7 +270,7 @@
|
||||
bounty-address :contract_address
|
||||
watch-hash :watch_hash}
|
||||
(db-bounties/open-bounty-contracts)]
|
||||
(update-bounty-token-balances issue-id bounty-address watch-hash)))
|
||||
(bounties/watch-tokens issue-id bounty-address watch-hash)))
|
||||
(log/info "Exit update-contract-internal-balances"))
|
||||
|
||||
(defn get-bounty-funds
|
||||
|
@ -399,12 +399,30 @@
|
||||
(defn strip-0x [x]
|
||||
(str/replace x #"^0x" ""))
|
||||
|
||||
(reg-event-fx
|
||||
:watch-and-confirm-payout
|
||||
(fn [{:keys [db]} [_ {issue-id :issue_id
|
||||
contract-address :contract_address
|
||||
:as issue}]]
|
||||
{:db (assoc-in db [:owner-bounties issue-id :confirming?] true)
|
||||
:http {:method POST
|
||||
:url "/api/watchTokens"
|
||||
:params {:contract_address contract-address
|
||||
:issue_id issue-id}
|
||||
:on-success #(dispatch [:confirm-payout issue])
|
||||
:on-error #(do
|
||||
(dispatch [:payout-confirm-failed issue-id %1])
|
||||
(dispatch [:set-flash-message
|
||||
:error
|
||||
(str "Failed to execute watch " %1)]))}}))
|
||||
|
||||
(reg-event-fx
|
||||
:confirm-payout
|
||||
(fn [{:keys [db]} [_ {issue-id :issue_id
|
||||
owner-address :owner_address
|
||||
contract-address :contract_address
|
||||
confirm-hash :confirm_hash} issue]]
|
||||
confirm-hash :confirm_hash
|
||||
:as issue}]]
|
||||
(println (:web3 db))
|
||||
(let [w3 (:web3 db)
|
||||
confirm-method-id (sig->method-id w3 "confirmTransaction(uint256)")
|
||||
@ -417,11 +435,10 @@
|
||||
:gas-price 20000000000
|
||||
:value 0
|
||||
:data data}]
|
||||
(println "data:" data)
|
||||
(try
|
||||
(web3-eth/send-transaction! w3 payload
|
||||
(send-transaction-callback issue-id))
|
||||
{:db (assoc-in db [:owner-bounties issue-id :confirming?] true)}
|
||||
{:db db}
|
||||
(catch js/Error e
|
||||
{:db (assoc-in db [:owner-bounties issue-id :confirm-failed?] true)
|
||||
:dispatch-n [[:payout-confirm-failed issue-id e]
|
||||
|
@ -38,7 +38,7 @@
|
||||
(merge (if (and merged? (not paid?))
|
||||
{}
|
||||
{:disabled true})
|
||||
{:on-click #(rf/dispatch [:confirm-payout claim])}
|
||||
{:on-click #(rf/dispatch [:watch-and-confirm-payout claim])}
|
||||
(when (and (or confirming? bot-confirm-unmined?)
|
||||
merged?)
|
||||
{:class "busy loading" :disabled true}))
|
||||
|
Loading…
x
Reference in New Issue
Block a user