Initial commit

This commit is contained in:
Julien Eluard 2018-02-17 10:34:37 +01:00
commit f1174feb2d
14 changed files with 905 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
target/
/npm-debug.log
node_modules/

67
MANIFESTO.md Normal file
View File

@ -0,0 +1,67 @@
### Development model
Simple. Opiniated. Adapted to the platform.
Data based. Hosted on decentralized file storage. Accessible via ETH.
Simple EDN / hiccup based syntax.
Some simple convention (entry point).
Simple syntax for simple use cases. More complex available.
Do we want to allow direct RN model?
ClojureScript / EDN first, allow JS to.
Logic will be distributed as JS.
Allow to hook in our screens (navigate to).
Explicitely allow to access some internal subscribe / dispatch.
Growable. Composable. Reusable.
https://github.com/juxt/mach/blob/master/examples/poll-twitter/Machfile.edn
### Development process
Have some simple block based UI to create basic logic
UI itself can be constructed by drag and drop and sticking componenets together directly
https://medium.com/@luna_language/luna-the-visual-way-to-create-software-c4db520d6d1e
https://makecode.com/#about
See data flowing
### Deployment process
### Discoverability
https://www.npmjs.com/package/ethereum-ens
https://github.com/ipfs/js-ipfs
## Simple apps to build on top
Simple split bill app
https://trustlines.network/
https://livepeer.org/
## Open Questions
Linda model? https://www.inf.ed.ac.uk/teaching/courses/ppls/linda.pdf http://programmingexamples.wikidot.com/linda
Semantic query?
How to isolate apps?
https://github.com/joltup/react-native-threads
Permission
Allow local things, warns if leave machine? Or stored?

119
build.clj Normal file
View File

