Skip to content

Commit

Permalink
[refactor] remove ethereum call and call-params
Browse files Browse the repository at this point in the history
- use `json-rpc/eth-call` and `json-rpc/eth-transaction-call`
everywhere
- move all conversions to abi-spec
  • Loading branch information
yenda committed May 20, 2019
1 parent 2c8770f commit a56b811
Show file tree
Hide file tree
Showing 18 changed files with 509 additions and 481 deletions.
64 changes: 10 additions & 54 deletions src/status_im/ethereum/contracts.cljs
Original file line number Diff line number Diff line change
@@ -1,61 +1,17 @@
(ns status-im.ethereum.contracts
(:require [re-frame.core :as re-frame]
[status-im.utils.ethereum.abi-spec :as abi-spec]
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.fx :as fx]
[status-im.utils.money :as money]
[status-im.wallet.core :as wallet]))
(:require [status-im.utils.ethereum.core :as ethereum]))

(def contracts
{:status/tribute-to-talk
{:address
{:mainnet nil
:testnet "0x3da3fc53e24707f36c5b4433b442e896c4955f0e"
:rinkeby nil}
:methods
{:get-manifest
{:signature "getManifest(address)"
:outputs ["bytes"]}
:set-manifest
{:signature "setManifest(bytes)"
:write? true}}}})
{:status/snt
{:mainnet "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
:testnet "0xc55cf4b03948d7ebc8b9e8bad92643703811d162"}
:status/tribute-to-talk
{:testnet "0x3da3fc53e24707f36c5b4433b442e896c4955f0e"}
:status/stickers
{:testnet "0x39d16CdB56b5a6a89e1A397A13Fe48034694316E"}})

(re-frame/reg-fx
::call
(fn [{:keys [address data callback]}]
(ethereum/call {:to address
:data data}
callback)))

(defn get-contract-address
(defn get-address
[db contract]
(let [chain-keyword (-> (get-in db [:account/account :networks (:network db)])
ethereum/network->chain-keyword)]
(get-in contracts [contract :address chain-keyword])))

(fx/defn call
[{:keys [db] :as cofx}
{:keys [contract contract-address method params
callback on-result on-error details]}]
(when-let [contract-address (or contract-address
(get-contract-address db contract))]
(let [{:keys [signature outputs write?]}
(get-in contracts [contract :methods method])
data (abi-spec/encode signature params)]
(if write?
(wallet/open-sign-transaction-flow
cofx
(merge {:to contract-address
:data data
:id "approve"
:symbol :ETH
:method "eth_sendTransaction"
:amount (money/bignumber 0)
:on-result on-result
:on-error on-error}
details))
{::call {:address contract-address
:data data
:callback #(callback (if (empty? outputs)
%
(abi-spec/decode % outputs)))}}))))
(get-in contracts [contract chain-keyword])))
258 changes: 148 additions & 110 deletions src/status_im/stickers/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,94 @@
[re-frame.core :as re-frame]
[status-im.accounts.core :as accounts]
[status-im.constants :as constants]
[status-im.ethereum.contracts :as contracts]
[status-im.ethereum.json-rpc :as json-rpc]
[status-im.ui.screens.navigation :as navigation]
[status-im.utils.ethereum.abi-spec :as abi-spec]
[status-im.utils.ethereum.core :as ethereum]
[status-im.utils.ethereum.stickers :as ethereum.stickers]
[status-im.utils.fx :as fx]
[status-im.utils.money :as money]
[status-im.utils.multihash :as multihash]
[status-im.utils.utils :as utils]
[status-im.wallet.core :as wallet]))

