going somewhere.
This commit is contained in:
1 parent
30d732f708
commit
75a91f7f7b
2 files changed
+81
-25
No files matched your search
@@ -1,6 +1,7 @@
|
|||||||
(ns skirmish.ledger.data-layer
|
(ns skirmish.ledger.data-layer
|
||||||
(:require [datomic.api :as d]
|
(:require [datomic.api :as d]
|
||||||
[infix.macros :refer [infix]]))
|
[infix.macros :refer [infix]]
|
||||||
|
[slingshot.slingshot :refer [throw+]]))
|
||||||
|
|
||||||
(defn get-all-account-public-key [db]
|
(defn get-all-account-public-key [db]
|
||||||
(d/q '[:find ?pk :where [?e :skirmish.ledger/owner-public-key ?pk]] db))
|
(d/q '[:find ?pk :where [?e :skirmish.ledger/owner-public-key ?pk]] db))
|
||||||
@@ -123,6 +124,31 @@
|
|||||||
res (assoc res (:to-account-id transaction) to-account)]
|
res (assoc res (:to-account-id transaction) to-account)]
|
||||||
res))
|
res))
|
||||||
|
|
||||||
|
(defn validate-transactions [transactions]
|
||||||
|
(loop [transactions transactions]
|
||||||
|
(when (seq transactions)
|
||||||
|
(let [transaction (first transactions)]
|
||||||
|
(when (not= (-> transaction :from-account :skirmish.ledger/sec)
|
||||||
|
(-> transaction :to-account :skirmish.ledger/sec))
|
||||||
|
(throw+ {:error-type :4XX
|
||||||
|
:status 400
|
||||||
|
:body {:error "Part of the transaction includes a transaction between two wallets of different underlying securities."}}))
|
||||||
|
(recur (rest transactions)))))
|
||||||
|
transactions)
|
||||||
|
|
||||||
|
(defn validate-resulting-transactions [transactions]
|
||||||
|
(loop [transactions transactions]
|
||||||
|
(when (seq transactions)
|
||||||
|
(let [transaction (first transactions)]
|
||||||
|
(when (neg? (get transaction 3))
|
||||||
|
(throw+ {:error-type :4XX
|
||||||
|
:status 400
|
||||||
|
:body {:error "Transaction would result in a negative amount in a wallet."}})))
|
||||||
|
(recur (rest transactions))))
|
||||||
|
transactions)
|
||||||
|
|
||||||
(defn create-transactions [db transactions]
|
(defn create-transactions [db transactions]
|
||||||
(let [transactions (map #(assoc-accounts db %) transactions)]
|
(let [transactions (map #(assoc-accounts db %) transactions)
|
||||||
(into #{} (vals (reduce compute-transactions {} transactions)))))
|
transactions (validate-transactions transactions)
|
||||||
|
ret (vals (reduce compute-transactions {} transactions))]
|
||||||
|
(validate-resulting-transactions ret)))
|
||||||
@@ -57,21 +57,22 @@
|
|||||||
(->> create-security-4 cs (s/assert ::ok))
|
(->> create-security-4 cs (s/assert ::ok))
|
||||||
conn))
|
conn))
|
||||||
|
|
||||||
|
(defn create-some-accounts [conn n]
|
||||||
(defn create-some-accounts [conn]
|
(let [create-emit-req (fn [amount account-id sec-id] {:body (edn->stream [amount account-id]) :route-params {:sec-id sec-id}})
|
||||||
|
sec-1-reqs (for [i (range 1 (inc n))] (create-emit-req (* i 100) (str i "-sec-1") "sec-1"))
|
||||||
|
sec-2-reqs (for [i (range 1 (inc n))] (create-emit-req (* i 100) (str i "-sec-2") "sec-2"))
|
||||||
|
reqs (concat sec-1-reqs sec-2-reqs)]
|
||||||
|
(loop [reqs reqs]
|
||||||
|
(when (seq reqs)
|
||||||
(let [es (controllers/emit-securities conn)
|
(let [es (controllers/emit-securities conn)
|
||||||
emit-sec-req-1 {:body (edn->stream [100 "1-sec-1"]) :route-params {:sec-id "sec-1"}}
|
req (first reqs)]
|
||||||
emit-sec-req-2 {:body (edn->stream [200 "2-sec-1"]) :route-params {:sec-id "sec-1"}}
|
(->> req es (s/assert ::ok))
|
||||||
emit-sec-req-3 {:body (edn->stream [1000 "1-sec-2"]) :route-params {:sec-id "sec-2"}}
|
(recur (rest reqs)))))
|
||||||
emit-sec-req-4 {:body (edn->stream [2000 "2-sec-2"]) :route-params {:sec-id "sec-2"}}]
|
|
||||||
(->> emit-sec-req-1 es (s/assert ::ok))
|
|
||||||
(->> emit-sec-req-2 es (s/assert ::ok))
|
|
||||||
(->> emit-sec-req-3 es (s/assert ::ok))
|
|
||||||
(->> emit-sec-req-4 es (s/assert ::ok))
|
|
||||||
conn))
|
conn))
|
||||||
|
|
||||||
|
|
||||||
(def create-some-securities-and-accounts (comp create-some-accounts create-some-securities))
|
(defn create-some-securities-and-accounts [conn n-accounts-by-currency]
|
||||||
|
(-> conn create-some-securities (create-some-accounts n-accounts-by-currency)))
|
||||||
|
|
||||||
|
|
||||||
(facts "about the securities"
|
(facts "about the securities"
|
||||||
@@ -173,24 +174,24 @@
|
|||||||
|
|
||||||
(facts "about accounts"
|
(facts "about accounts"
|
||||||
(fact "we should be able to get list of all accounts"
|
(fact "we should be able to get list of all accounts"
|
||||||
(let [conn (create-some-securities-and-accounts (create-conn))
|
(let [conn (create-some-securities-and-accounts (create-conn) 2)
|
||||||
req {:route-params {} :headers {"accept" "application/edn"}}
|
req {:route-params {} :headers {"accept" "application/edn"}}
|
||||||
expt [{:account-public-key "1-sec-1" :url "http://localhost:1604/api/1/ledger/accounts/1-sec-1"}
|
expt #{{:account-public-key "1-sec-1" :url "http://localhost:1604/api/1/ledger/accounts/1-sec-1"}
|
||||||
{:account-public-key "1-sec-2" :url "http://localhost:1604/api/1/ledger/accounts/1-sec-2"}
|
{:account-public-key "1-sec-2" :url "http://localhost:1604/api/1/ledger/accounts/1-sec-2"}
|
||||||
{:account-public-key "2-sec-1" :url "http://localhost:1604/api/1/ledger/accounts/2-sec-1"}
|
{:account-public-key "2-sec-1" :url "http://localhost:1604/api/1/ledger/accounts/2-sec-1"}
|
||||||
{:account-public-key "2-sec-2" :url "http://localhost:1604/api/1/ledger/accounts/2-sec-2"}]]
|
{:account-public-key "2-sec-2" :url "http://localhost:1604/api/1/ledger/accounts/2-sec-2"}}]
|
||||||
((controllers/get-available-accounts conn) req) => (spec-check ::ok)
|
((controllers/get-available-accounts conn) req) => (spec-check ::ok)
|
||||||
(-> ((controllers/get-available-accounts conn) req) body :accounts sec->hash-set) => (sec->hash-set expt)))
|
(-> ((controllers/get-available-accounts conn) req) body :accounts) => (just expt)))
|
||||||
|
|
||||||
(fact "we should be able to get account"
|
(fact "we should be able to get account"
|
||||||
(let [conn (create-some-securities-and-accounts (create-conn))
|
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||||
req {:route-params {:account-id "2-sec-1"} :headers {"accept" "application/edn"}}]
|
req {:route-params {:account-id "2-sec-1"} :headers {"accept" "application/edn"}}]
|
||||||
((controllers/get-account conn) req) => (spec-check ::ok)
|
((controllers/get-account conn) req) => (spec-check ::ok)
|
||||||
(body ((controllers/get-account conn) req)) => {:account {:account-public-key "2-sec-1" :amount 200 :sec-id :sec-1}
|
(body ((controllers/get-account conn) req)) => {:account {:account-public-key "2-sec-1" :amount 200 :sec-id :sec-1}
|
||||||
:sec-url "/api/1/ledger/securities/sec-1"}))
|
:sec-url "/api/1/ledger/securities/sec-1"}))
|
||||||
|
|
||||||
(fact "the interest should be payed when getting the account"
|
(fact "the interest should be payed when getting the account"
|
||||||
(let [conn (create-some-securities-and-accounts (create-conn))
|
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||||
req {:route-params {:account-id "2-sec-1"} :headers {"accept" "application/edn"}}]
|
req {:route-params {:account-id "2-sec-1"} :headers {"accept" "application/edn"}}]
|
||||||
((controllers/get-account conn) req) => (spec-check ::ok)
|
((controllers/get-account conn) req) => (spec-check ::ok)
|
||||||
(body ((controllers/get-account conn) req)) => {:account {:account-public-key "2-sec-1" :amount 200 :sec-id :sec-1}
|
(body ((controllers/get-account conn) req)) => {:account {:account-public-key "2-sec-1" :amount 200 :sec-id :sec-1}
|
||||||
@@ -198,7 +199,7 @@
|
|||||||
|
|
||||||
|
|
||||||
(fact "we should not get an account if it does not exists"
|
(fact "we should not get an account if it does not exists"
|
||||||
(let [conn (create-some-securities-and-accounts (create-conn))
|
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||||
req {:route-params {:account-id "2-sec-10"} :headers {"accept" "application/edn"}}]
|
req {:route-params {:account-id "2-sec-10"} :headers {"accept" "application/edn"}}]
|
||||||
((controllers/get-account conn) req) => (spec-check ::status-404))))
|
((controllers/get-account conn) req) => (spec-check ::status-404))))
|
||||||
|
|
||||||
@@ -266,7 +267,7 @@
|
|||||||
|
|
||||||
(facts "about transactions"
|
(facts "about transactions"
|
||||||
(fact "about transferring an amount from one wallet to another"
|
(fact "about transferring an amount from one wallet to another"
|
||||||
(let [conn (create-some-securities-and-accounts (create-conn))
|
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||||
transaction {:from-account-id "1-sec-1"
|
transaction {:from-account-id "1-sec-1"
|
||||||
:to-account-id "2-sec-1"
|
:to-account-id "2-sec-1"
|
||||||
:amount 50}
|
:amount 50}
|
||||||
@@ -274,13 +275,42 @@
|
|||||||
[eid1 eid2] (get-account-eids db "1-sec-1" "2-sec-1")
|
[eid1 eid2] (get-account-eids db "1-sec-1" "2-sec-1")
|
||||||
expt #{[:db/add eid1 :skirmish.ledger/amount 50]
|
expt #{[:db/add eid1 :skirmish.ledger/amount 50]
|
||||||
[:db/add eid2 :skirmish.ledger/amount 250]}]
|
[:db/add eid2 :skirmish.ledger/amount 250]}]
|
||||||
(data-layer/create-transactions db [transaction]) => expt)) ;expt))
|
(data-layer/create-transactions db [transaction]) => (just expt)))
|
||||||
(fact "about transferring an amount from one wallet to another"
|
(fact "about transferring an amount from one wallet to another"
|
||||||
(let [conn (create-some-securities-and-accounts (create-conn))
|
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||||
transaction {:from-account-id "1-sec-1"
|
transaction {:from-account-id "1-sec-1"
|
||||||
:to-account-id "1-sec-1"
|
:to-account-id "1-sec-1"
|
||||||
:amount 45}
|
:amount 45}
|
||||||
db (d/db conn)
|
db (d/db conn)
|
||||||
[eid1] (get-account-eids db "1-sec-1")
|
[eid1] (get-account-eids db "1-sec-1")
|
||||||
expt #{[:db/add eid1 :skirmish.ledger/amount 100]}]
|
expt #{[:db/add eid1 :skirmish.ledger/amount 100]}]
|
||||||
(data-layer/create-transactions db [transaction]) => expt)))
|
(data-layer/create-transactions db [transaction]) => (just expt)))
|
||||||
|
(fact "about transferring amounts between three wallets"
|
||||||
|
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||||
|
transaction-1 {:from-account-id "1-sec-1"
|
||||||
|
:to-account-id "2-sec-1"
|
||||||
|
:amount 50}
|
||||||
|
transaction-2 {:from-account-id "2-sec-1"
|
||||||
|
:to-account-id "3-sec-1"
|
||||||
|
:amount 250}
|
||||||
|
db (d/db conn)
|
||||||
|
[eid1 eid2 eid3] (get-account-eids db "1-sec-1" "2-sec-1" "3-sec-1")
|
||||||
|
expt #{[:db/add eid1 :skirmish.ledger/amount 50]
|
||||||
|
[:db/add eid2 :skirmish.ledger/amount 0]
|
||||||
|
[:db/add eid3 :skirmish.ledger/amount 550]}]
|
||||||
|
(data-layer/create-transactions db [transaction-1 transaction-2]) => (just expt)))
|
||||||
|
(fact "about transaction between different assets types"
|
||||||
|
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||||
|
transaction {:from-account-id "1-sec-1"
|
||||||
|
:to-account-id "1-sec-2"
|
||||||
|
:amount 50}
|
||||||
|
db (d/db conn)]
|
||||||
|
(data-layer/create-transactions db [transaction]) => (throws #"different underlying securities")))
|
||||||
|
(fact "about transaction with negative results"
|
||||||
|
(let [conn (create-some-securities-and-accounts (create-conn) 10)
|
||||||
|
transaction {:from-account-id "1-sec-1"
|
||||||
|
:to-account-id "2-sec-1"
|
||||||
|
:amount 500}
|
||||||
|
db (d/db conn)]
|
||||||
|
(data-layer/create-transactions db [transaction]) => (throws #"negative amount in a wallet"))))
|
||||||
|
|
||||||
Reference in new issue
Block a user