             [clojure-fabric.request :as request]
             [clojure-fabric.response :as response]
             [clojure.core.cache :as cache])
-  (:import [org.hyperledger.fabric.sdk User Enrollment]
+  (:import [org.hyperledger.fabric.sdk User Enrollment Peer Orderer]
            [org.bouncycastle.jcajce.provider.asymmetric.ec BCECPrivateKey]))
+
+(defprotocol Marshall
+  (marshall [obj]))
+
+;;; FIXME: call marshal from generated code when return type matches
+(extend-protocol Marshall
+  java.util.Collection
+  (marshall [obj]
+    (if (instance? clojure.lang.IPersistentSet obj)
+      obj
+      (seq obj))))
 
 (defonce client-lru-cache
   ;; FIXME: magic number
   (atom (cache/lru-cache-factory {} :threshold 64)))
 
-(defn make-client [msp-id name priv-key cert & [{:keys [roles account affiliation]}]]
+(defn make-client [msp-id name priv-key cert {:keys [roles account affiliation]}]
   (let [new-client (client/create-new-instance)]
     (client/set-crypto-suite new-client (crypto/get-crypto-suite))
     (client/set-user-context new-client 

(defn get-or-make-channel [client channel-id]
  (or (client/get-channel client channel-id) (client/new-channel client channel-id)))

;; (defn add-orderer
;;   ([client channel-id orderer-opts-map]
;;    ;; Add an orderer if there is no orderer
;;    (add-orderer channel-id orderer-opts-map false))
;;   ([client channel-id orderer-opts-map force?]
;;    (let [channel (get-or-make-channel client channel-id)]
;;      (if-let [existing-orderers (and (not force?) (client/get))])
         
;;      )
;;    )
;;   )
;;;
;;; Peers
;;;     Endorser

                                      (.getCert ^Enrollment enrollment))]
    (swap! client-lru-cache cache/evict cache-key)))

(defrecord ClientOpts [roles account affiliation])

(defn get-or-make-client [msp-id name priv-key cert opts]
  (let [cache-key (priv-key+cert->hash priv-key cert)
        lru-cache (swap! client-lru-cache cache/hit cache-key)]
    (if-let [existing-client (cache/lookup lru-cache cache-key)]