(fx/defn init-stickers-packs [{:keys [db]}]
(defn pack-data-callback
[id open?]
(fn [[category owner mintable timestamp price contenthash]]
(let [proto-code (subs contenthash 2 4)
hash (when contenthash
(multihash/base58 (multihash/create :sha2-256 (subs contenthash 12))))]
(when (and (#{constants/swarm-proto-code constants/ipfs-proto-code}
proto-code) hash)
(re-frame/dispatch [:stickers/load-pack proto-code hash id price open?])))))

(re-frame/reg-fx
:stickers/set-pending-timout-fx
(fn []
(utils/set-timeout #(re-frame/dispatch [:stickers/pending-timout])
10000)))

(defn eth-call-pack-data
[contract id open?]
(json-rpc/eth-call
{:contract contract
;; Returns vector of pack data parameters by pack id:
;; [category owner mintable timestamp price contenthash]
:method "getPackData(uint256)"
:params [id]
:outputs ["bytes4[]" "address" "bool" "uint256" "uint256" "bytes"]
:on-success (pack-data-callback id open?)}))

(re-frame/reg-fx
:stickers/pack-data-fx
(fn [[contract id]]
(eth-call-pack-data contract id true)))

(re-frame/reg-fx
:stickers/load-packs-fx
(fn [[contract]]
(json-rpc/eth-call
{:contract contract
;; Returns number of packs registered in the contract
:method "packCount()"
:outputs ["uint256"]
:on-success
(fn [[count]]
(dotimes [id count]
(eth-call-pack-data contract id false)))})))

(re-frame/reg-fx
:stickers/owned-packs-fx
(fn [[contract address]]
(json-rpc/eth-call
{:contract contract
;; Returns vector of owned tokens ids in the contract by address
:method "tokensOwnedBy(address)"
:params [address]
:outputs ["uint256[]"]
:on-success
(fn [[tokens]]
(doseq [id tokens]
(json-rpc/eth-call
{:contract contract
;; Returns pack id in the contract by token id
:method "tokenPackId(uint256)"
:params [id]
:outputs ["uint256"]
:on-success
(fn [[pack-id]]
(re-frame/dispatch [:stickers/pack-owned pack-id]))})))})))

(fx/defn init-stickers-packs
[{:keys [db]}]
(let [sticker-packs (into {} (map #(let [pack (edn/read-string %)]
(vector (:id pack) pack))
(get-in db [:account/account :stickers])))]
{:db (assoc db :stickers/packs-installed sticker-packs :stickers/packs sticker-packs)}))
{:db (assoc db
:stickers/packs-installed sticker-packs
:stickers/packs sticker-packs)}))

(fx/defn install-stickers-pack [{{:account/keys [account] :as db} :db :as cofx} id]
(fx/defn install-stickers-pack
[{{:account/keys [account] :as db} :db :as cofx} id]
(let [pack (get-in db [:stickers/packs id])]
(fx/merge
cofx
Expand All @@ -27,125 +99,91 @@
(assoc :stickers/selected-pack id))}
(accounts/update-stickers (conj (:stickers account) (pr-str pack))))))