@ -0,0 +1,119 @@
(require '[cljs.build.api :as api]
'[clojure.java.shell :as shell]
'[clojure.string :as string])
;;; Configuration.
(def source-dir "src")
(def test-dir "test")
(def compiler-config {:main 'pluto.test
:asset-path "js/out"
:output-to "resources/public/js/pluto.js"
:output-dir "resources/public/js/out"
:optimizations :none
:static-fns true
:closure-defines {"re_frame.trace.trace_enabled_QMARK_" true}
:preloads ['day8.re-frame.trace.preload]
:source-map true})
(def test-config {:main 'my-app.test-runner
:output-to "target/test.js"
:output-dir "target/test"
:optimizations :none
:source-map true})
(def test-environment {:SOME_ENV_VAR "some-env-value"})
(def dev-config (merge compiler-config
{:optimizations :none
:source-map true}))
;;; Tasks mechanism.
(defmulti task first)
(defmethod task :default
[args]
(let [all-tasks (-> task methods (dissoc :default) keys sort (->> (interpose ", ") (apply str)))]
(println "unknown or missing task argument. Choose one of:" all-tasks)
(System/exit 1)))
;;; Helper functions.
(defn run-node-tests []
(let [{:keys [out err exit]} (shell/sh "node" "target/test.js" :env test-environment)]
(println out err)
(= exit 0)))
(defn try-require [ns-sym]
(try (require ns-sym) true (catch Exception e (.printStackTrace e) false)))
(defmacro with-namespaces
[namespaces & body]
(if (every? try-require namespaces)
`(do ~@body)
`(do (println "task not available - required dependencies not found")
(System/exit 1))))
;;; Compiling task.
(defn compile-once []
(api/build source-dir compiler-config))
(defn compile-refresh []
(api/watch source-dir compiler-config))
(defmethod task "compile" [[_ type]]
(case type
(nil "once") (compile-once)
"watch" (compile-refresh)
(do (println "Unknown argument to compile task:" type)
(System/exit 1))))
;;; Testing task
(defn test-once []
(api/build (api/inputs source-dir test-dir) test-config)
(let [success? (run-node-tests)]
(System/exit (if success? 0 1))))
(defn test-refresh []
(api/watch (api/inputs source-dir test-dir)
(assoc test-config :watch-fn run-node-tests)))
(defmethod task "test" [[_ type]]
(case type
(nil "once") (test-once)
"watch" (test-refresh)
(do (println "Unknown argument to test task:" type)
(System/exit 1))))
;;; Figwheeling task
(defmethod task "figwheel" [[_ port]]
(with-namespaces [figwheel-sidecar.repl-api]
(figwheel-sidecar.repl-api/start-figwheel!
{:figwheel-options (cond-> {}
port (merge {:http-server-root "public"
:server-ip "localhost"
:nrepl-port (some-> port Long/parseLong)
:on-jsload "pluto.test/run"
:nrepl-middleware ["cemerick.piggieback/wrap-cljs-repl"]}))
:all-builds [{:id "dev"
:figwheel true
:source-paths [source-dir]
:compiler dev-config}]})
(when-not port
(figwheel-sidecar.repl-api/cljs-repl))))
;;; Build script entrypoint.
(task *command-line-args*)

14
deps.edn Normal file
View File

@ -0,0 +1,14 @@
{:deps {org.clojure/clojurescript {:mvn/version "1.9.946"}
org.clojure/tools.reader {:mvn/version "1.2.1"}
reagent {:mvn/version "0.8.0-alpha2"}
re-frame {:mvn/version "0.10.4"}
binaryage/devtools {:mvn/version "0.9.9"}
day8.re-frame/trace {:mvn/version "0.1.18"}}
:paths ["src" "resources"]
:aliases {:repl
{:extra-deps
{;; Figwheel ClojureScript REPL
com.cemerick/piggieback {:mvn/version "0.2.2"
:exclusions [com.google.javascript/closure-compiler]}
figwheel-sidecar {:mvn/version "0.5.14"
:exclusions [com.google.javascript/closure-compiler]}}}}}

View File

@ -0,0 +1,77 @@
## Unified API
---
### Second slide
> Best quote ever.
---
## Third slide
```clojure
[div
[text ""]]
```
---
## Competition models
---
### Toshi
* Regular DApps
* chatbot model
* no integration / extension points
---
### Cipher
* Regular DApps
* no chatbot
* no integration / extension points
https://github.com/dawnlabs/carbon
## 4 slide
<div class="test">
TOTO
</div>
<div class="fragment" data-fragment-index="3">Appears last</div>
<div class="fragment" data-fragment-index="1">Appears first</div>
<div class="fragment" data-fragment-index="2">Appears second</div>
<button onclick="alert('Vous avez cliqué !');">
Hello
</button>
Note: speaker notes FTW!
## Security
Do not reproduce web failures (cookies, localStorage)
Allow access by default?
But data sending preventing by default
No external connection allowed
Permission per remote host
https://blog.colony.io/securing-local-storage-for-dapps-33dc4d52e1fd
Dev model:
similar to REST API (expose actions, not data model)
http://www.amundsen.com/blog/archives/1167

View File

@ -0,0 +1,261 @@
/**
* A simple theme for reveal.js presentations, similar
* to the default theme. The accent color is darkblue.
*
* This theme is Copyright (C) 2012 Owen Versteeg, https://github.com/StereotypicalApps. It is MIT licensed.
* reveal.js is Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
*/
@import url(https://fonts.googleapis.com/css?family=News+Cycle:400,700);
@import url(https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic);
section.has-dark-background, section.has-dark-background h1, section.has-dark-background h2, section.has-dark-background h3, section.has-dark-background h4, section.has-dark-background h5, section.has-dark-background h6 {
color: #fff; }
/*********************************************
* GLOBAL STYLES
*********************************************/
body {
background-color: #4957b8; }
.reveal {
font-family: "Lato", sans-serif;
font-size: 40px;
font-weight: normal;
color: #fff; }
::selection {
color: #fff;
background: rgba(0, 0, 0, 0.99);
text-shadow: none; }
.reveal .slides > section,
.reveal .slides > section > section {
line-height: 1.3;
font-weight: inherit; }
/*********************************************
* HEADERS
*********************************************/
.reveal h1,
.reveal h2,
.reveal h3,
.reveal h4,
.reveal h5,
.reveal h6 {
margin: 0 0 20px 0;
color: #fff;
font-family: "PostGrotesk-Medium", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
font-weight: normal;
line-height: 1.2;
letter-spacing: normal;
text-transform: none;
text-shadow: none;
word-wrap: break-word; }
.reveal h1 {
font-size: 3.77em; }
.reveal h2 {
font-size: 2.11em; }
.reveal h3 {
font-size: 1.55em; }
.reveal h4 {
font-size: 1em; }
.reveal h1 {
text-shadow: none; }
/*********************************************
* OTHER
*********************************************/
.reveal p {
margin: 20px 0;
line-height: 1.3; }
/* Ensure certain elements are never larger than the slide itself */
.reveal img,
.reveal video,
.reveal iframe {
max-width: 95%;
max-height: 95%; }
.reveal strong,
.reveal b {
font-weight: bold; }
.reveal em {
font-style: italic; }
.reveal ol,
.reveal dl,
.reveal ul {
display: inline-block;
text-align: left;
margin: 0 0 0 1em; }
.reveal ol {
list-style-type: decimal; }
.reveal ul {
list-style-type: disc; }
.reveal ul ul {
list-style-type: square; }
.reveal ul ul ul {
list-style-type: circle; }
.reveal ul ul,
.reveal ul ol,
.reveal ol ol,
.reveal ol ul {
display: block;
margin-left: 40px; }
.reveal dt {
font-weight: bold; }
.reveal dd {
margin-left: 40px; }
.reveal blockquote {
display: block;
position: relative;
width: 70%;
margin: 20px auto;
padding: 5px;
font-style: italic;
background: rgba(255, 255, 255, 0.05);
box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2); }
.reveal blockquote p:first-child,
.reveal blockquote p:last-child {
display: inline-block; }
.reveal q {
font-style: italic; }
.reveal pre {
display: block;
position: relative;
width: 90%;
margin: 20px auto;
text-align: left;
font-size: 0.55em;
font-family: monospace;
line-height: 1.2em;
word-wrap: break-word;
box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.3); }
.reveal code {
font-family: monospace;
text-transform: none; }
.reveal pre code {
display: block;
padding: 5px;
overflow: auto;
max-height: 400px;
word-wrap: normal; }
.reveal table {
margin: auto;
border-collapse: collapse;
border-spacing: 0; }
.reveal table th {
font-weight: bold; }
.reveal table th,
.reveal table td {
text-align: left;
padding: 0.2em 0.5em 0.2em 0.5em;
border-bottom: 1px solid; }
.reveal table th[align="center"],
.reveal table td[align="center"] {
text-align: center; }
.reveal table th[align="right"],
.reveal table td[align="right"] {
text-align: right; }
.reveal table tbody tr:last-child th,
.reveal table tbody tr:last-child td {
border-bottom: none; }
.reveal sup {
vertical-align: super; }
.reveal sub {
vertical-align: sub; }
.reveal small {
display: inline-block;
font-size: 0.6em;
line-height: 1.2em;
vertical-align: top; }
.reveal small * {
vertical-align: top; }
/*********************************************
* LINKS
*********************************************/
.reveal a {
color: #00008B;
text-decoration: none;
-webkit-transition: color .15s ease;
-moz-transition: color .15s ease;
transition: color .15s ease; }
.reveal a:hover {
color: #0000f1;
text-shadow: none;
border: none; }
.reveal .roll span:after {
color: #fff;
background: #00003f; }
/*********************************************
* IMAGES
*********************************************/
.reveal section img {
margin: 15px 0px;
background: rgba(255, 255, 255, 0.12);
border: 4px solid #000;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); }
.reveal section img.plain {
border: 0;
box-shadow: none; }
.reveal a img {
-webkit-transition: all .15s linear;
-moz-transition: all .15s linear;
transition: all .15s linear; }
.reveal a:hover img {
background: rgba(255, 255, 255, 0.2);
border-color: #00008B;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); }
/*********************************************
* NAVIGATION CONTROLS
*********************************************/
.reveal .controls {
color: #00008B; }
/*********************************************
* PROGRESS BAR
*********************************************/
.reveal .progress {
background: rgba(0, 0, 0, 0.2);
color: #00008B; }
.reveal .progress span {
-webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
-moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); }

1
scripts/figwheel.sh Executable file
View File

@ -0,0 +1 @@
clj -R:repl build.clj figwheel

46
src/pluto/README.md Normal file
View File

@ -0,0 +1,46 @@
# Use case
## Hello world
A dumb text showing "Hello world"
QmbXjFEF6WbxNb4gyZE3JkEGG3ur4fmDgvo5vsQvdy95vW
[screen
[text "Hello world"]]
## Basic data interaction
inc/dec buttons, some text showing the count
```main.edn
:main
[screen
[text #subscribe ::counter]
[button {:on-press #dispatch ::dec}
"Dec"]
[button {:on-press #dispatch ::inc}
"Inc"]]
```
## Basic transaction
Send some STT to an exeisting address
## Reuse screens
Browse contact, select one, then open wallet send transaction screen pre-populated with this contact.
## TO think about
# ENS
# IPFS storage
### Remotely load JS code in react-native
https://github.com/MaxLeap/HotLoad-SDK
https://github.com/Microsoft/react-native-code-push
https://docs.expo.io/versions/latest/guides/how-expo-works.html
https://www.aerofs.com/reactnativeautoupdater-dynamic-updates-to-react-native-apps/
https://github.com/redbooth/react-native-auto-updater/

3
src/pluto/core.cljc Normal file
View File

@ -0,0 +1,3 @@
(ns pluto.core
)

26
src/pluto/feedback.md Normal file
View File

@ -0,0 +1,26 @@
IP company
Push a number of papers
Lots of photo / video to take
Doctor
Ask to do tests
Do some tests
Then chat with Doctor
Transfer to Doctor
=> chat bot?
german iOT (manufacturing as a service)
Machine with crypto integration
Interraction with machine directly?
airbnb on blockchain
chat representing the company?
web3.js
constantly breaking
make send transaction easy

14
src/pluto/hiccup.cljc Normal file
View File

@ -0,0 +1,14 @@
(ns pluto.hiccup
(:require [clojure.spec.alpha :as spec]))
(spec/def :hiccup/form
(spec/or
:string string?
:number number?
:element :hiccup/element))
(spec/def :hiccup/element
(spec/cat
:tag keyword?
:attrs (spec/? map?)
:children (spec/* :hiccup/form)))

88
src/pluto/pres.md Normal file
View File

@ -0,0 +1,88 @@
## Add a slide on ideas
## Remove side by side code comparison
# 14
## Transparency
We are all about open blockchain interactions. Rely on standard.
Security is one of our pillar so we require transparency. We don't believe in security by obscurity.
100% of our codebase is opensource. Accessible for everyone to see, participate.
##Contribution
That's the main idea behind OpenBounty. Anyone can join and contribute to the product, and make some money.
Actually we even use those contributions to hire new people.
Oh BTW even openbounty is opensource!
One fancy DApp you can use and see how it works.
##Audit
Because all source code is available you can check what and how things are done.
BTW we are planning a security audit that will be publicly available.
##Tweak
You can even tweak the app yourself, build it and use it as is on your phone!
# 15
2 main projects. More are coming!
status-react
UI part of this app. This is whera chat, wallet and DApp browsing is implemented.
One codebase for iOS and android.
Using modern stack (ClojureScript, react-native).
Providing best user experience we can.
Currently going through massive simplification and performance oriented work.
status-go
Our layer to the ethereum world, built on top of ethereum libraries
ethereum is desktop technology, so all optimization work happen here
Also heavily invested in optimization of ethereum itself and contributing to new technologies (LES2, new whisper)
Others: status-desktop, status-electron, hardwallet
# 16
Even part of our process is opensource
You can see our proposition as they arrive, vote on them, comment on them
Look at ideas repo
# 17
Not a typical app
Not a typical client server app
Part of a mesh network
Part of the ethereum network
Status is a complete light node
not mining obviously
Relay whisper messages
Opens door to a lot of inovation
Also remember status-desktop has same stack
Why not iOT stuff?
# 18
Open inovation internally
You have an idea? Make a proposition, convince people, work on it
Example of status-desktop POC
Alternative to our current QT effort
A new effort from scratch using electron JS tech stack
Reuse our logic
Already functional and usable, even if still basic
# 19
Mesh newtwork
Issues, not enough nodes
Could be controlled by big miners?
A need for much more small nodes
# 20
Mesh with status nodes included
phone
desktop
long running nodes on top of raspberry
How to incentivize people having long running nodes?
Incentivized layers
* swarm for files
* streaming
* relayer
Part of the answer?

12
src/pluto/semantic.md Normal file
View File

@ -0,0 +1,12 @@
how it maps to db
switch network
account
addresses
whisper key
wallet
local
hardware

174
src/pluto/test.cljs Normal file
View File

@ -0,0 +1,174 @@
(ns pluto.test
(:require [clojure.tools.reader.edn :as edn]
[clojure.walk :as walk]
[reagent.core :as reagent]
[re-frame.core :as rf]
[re-frame.loggers :as rf.loggers]
[clojure.string :as str]
[devtools.core :as devtools]))
(devtools/install!)
;; A detailed walk-through of this source code is provided in the docs:
;; https://github.com/Day8/re-frame/blob/master/docs/CodeWalkthrough.md
;; -- Domino 1 - Event Dispatch -----------------------------------------------
(defn dispatch-timer-event
[]
(let [now (js/Date.)]
(rf/dispatch [:timer now]))) ;; <-- dispatch used
;; Call the dispatching function every second.
;; `defonce` is like `def` but it ensures only one instance is ever
;; created in the face of figwheel hot-reloading of this file.
(defonce do-timer (js/setInterval dispatch-timer-event 1000))
;; -- Domino 2 - Event Handlers -----------------------------------------------
(rf/reg-event-db ;; sets up initial application state
:initialize ;; usage: (dispatch [:initialize])
(fn [_ _] ;; the two parameters are not important here, so use _
{:time (js/Date.) ;; What it returns becomes the new application state
:time-color "#f88"})) ;; so the application state will initially be a map with two keys
(rf/reg-event-db ;; usage: (dispatch [:time-color-change 34562])
:time-color-change ;; dispatched when the user enters a new colour into the UI text field
(fn [db [_ new-color-value]] ;; -db event handlers given 2 parameters: current application state and event (a vector)
(assoc db :time-color new-color-value))) ;; compute and return the new application state
(rf/reg-event-db ;; usage: (dispatch [:timer a-js-Date])
:timer ;; every second an event of this kind will be dispatched
(fn [db [_ new-time]] ;; note how the 2nd parameter is destructured to obtain the data value
(assoc db :time new-time))) ;; compute and return the new application state
;; -- Domino 4 - Query -------------------------------------------------------
(rf/reg-sub
:time
(fn [db _] ;; db is current app state. 2nd unused param is query vector
(:time db))) ;; return a query computation over the application state
(rf/reg-sub
:time-color
(fn [db _]
(:time-color db)))
;; -- Domino 5 - View Functions ----------------------------------------------
(defn clock
[]
[:div.example-clock
{:style {:color @(rf/subscribe [:time-color])}}
(-> @(rf/subscribe [:time])
.toTimeString
(str/split " ")
first)])
(defn color-input
[]
[:div.color-input
"Time color: "
[:input {:type "text"
:value @(rf/subscribe [:time-color])
:on-change #(rf/dispatch [:time-color-change (-> % .-target .-value)])}]]) ;; <---
(defn screen [props content]
[:div props content])
(defn button [props content]
[:button props content])
(defn text [props content]
[:text props content])
(def components {:text text
:screen screen})
(defn my-unknown [tag val]
{:unknown-tag tag :value val})
(defn subscribe [o]
@(rf/subscribe o))
(defn parse-view [s]
(edn/read-string {:default my-unknown :readers {'subscribe subscribe}}
s))
(defn split [[o & rest]]
(apply conj [((keyword o) components)] rest))
(defn translate-components [o]
(walk/postwalk (fn [x]
(if (vector? x)
(split o)
x)) o))
(defn body [r f]
(.then r f))
(defn load-http [s f]
(let [xhr (js/XMLHttpRequest.)]
(.open xhr "GET" (str s "/main.edn") true)
(.send xhr nil)
(set! (.-onreadystatechange xhr)
#(when (= (.-readyState xhr) 4)
(f (.-response xhr))))))
(defn ipfs->map [o]
{:content (.toString (get o "content") "utf8")})
(defn parse-ipfs-files [err o]
(println "PARSE" o)
(let [v (js->clj o)]
(println (map ipfs->map v))))
(defn dump [err]
(println "ERR" err)
)
(defn load-ipfs [ipfs f]
(let [o ((.-get (.-files ipfs)) "QmbXjFEF6WbxNb4gyZE3JkEGG3ur4fmDgvo5vsQvdy95vW")]
(js/console.log ">>" o)))
(defn load-view [s]
(-> s
parse-view
translate-components))
(def warn (js/console.warn.bind js/console))
(rf.loggers/set-loggers!
{:warn (fn [& args]
(cond
(= "re-frame: overwriting" (first args)) nil
:else (apply warn args)))})
(enable-console-print!)
(defn render [h]
(println "RENDER" h)
;document.getElementById('myframe1').contentWindow.
(let [frame (js/document.getElementById "frame")]
(println "FRAME" frame)
(println "doc" (aget frame "contentWindow") (.getElementById (aget frame "contentWindow" "document") "app") )
(reagent/render h (.-body (aget frame "contentWindow" "document")))))
(defn ^:export run
[]
(println "RUN")
(rf/clear-subscription-cache!)
(rf/dispatch-sync [:initialize]) ;; puts a value into application state
(load-http "hello"
#(-> %
load-view
render))
#_
(let [ipfs (js/Ipfs.)]
(load-ipfs ipfs render)))