Skip to content

Commit

Permalink
Account for decimals (ERC20, ETH) on new job & job details
Browse files Browse the repository at this point in the history
  • Loading branch information
madis committed Dec 5, 2023
1 parent 8ab4ec9 commit 8eedb89
Show file tree
Hide file tree
Showing 20 changed files with 128 additions and 51 deletions.
4 changes: 2 additions & 2 deletions contracts/Ethlance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -204,12 +204,12 @@ contract Ethlance is IERC721Receiver, IERC1155Receiver, DSAuth {
address payable newJobPayableAddress = payable(address(uint160(newJob)));
MutableForwarder(newJobPayableAddress).setTarget(jobProxyTarget);

emit JobCreated(newJobPayableAddress, _creator, _offeredValues, _invitedArbiters, _ipfsData, timestamp(), Job(newJobPayableAddress).version());

EthlanceStructs.transferToJob(_creator, address(this), newJobPayableAddress, _offeredValues);
isJobMap[newJobPayableAddress] = true;
Job(newJobPayableAddress).initialize(this, _creator, _offeredValues, _invitedArbiters);

emit JobCreated(newJobPayableAddress, _creator, _offeredValues, _invitedArbiters, _ipfsData, timestamp(), Job(newJobPayableAddress).version());

return newJob;
}

Expand Down
1 change: 1 addition & 0 deletions contracts/Job.sol
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ contract Job is IERC721Receiver, IERC1155Receiver, DSAuth, JobStorage {

disputes[_invoiceId] = dispute;
invoices[_invoiceId] = invoice;
ethlance.emitFundsOut(address(this), _valueForInvoicer);
ethlance.emitDisputeResolved(address(this), _invoiceId, _valueForInvoicer, _ipfsData);
}

Expand Down
2 changes: 1 addition & 1 deletion contracts/testing/TestToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ contract TestToken is IERC20 {
//
string public name = "TestToken";
string public symbol = "TEST";
uint8 public decimals = 0;
uint8 public decimals = 2;


//
Expand Down
4 changes: 3 additions & 1 deletion server/src/ethlance/server/db.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
[:token-detail/type :text not-nil] ; #{:eth :erc20 :erc721 :erc1155}
[:token-detail/name :text]
[:token-detail/symbol :text]
[:token-detail/decimals :integer not-nil]
;; PK
[(sql/call :primary-key :token-detail/id)]]
:list-keys []}
Expand Down Expand Up @@ -969,7 +970,8 @@
{:token-detail/id (:address token-details)
:token-detail/type (:type token-details)
:token-detail/name (:name token-details)
:token-detail/symbol (:symbol token-details)}))))
:token-detail/symbol (:symbol token-details)
:token-detail/decimals (:decimals token-details)}))))

(defn ready-state?
[]
Expand Down
3 changes: 2 additions & 1 deletion server/src/ethlance/server/syncer.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
(let [eth-token-details {:address "0x0000000000000000000000000000000000000000"
:name "Ether"
:symbol "ETH"
:type :eth}]
:type :eth
:decimals 18}]
(if (not (<? (ethlance-db/get-token conn token-address)))
(if (= :eth token-type)
(ethlance-db/store-token-details conn eth-token-details)
Expand Down
1 change: 1 addition & 0 deletions shared/src/ethlance/shared/graphql/schema.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@
tokenDetail_type: Keyword
tokenDetail_name: String
tokenDetail_symbol: String
tokenDetail_decimals: Int
}
Expand Down
10 changes: 9 additions & 1 deletion shared/src/ethlance/shared/token_utils.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,18 @@
token-name (when (has-contract-method? contract-instance "name")
(<! (promise->chan (w3-eth/contract-call contract-instance :name [] {}))))
token-symbol (when (has-contract-method? contract-instance "symbol")
(<! (promise->chan (w3-eth/contract-call contract-instance :symbol [] {}))))]
(<! (promise->chan (w3-eth/contract-call contract-instance :symbol [] {}))))
token-decimals (case token-type
:eth 18
:erc721 0
:erc1155 1
:erc20 (if (has-contract-method? contract-instance "decimals")
(<! (promise->chan (w3-eth/contract-call contract-instance :decimals [] {})))
18))]
{:address contract-address
:type token-type
:name token-name
:symbol token-symbol
:decimals token-decimals
:web3-instance web3-instance
:contract-instance contract-instance})))
6 changes: 3 additions & 3 deletions ui/resources/public/less/page/new-job.less
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,9 @@
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;