(fx/defn load-sticker-pack-success [{:keys [db] :as cofx} edn-string id price open?]
(fx/defn load-sticker-pack-success
[{:keys [db] :as cofx} edn-string id price open?]
(let [pack (assoc (get (edn/read-string edn-string) 'meta)
:id id :price price)]
(fx/merge cofx
{:db (-> db (assoc-in [:stickers/packs id] pack))}
#(when open? (navigation/navigate-to-cofx % :stickers-pack-modal pack)))))

(defn pack-data-callback [id open?]
(fn [[category owner mintable timestamp price contenthash]]
(let [proto-code (subs contenthash 2 4)
hash (when contenthash (multihash/base58 (multihash/create :sha2-256 (subs contenthash 12))))]
(when (and (#{constants/swarm-proto-code constants/ipfs-proto-code} proto-code) hash)
(re-frame/dispatch [:stickers/load-pack proto-code hash id price open?])))))
{:db (assoc-in db [:stickers/packs id] pack)}
#(when open?
(navigation/navigate-to-cofx % :stickers-pack-modal pack)))))

(fx/defn open-sticker-pack
[{{:keys [network] :stickers/keys [packs packs-installed] :as db} :db :as cofx} id]
[{{:stickers/keys [packs packs-installed] :as db} :db :as cofx} id]
(when id
(let [pack (or (get packs-installed id) (get packs id))
network (get-in db [:account/account :networks network])]
(let [pack (or (get packs-installed id)
(get packs id))
contract-address (contracts/get-address db :status/stickers)]
(if pack
(navigation/navigate-to-cofx cofx :stickers-pack-modal pack)
{:stickers/pack-data-fx [network id true]}))))

(fx/defn load-pack [cofx proto-code hash id price open?]
{:http-get {:url (str (if (= constants/swarm-proto-code proto-code)
"https://swarm-gateways.net/bzz:/"
"https://ipfs.infura.io/ipfs/")
hash)
:success-event-creator (fn [o]
[:stickers/load-sticker-pack-success o id price open?])
:failure-event-creator (constantly nil)}})

(fx/defn load-packs [{{:keys [network] :as db} :db}]
(let [network (get-in db [:account/account :networks network])
address (ethereum/normalized-address (get-in db [:account/account :address]))]
{:stickers/owned-packs-fx [network address]
:stickers/load-packs-fx [network]}))

(defn prepare-transaction [id tx on-result]
(merge {:id id
:symbol :ETH
:method constants/web3-send-transaction
:amount (money/bignumber 0)}
(when on-result {:on-result on-result})
tx))

(def snt-contracts
{:mainnet "0x744d70fdbe2ba4cf95131626614a1763df805b9e"
:testnet "0xc55cf4b03948d7ebc8b9e8bad92643703811d162"
:rinkeby nil})

(fx/defn approve-pack [{db :db} pack-id price]
(let [network (get-in db [:account/account :networks (:network db)])
address (ethereum/normalized-address (get-in db [:account/account :address]))
chain (ethereum/network->chain-keyword network)
stickers-contract (get ethereum.stickers/contracts chain)
data (abi-spec/encode "buyToken(uint256,address)" [pack-id address])
tx-object {:to (get snt-contracts chain)
:data (abi-spec/encode "approveAndCall(address,uint256,bytes)" [stickers-contract price data])}]
(wallet/open-modal-wallet-for-transaction
db
(prepare-transaction "approve" tx-object [:stickers/pending-pack pack-id])
tx-object)))
(when contract-address
{:stickers/pack-data-fx [contract-address id]})))))

(fx/defn load-pack
[cofx proto-code hash id price open?]
{:http-get {:url (str (if (= constants/swarm-proto-code proto-code)
"https://swarm-gateways.net/bzz:/"
"https://ipfs.infura.io/ipfs/")
hash)
:success-event-creator
(fn [o]
[:stickers/load-sticker-pack-success o id price open?])
:failure-event-creator
(constantly nil)}})

(fx/defn load-packs
[{:keys [db]}]
(let [contract (contracts/get-address db :status/stickers)
address (ethereum/current-address db)]
(when contract
{:stickers/owned-packs-fx [contract address]
:stickers/load-packs-fx [contract]})))

(fx/defn approve-pack
[{db :db :as cofx} pack-id price]
(let [address (ethereum/current-address db)
chain (ethereum/chain-keyword db)
stickers-contract (contracts/get-address db :status/stickers)
snt-contract (contracts/get-address db :status/snt)]
(wallet/eth-transaction-call
cofx
{:contract snt-contract
:method "approveAndCall(address,uint256,bytes)"
:params [stickers-contract
price
(abi-spec/encode "buyToken(uint256,address)"
[pack-id address])]
:on-result [:stickers/pending-pack pack-id]})))

(fx/defn pending-pack
[{{:keys [network] :as db} :db :as cofx} id]
(let [network (get-in db [:account/account :networks network])
address (ethereum/normalized-address (get-in db [:account/account :address]))]
(fx/merge cofx
{:db (update db :stickers/packs-pendning conj id)
:stickers/owned-packs-fx [network address]}
(navigation/navigate-to-clean :wallet-transaction-sent-modal {})
#(when (zero? (count (:stickers/packs-pendning db)))
{:stickers/set-pending-timout-fx nil}))))
[{:keys [db] :as cofx} id]
(let [contract (contracts/get-address db :status/stickers)
address (ethereum/current-address db)]
(when contract
(fx/merge cofx
{:db (update db :stickers/packs-pending conj id)
:stickers/owned-packs-fx [contract address]}
(navigation/navigate-to-clean :wallet-transaction-sent-modal {})
#(when (zero? (count (:stickers/packs-pending db)))
{:stickers/set-pending-timout-fx nil})))))

(fx/defn pending-timeout
[{{:keys [network] :stickers/keys [packs-pendning packs-owned] :as db} :db}]
(let [packs-diff (clojure.set/difference packs-pendning packs-owned)
network (get-in db [:account/account :networks network])
address (ethereum/normalized-address (get-in db [:account/account :address]))]
(merge {:db (assoc db :stickers/packs-pendning packs-diff)}
(when-not (zero? (count packs-diff))
{:stickers/owned-packs-fx [network address]
:stickers/set-pending-timout-fx nil}))))
[{{:stickers/keys [packs-pending packs-owned] :as db} :db}]
(let [packs-diff (clojure.set/difference packs-pending packs-owned)
contract (contracts/get-address db :status/stickers)
address (ethereum/current-address db)]
(when contract
(merge {:db (assoc db :stickers/packs-pending packs-diff)}
(when-not (zero? (count packs-diff))
{:stickers/owned-packs-fx [contract address]
:stickers/set-pending-timout-fx nil})))))

(fx/defn pack-owned [{db :db} id]
{:db (update db :stickers/packs-owned conj id)})

(fx/defn get-owned-pack
[{{:keys [network] :as db} :db}]
(let [address (ethereum/normalized-address (get-in db [:account/account :address]))]
{:stickers/owned-packs-fx [network address]}))

(re-frame/reg-fx
:stickers/pack-data-fx
(fn [[network id open?]]
(when-let [contract (get ethereum.stickers/contracts (ethereum/network->chain-keyword network))]
(ethereum.stickers/pack-data contract id (pack-data-callback id open?)))))

(re-frame/reg-fx
:stickers/set-pending-timout-fx
(fn []
(js/setTimeout #(re-frame/dispatch [:stickers/pending-timout]) 10000)))

(re-frame/reg-fx
:stickers/load-packs-fx
(fn [[network]]
(when-let [contract (get ethereum.stickers/contracts (ethereum/network->chain-keyword network))]
(ethereum.stickers/pack-count contract
(fn [count]
(dotimes [n count]
(ethereum.stickers/pack-data contract n (pack-data-callback n false))))))))

(re-frame/reg-fx
:stickers/owned-packs-fx
(fn [[network address]]
(when-let [contract (get ethereum.stickers/contracts (ethereum/network->chain-keyword network))]
(ethereum.stickers/owned-tokens contract address
(fn [tokens]
(doseq [n tokens]
(ethereum.stickers/token-pack-id contract n
#(re-frame/dispatch [:stickers/pack-owned %]))))))))
[{:keys [db]}]
(let [contract (contracts/get-address db :status/stickers)
address (ethereum/current-address db)]
(when contract
{:stickers/owned-packs-fx [contract address]})))
4 changes: 2 additions & 2 deletions src/status_im/subs.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@
(reg-root-key-sub :stickers/packs :stickers/packs)
(reg-root-key-sub :stickers/installed-packs :stickers/packs-installed)
(reg-root-key-sub :stickers/packs-owned :stickers/packs-owned)
(reg-root-key-sub :stickers/packs-pendning :stickers/packs-pendning)
(reg-root-key-sub :stickers/packs-pending :stickers/packs-pending)

;;mailserver
(reg-root-key-sub :mailserver/current-id :mailserver/current-id)
Expand Down Expand Up @@ -767,7 +767,7 @@
:<- [:stickers/packs]
:<- [:stickers/installed-packs]
:<- [:stickers/packs-owned]
:<- [:stickers/packs-pendning]
:<- [:stickers/packs-pending]
(fn [[packs installed owned pending]]
(map (fn [{:keys [id] :as pack}]
(cond-> pack
Expand Down
Loading

0 comments on commit a56b811

Please sign in to comment.