&.disabled {
opacity: 0.5;
}
// &.disabled {
// opacity: 0.5;
// }
> .label {
font-weight: 700;
padding-right: 0.5em;
Expand Down
20 changes: 20 additions & 0 deletions ui/src/ethlance/ui/component/token_amount_input.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
(ns ethlance.ui.component.token-amount-input
(:require
[reagent.core :as r]
[ethlance.ui.component.text-input :as text-input]))

(defn c-token-amount-input
[{:keys [decimals on-change] :as opts}]
(let [text-input-opts (dissoc opts :decimals)
; Even though tokens (including ETH) can have 18 decimals, using so many in the UI isn't practical
max-ui-decimals 3
decimals-for-ui (min decimals max-ui-decimals)
step (/ 1 (cljs.math/pow 10 decimals-for-ui))
; Should use method similar to https://stackoverflow.com/a/10880710/1025412
human->token-amount (fn [human-amount] (.round js/Math (* (cljs.math/pow 10 decimals-for-ui) human-amount)))
token-on-change (fn [human-amount]
(on-change {:token-amount (human->token-amount human-amount)
:human-amount human-amount
:decimals decimals}))
amount-extras {:type :number :step step :on-change token-on-change}]
[text-input/c-text-input (merge text-input-opts amount-extras)]))
9 changes: 5 additions & 4 deletions ui/src/ethlance/ui/component/token_info.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@

(defn token-info-str [token-amount token-detail]
(let [token-type (:token-detail/type token-detail)
token-name (:token-detail/name token-detail)]
(str (util.tokens/human-amount token-amount token-type)
token-name (:token-detail/name token-detail)
decimals (:token-detail/decimals token-detail)]
(str (util.tokens/human-amount token-amount token-type decimals)
" "
(if token-name
token-name
Expand All @@ -20,9 +21,9 @@
; 1 (ERC721, 0x3xZ...)
; 2 (ERC1155, 0x76BE3...) linking to https://etherscan.io/token/0x76be3b62873462d2142405439777e971754e8e77
(defn c-token-info [token-amount token-detail]
(println ">>> c-token-info called with" token-amount token-detail)
(let [token-type (:token-detail/type token-detail)
display-amount (util.tokens/human-amount token-amount token-type)
token-decimals (:token-detail/decimals token-detail)
display-amount (util.tokens/human-amount token-amount token-type token-decimals)
token-symbol (:token-detail/symbol token-detail)
dollar-amount (if (= token-type :eth)
(util.tokens/round 2 (* display-amount @(re/subscribe [::rates-subs/conversion-rate :ETH :USD]))))
Expand Down
1 change: 0 additions & 1 deletion ui/src/ethlance/ui/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@

(defn ^:export init []
(let [main-config (ui.config/get-config environment)]
(println ">>> ethlance.ui.core/init starting with CONFIG: " main-config)
(util.injection/inject-data-scroll! {:injection-selector "#app"})

;; Initialize our district re-mount components
Expand Down
11 changes: 9 additions & 2 deletions ui/src/ethlance/ui/page/job_contract.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,19 @@
:arbiter)

:arbiter
(cond
(when
(or
(given-feedback? :employer :candidate feedbacks)
(given-feedback? :candidate :employer feedbacks))
(if (given-feedback? :arbiter :candidate feedbacks)
(cond
(and (not (given-feedback? :arbiter :employer feedbacks))
(not (given-feedback? :arbiter :candidate feedbacks)))
:candidate
(and (not (given-feedback? :arbiter :employer feedbacks))
(given-feedback? :arbiter :candidate feedbacks))
:employer
(and (not (given-feedback? :arbiter :candidate feedbacks))
(given-feedback? :arbiter :employer feedbacks))
:candidate)))

open-invoices? (not (empty? open-invoices))
Expand Down
7 changes: 6 additions & 1 deletion ui/src/ethlance/ui/page/job_contract/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,18 @@
invoice-id (:invoice/id forwarded-event-data)
token-type (:token-type forwarded-event-data)
raw-amount (:token-amount forwarded-event-data)
amount (case token-type
:eth raw-amount
:erc20 (Math/floor raw-amount)
:erc721 1
:erc1155 (Math/floor raw-amount))
token-address (:token-address forwarded-event-data)
token-id (:token-id forwarded-event-data)
address-placeholder "0x0000000000000000000000000000000000000000"
token-address (if (not (= token-type :eth))
token-address
address-placeholder)
offered-value {:value (str raw-amount)
offered-value {:value (str amount)
:token
{:tokenId token-id
:tokenContract
Expand Down
27 changes: 15 additions & 12 deletions ui/src/ethlance/ui/page/job_detail.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
[ethlance.ui.component.text-input :refer [c-text-input]]
[ethlance.ui.component.textarea-input :refer [c-textarea-input]]
[ethlance.ui.component.pagination :as pagination]
[ethlance.ui.component.token-amount-input :refer [c-token-amount-input]]
[district.ui.graphql.subs :as gql]
[ethlance.ui.util.component :refer [<sub >evt]]
[ethlance.ui.util.navigation :refer [link-params] :as util.navigation]
Expand Down Expand Up @@ -56,6 +57,7 @@
[:token-detail/id
:token-detail/type
:token-detail/name
:token-detail/decimals
:token-detail/symbol]]
[:invoices
[:total-count
Expand Down Expand Up @@ -505,22 +507,22 @@

(defn c-add-funds [contract-address token-id token-details]
(let [amount @(re/subscribe [:page.job-detail/add-funds-amount])
step (if (= (:token-detail/type token-details) :eth) 0.001 1)
adding-funds? (re/subscribe [:page.job-detail/adding-funds?])
add-funds-tx-in-progress? (re/subscribe [:page.job-detail/add-funds-tx-in-progress?])
]
add-funds-tx-in-progress? (re/subscribe [:page.job-detail/add-funds-tx-in-progress?])]
(if @adding-funds?
[:div.add-funds
[c-text-input
{:placeholder "Token amount"
:step step
:type :number
:default-value nil
:value amount
:on-change #(re/dispatch [:page.job-detail/set-add-funds-amount (js/parseFloat %)])}]
[c-token-amount-input
{:value (:human-amount amount)
:placeholder "Token amount"
:decimals (:token-detail/decimals token-details)
:on-change #(re/dispatch [:page.job-detail/set-add-funds-amount %])}]
[c-button {:on-click (fn []
(when (not @add-funds-tx-in-progress?)
(>evt [:page.job-detail/finish-adding-funds contract-address token-details token-id amount])))
(>evt [:page.job-detail/finish-adding-funds
contract-address
token-details
token-id
(:token-amount amount)])))
:disabled? @add-funds-tx-in-progress?
:size :small}
[c-button-label "Confirm"]]]
Expand Down Expand Up @@ -600,7 +602,7 @@
[:div
[:div.button.primary.active
{:style (when (or @end-job-tx-in-progress? has-unpaid-invoices? has-unresolved-disputes?) {:background :gray})
:disabled? @end-job-tx-in-progress?
:disabled @end-job-tx-in-progress?
:on-click (fn []
(when (and can-end-job? (not @end-job-tx-in-progress?))
(re/dispatch [:page.job-detail/end-job {:job/id contract-address :employer employer-id}])))}
Expand Down Expand Up @@ -649,6 +651,7 @@
[:token-details [:token-detail/id
:token-detail/type
:token-detail/name
:token-detail/decimals
:token-detail/symbol]]
[:invoices
[[:items
Expand Down
3 changes: 1 addition & 2 deletions ui/src/ethlance/ui/page/job_detail/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -460,11 +460,10 @@

(re/reg-event-fx
:page.job-detail/finish-adding-funds
(fn [{:keys [db] :as cofx} [_ job-address token-details token-id amount]]
(fn [{:keys [db] :as cofx} [_ job-address token-details token-id tx-amount]]
(let [funder (accounts-queries/active-account (:db cofx))
tx-opts-base {:from funder :gas 10000000}
token-type (:token-detail/type token-details)
tx-amount (util.tokens/machine-amount amount token-type)
tx-opts (if (= token-type :eth)
(assoc tx-opts-base :value tx-amount)
tx-opts-base)
Expand Down
10 changes: 5 additions & 5 deletions ui/src/ethlance/ui/page/jobs.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
[ethlance.ui.component.inline-svg :refer [c-inline-svg]]
[ethlance.ui.component.loading-spinner :refer [c-loading-spinner]]
[ethlance.ui.component.main-layout :refer [c-main-layout]]
[ethlance.ui.component.token-info :refer [c-token-info]]
[ethlance.ui.util.tokens :as tokens]
[ethlance.ui.component.mobile-search-filter
:refer
Expand Down Expand Up @@ -77,16 +78,14 @@
:beginner "Novice ($)"
:intermediate "Professional ($$)"
:expert "Expert ($$$)")
amount (str
(tokens/human-amount (:job/token-amount job) (:job/token-type job))
" "
(get-in job [:token-details :token-detail/symbol]) " (" (get-in job [:token-details :token-detail/name]) ")")]
token-details (get-in job [:token-details])
amount (:job/token-amount job)]
[:div.job-detail-table
[:div.name "Payment Type"]
[:div.value (str/title bid-option)]

[:div.name "Funds available"]
[:div.value amount]
[:div.value [c-token-info amount token-details]]

[:div.name "Experience Level"]
[:div.value formatted-experience-level]
Expand Down Expand Up @@ -231,6 +230,7 @@
[:token-details
[:token-detail/id
:token-detail/type
:token-detail/decimals
:token-detail/name
:token-detail/symbol]]

Expand Down
11 changes: 7 additions & 4 deletions ui/src/ethlance/ui/page/new_job.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
[ethlance.ui.component.search-input :refer [c-chip-search-input]]
[ethlance.ui.component.select-input :refer [c-select-input]]
[ethlance.ui.component.text-input :refer [c-text-input]]
[ethlance.ui.component.token-amount-input :refer [c-token-amount-input]]
[ethlance.ui.component.textarea-input :refer [c-textarea-input]]
[ethlance.ui.util.component :refer [<sub >evt]]
[ethlance.ui.subscriptions :as subs]
Expand Down Expand Up @@ -90,7 +91,8 @@
token-with-id? (#{:erc721 :erc1155} @*token-type)
disabled? (or
(not (s/valid? :page.new-job/create @form-values))
@tx-in-progress?)]
@tx-in-progress?)
token-decimals (re/subscribe [:page.new-job/token-decimals])]
[c-main-layout {:container-opts {:class :new-job-main-container}}
[:div.forms-left
[:div.title "New job"]
Expand Down Expand Up @@ -170,10 +172,11 @@
[:erc1155 [c-radio-secondary-element "Multi-Token (ERC-1155)"]]]
(when token-with-amount?
[:div.token-address-input
[c-text-input
; Specialized for tokens (takes account the decimals from the contract)
[c-token-amount-input
{:value @*token-amount
:on-change #(re/dispatch [:page.new-job/set-token-amount %])
:placeholder "Token Amount"}]
:decimals @token-decimals
:on-change #(re/dispatch [:page.new-job/set-token-amount %])}]
[:div.token-label "(amount)"]])
(when with-token?
[:div.token-address-input
Expand Down
31 changes: 25 additions & 6 deletions ui/src/ethlance/ui/page/new_job/events.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,40 @@
; The simple setter implementation for eventual production
; (re/reg-event-fx :page.new-job/set-token-type (create-assoc-handler :job/token-type))

(re/reg-event-db
:page.new-job/decimals-response
(fn [db [_ decimals]]
(println ">>> DECIMALS RESPONSE" decimals)
(assoc-in db [state-key :job/token-decimals] decimals)))

; Implementation to auto-fill testnet token data with address
(re/reg-event-fx
:page.new-job/set-token-type
(fn [cofx [_ token-type]]
(fn [{:keys [db] :as cofx} [_ token-type]]
(let [token-type->contract-name {:erc20 :token
:erc721 :test-nft
:erc1155 :test-multi-token}
token-address (fn [token-type]
(when (token-type token-type->contract-name)
(district.ui.smart-contracts.queries/contract-address
(:db cofx)
(token-type token-type->contract-name))))]
{:db (-> (:db cofx)
(token-type token-type->contract-name))))
erc20-decimals (fn []
[:web3/call
{:fns
[{:instance (w3n-eth/contract-at
(district.ui.web3.queries/web3 db)
(ethlance.shared.contract-constants/abi token-type)
(token-address token-type))
:fn :decimals
:args []
:on-success [:page.new-job/decimals-response]
:on-error [:page.new-job/decimals-response]}]}])
default-decimals (if (= token-type :eth) 18 0)
other-token-decimals (fn [] [:dispatch [:page.new-job/decimals-response default-decimals]])
decimals-fx-fn (if (= :erc20 token-type) erc20-decimals other-token-decimals)]
{:fx [(decimals-fx-fn)]
:db (-> db
(assoc-in ,,, [state-key :job/token-address] (token-address token-type))
(assoc-in ,,, [state-key :job/token-type] token-type))})))

Expand Down Expand Up @@ -268,9 +289,7 @@
(let [creator (accounts-queries/active-account (:db cofx))
job-fields (get-in cofx [:db state-key])
token-type (:job/token-type job-fields)
token-amount (if (= token-type :eth)
(eth->wei (:job/token-amount job-fields))
(:job/token-amount job-fields))
token-amount (get-in job-fields [:job/token-amount :token-amount])
address-placeholder "0x0000000000000000000000000000000000000000"
token-address (if (not (= token-type :eth))
(:job/token-address job-fields)
Expand Down
Loading

0 comments on commit 8eedb89

Please sign in to comment.