├── clean.sh
├── rebar3
├── config
├── sys.config.tmpl
└── vm.args
├── js
├── favicon.ico
├── test.html
├── glossary.js
├── active_oracles.js
├── active_oracles.html
├── main.html
├── add.js
├── server.js
├── rpc.js
├── utils.js
├── main.js
└── oracle_list.js
├── attach.sh
├── apps
└── amoveo_p2p_derivatives_explorer
│ └── src
│ ├── pair_buy.erl
│ ├── amoveo_p2p_derivatives_explorer.app.src
│ ├── db.erl
│ ├── amoveo_p2p_derivatives_explorer_app.erl
│ ├── records.hrl
│ ├── amoveo_p2p_derivatives_explorer_sup.erl
│ ├── swap_markets.erl
│ ├── swap_full.erl
│ ├── file_handler.erl
│ ├── utils.erl
│ ├── talker.erl
│ ├── swap_history.erl
│ ├── binary_contracts.erl
│ ├── buy_veo_orders.erl
│ ├── scalar_contracts.erl
│ ├── swap_verify.erl
│ ├── http_handler.erl
│ └── swap_books.erl
├── .gitignore
├── empty_gen_server.save
├── start.sh
├── rebar.config
└── README.md
/clean.sh:
--------------------------------------------------------------------------------
1 | rm _build/prod/rel/amoveo_p2p_derivatives_explorer/*.db
2 |
--------------------------------------------------------------------------------
/rebar3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zack-bitcoin/Amoveo_p2p_derivatives_explorer/master/rebar3
--------------------------------------------------------------------------------
/config/sys.config.tmpl:
--------------------------------------------------------------------------------
1 | [
2 | { amoveo_p2p_derivatives_explorer, [
3 | {test_mode, false}
4 | ]}
5 | ].
6 |
--------------------------------------------------------------------------------
/js/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zack-bitcoin/Amoveo_p2p_derivatives_explorer/master/js/favicon.ico
--------------------------------------------------------------------------------
/config/vm.args:
--------------------------------------------------------------------------------
1 | -sname amoveo_p2p_derivatives_explorer
2 |
3 | -setcookie amoveo_p2p_derivatives_explorer_cookie
4 |
5 | +K true
6 | +A30
7 |
--------------------------------------------------------------------------------
/attach.sh:
--------------------------------------------------------------------------------
1 | ./_build/prod/rel/amoveo_p2p_derivatives_explorer/bin/amoveo_p2p_derivatives_explorer attach
2 | # ./_build/prod/rel/amoveo_p2p_derivatives_explorer/bin/amoveo_p2p_derivatives_explorer daemon_attach
3 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/pair_buy.erl:
--------------------------------------------------------------------------------
1 | -module(pair_buy).
2 | -export([]).
3 |
4 | -record(pair_buy_offer,
5 | {from, nonce, start_limit,
6 | end_limit, source_id,
7 | source_type, contract_hash,
8 | new_id, amount1, fee1,
9 | amount2, fee2, subs1, subs2}).
10 |
11 |
12 |
--------------------------------------------------------------------------------
/js/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Amoveo P2P derivatives explorer - home
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .edts
3 | *.iml
4 | _build
5 | /rel/
6 | *.db
7 | *~
8 | .#*
9 | \#*
10 | .rebar
11 | erl_crash.dump
12 | keys_backup
13 | lib/
14 | bin/
15 | .Python
16 | include/
17 | *.pyc
18 | nosetests.xml
19 | pip-selfcheck.json
20 | config/*/sys.config
21 | config/sys.config
22 | man
23 | compile_commands.json
24 | deps/*
25 | rebar.lock
26 | .DS_Store
--------------------------------------------------------------------------------
/empty_gen_server.save:
--------------------------------------------------------------------------------
1 | -module().
2 | -behaviour(gen_server).
3 | -export([start_link/0,code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2]).
4 | init(ok) -> {ok, []}.
5 | start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, ok, []).
6 | code_change(_OldVsn, State, _Extra) -> {ok, State}.
7 | terminate(_, _) -> io:format("died!"), ok.
8 | handle_info(_, X) -> {noreply, X}.
9 | handle_cast(_, X) -> {noreply, X}.
10 | handle_call(_, _From, X) -> {reply, X, X}.
--------------------------------------------------------------------------------
/js/glossary.js:
--------------------------------------------------------------------------------
1 | var glossary = (function(){
2 | function helper(div, name) {
3 | return helper2(div, name, "(?)");
4 | };
5 | function helper2(div, name, s) {
6 | var x = document.createElement("a");
7 | x.innerHTML = s;
8 | x.href = "https://github.com/zack-bitcoin/amoveo/tree/master/docs/light_node/glossary/".concat(name).concat(".md");
9 | x.target = "_blank";
10 | div.appendChild(x);
11 | };
12 | return {link: helper, link2: helper2}
13 | })();
14 |
--------------------------------------------------------------------------------
/start.sh:
--------------------------------------------------------------------------------
1 | #set up a config file if it does not already exist.
2 | if [ ! -f config/sys.config ]; then
3 | cp config/sys.config.tmpl config/sys.config
4 | echo "File not found!"
5 | fi
6 |
7 | # First recompile the code and rebuild the release.
8 | ./rebar3 compile
9 | ./rebar3 as prod release
10 | # then launch the software
11 | ./_build/prod/rel/amoveo_p2p_derivatives_explorer/bin/amoveo_p2p_derivatives_explorer start
12 | # ./_build/prod/rel/amoveo_p2p_derivatives_explorer/bin/amoveo_p2p_derivatives_explorer daemon
13 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/amoveo_p2p_derivatives_explorer.app.src:
--------------------------------------------------------------------------------
1 | {application, amoveo_p2p_derivatives_explorer,
2 | [{description, "An OTP application"},
3 | {vsn, "0.1.0"},
4 | {registered, []},
5 | {mod, { amoveo_p2p_derivatives_explorer_app, []}},
6 | {applications,
7 | [kernel,
8 | stdlib,
9 | ssl,
10 | cowboy,
11 | inets,
12 | encrypter,
13 | jiffy,
14 | pink_hash,
15 | chalang,
16 | compiler
17 | ]},
18 | {env,[]},
19 | {modules, []},
20 |
21 | {maintainers, []},
22 | {licenses, ["Apache 2.0"]},
23 | {links, []}
24 | ]}.
25 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/db.erl:
--------------------------------------------------------------------------------
1 | -module(db).
2 | -export([test/0, save/2, read/1]).
3 | save(F, X) -> file:write_file(F, term_to_binary(X)).
4 | read(F) ->
5 | case file:read_file(F) of
6 | {ok, <<>>} -> <<>>;
7 | {ok, Out} -> binary_to_term(Out);
8 | {error, enoent} ->
9 | %io:fwrite("file does not exist\n"),
10 | "";
11 | {error, Reason} -> Reason
12 | end.
13 | -record(d, {a = "", b = "" }).
14 | test() ->
15 | X = #d{a=[1, 2, <<"abc">>, []], b = <<1,2,3,200>> },
16 | File = "database.db",
17 | save(File, X),
18 | X = read(File),
19 | success.
20 |
--------------------------------------------------------------------------------
/js/active_oracles.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var div = document.createElement("div");
3 | document.body.appendChild(div);
4 | variable_public_get(["oracle_list", 2], function(X) {
5 | //console.log(JSON.stringify(X));
6 | return display_oracles(X.slice(1));
7 | });
8 | function display_oracles(L) {
9 | if ((JSON.stringify(L)) == "[]") {
10 | return [];
11 | }
12 | var L1 = L[0];
13 | var p = document.createElement("p");
14 | p.innerHTML = ("").concat(L1[2][1]).concat(" ").concat(atob(L1[1]));
15 | div.appendChild(p);
16 | return display_oracles(L.slice(1));
17 | };
18 | })();
19 |
--------------------------------------------------------------------------------
/js/active_oracles.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Amoveo oracles explorer - home
6 | Here is a light node tool in your browser, you can use it to make derivatives for any of these oracles
7 |
8 | Return to the page for exploring available P2P derivative bets.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/js/main.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Amoveo P2P derivatives explorer - home
6 | Here is a light node tool in your browser, you can use it to participate in P2P derivatives contracts on Amoveo.
7 |
8 | Here you can see all the oracles available to bet on.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/amoveo_p2p_derivatives_explorer_app.erl:
--------------------------------------------------------------------------------
1 | -module(amoveo_p2p_derivatives_explorer_app).
2 | -behaviour(application).
3 | -export([start/2, stop/1]).
4 | start(_StartType, _StartArgs) ->
5 | inets:start(),
6 | start_http(),
7 | swap_history:garbage_cron(),
8 | swap_books:garbage_cron(),
9 | spawn(fun() -> scalar_contracts:cron() end),
10 | amoveo_p2p_derivatives_explorer_sup:start_link().
11 | stop(_State) ->
12 | ok.
13 | start_http() ->
14 | Dispatch =
15 | cowboy_router:compile(
16 | [{'_', [
17 | {"/:file", file_handler, []},
18 | {"/", http_handler, []}
19 | ]}]),
20 | %{ok, Port} = application:get_env(amoveo_mining_pool, port),
21 | Port = 8090,
22 | IP = {0,0,0,0},
23 | {ok, _} = cowboy:start_clear(
24 | http,
25 | [{ip, IP}, {port, Port}],
26 | #{env => #{dispatch => Dispatch}}),
27 | ok.
28 |
29 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/records.hrl:
--------------------------------------------------------------------------------
1 | -record(swap_tx, {from, offer, fee}).
2 | -record(swap_tx2, {from, nonce, fee, offer, match_parts}).
3 | -record(swap_offer, {
4 | acc1, start_limit, end_limit, salt,
5 | amount1, cid1, type1, %this is what acc1 gives.
6 | amount2, cid2, type2, %this is what acc2 gives.
7 | fee1, %what acc1 pays in fees
8 | nonce}).
9 | -record(swap_offer2, {
10 | acc1, start_limit, end_limit,
11 | cid1, type1, amount1,
12 | cid2, type2, amount2,
13 | salt, start_nonce, parts}).
14 | -record(acc, {balance = 0, %amount of money you have
15 | nonce = 0, %increments with every tx you put on the chain.
16 | pubkey = <<>>,
17 | bets = 1,%This is a pointer to the merkel tree that stores how many bets you have made in each oracle.
18 | bets_hash = <<>>}).
19 | -record(sub_acc, {balance = 0,
20 | nonce = 0,
21 | pubkey,
22 | contract_id,
23 | type}).
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/amoveo_p2p_derivatives_explorer_sup.erl:
--------------------------------------------------------------------------------
1 | -module(amoveo_p2p_derivatives_explorer_sup).
2 | -behaviour(supervisor).
3 | -export([start_link/0, init/1, stop/0]).
4 | -define(SERVER, ?MODULE).
5 | -define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
6 | -define(keys, [swap_history,
7 | swap_books,
8 | swap_full,
9 | swap_markets,
10 | scalar_contracts,
11 | binary_contracts,
12 | buy_veo_orders
13 | ]).
14 | %active_oracles, oracles, channel_offers_ram, channel_offers_hd, volume_order, close_offers]).
15 | start_link() ->
16 | supervisor:start_link({local, ?SERVER}, ?MODULE, []).
17 | child_killer([]) -> ok;
18 | child_killer([H|T]) ->
19 | supervisor:terminate_child(amoveo_p2p_derivatives_explorer_sup, H),
20 | child_killer(T).
21 | stop() -> child_killer(?keys).
22 | child_maker([]) -> [];
23 | child_maker([H|T]) -> [?CHILD(H, worker)|child_maker(T)].
24 | init([]) ->
25 | Children = child_maker(?keys),
26 | {ok, { {one_for_all, 50000, 1}, Children} }.
27 |
--------------------------------------------------------------------------------
/rebar.config:
--------------------------------------------------------------------------------
1 | {erl_opts, [debug_info]}.
2 | {deps, [
3 | {cowboy, "2.10.0", {git, "https://github.com/ninenines/cowboy.git", {tag, "2.10.0"}}},
4 | {pink_hash, "1", {git, "https://github.com/BumblebeeBat/pink_crypto", {tag, "master"}}},
5 | {chalang, "1", {git, "https://github.com/zack-bitcoin/chalang", {tag, "master"}}},
6 | {encrypter, "1", {git, "https://github.com/zack-bitcoin/encrypter", {tag, "master"}}}
7 | ]}.
8 |
9 | {relx, [{release, { amoveo_p2p_derivatives_explorer, "0.1.0" },
10 | [amoveo_p2p_derivatives_explorer,
11 | sasl]},
12 |
13 | {sys_config, "./config/sys.config"},
14 | {vm_args, "./config/vm.args"},
15 |
16 | {dev_mode, true},
17 | {include_erts, false},
18 |
19 | {extended_start_script, true}]
20 | }.
21 |
22 | {profiles, [{prod, [{relx, [{dev_mode, false},
23 | {include_erts, true}]}]
24 | }]
25 | }.
26 | {overrides,
27 | [{override, jiffy, [
28 | {plugins, [pc]},
29 | {artifacts, ["priv/jiffy.so"]},
30 | {provider_hooks, [
31 | {post,
32 | [
33 | {compile, {pc, compile}},
34 | {clean, {pc, clean}}
35 | ]
36 | }]
37 | }
38 | ]}
39 | ]}.
40 |
--------------------------------------------------------------------------------
/js/add.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var div = document.createElement("div");
3 | document.body.appendChild(div);
4 | var status = document.createElement("p");
5 | status.innerHTML = "add offer status: ready";
6 | div.appendChild(status);
7 | div.appendChild(br());
8 | var contract = text_input("channel offer: ", div);
9 | div.appendChild(br());
10 | //var question_text = text_input("if the oracle does not yet exist, put the question text here: ", div);
11 | //div.appendChild(br());
12 | //var expires = text_input("if the oracle does not yet exist, put the height when it becomes possible to trade here: ", div);
13 | //div.appendChild(br());
14 | var Button = button_maker2("publish the channel offer", publish);
15 | div.appendChild(Button);
16 | function publish() {
17 | status.innerHTML = "add offer status: failed";
18 | var c = JSON.parse(contract.value);
19 | //c = c.concat([[-7,
20 | // btoa(question_text.value),
21 | // parseInt(expires.value)]]);
22 | variable_public_get(["add", c], function(X) {
23 | status.innerHTML = "add offer status: successfully posted a trade";
24 | });
25 | };
26 | })();
27 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/swap_markets.erl:
--------------------------------------------------------------------------------
1 | %store a copy of data about the current set of markets here.
2 |
3 | %every few minutes we want to rescan the open trades, and make a new version of data to store here.
4 |
5 | -module(swap_markets).
6 | -behaviour(gen_server).
7 | -export([start_link/0,code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2,
8 | read/0, refresh/0,
9 | cron/0]).
10 | -record(x, {id, cid1, type1, cid2, type2}).
11 | init(ok) -> {ok, []}.
12 | start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, ok, []).
13 | code_change(_OldVsn, State, _Extra) -> {ok, State}.
14 | terminate(_, _) -> io:format("died!"), ok.
15 | handle_info(_, X) -> {noreply, X}.
16 | handle_cast(refresh, _) ->
17 | %scan all open trades
18 | X = swap_books:markets(),
19 | {noreply, X};
20 | handle_cast(_, X) -> {noreply, X}.
21 | handle_call(read, _From, X) ->
22 | {reply, X, X};
23 | handle_call(_, _From, X) -> {reply, X, X}.
24 |
25 | read() -> gen_server:call(?MODULE, read).
26 | refresh() -> gen_server:cast(?MODULE, refresh).
27 |
28 | cron() ->
29 | timer:sleep(5000),
30 | spawn(fun() ->
31 | refresh()
32 | end),
33 | spawn(fun() ->
34 | cron()
35 | end).
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | amoveo_p2p_derivatives_explorer
2 | =====
3 |
4 | The purpose of this tool is so that people can make P2P derivatives offers from the amoveo light node, and post them to this website. The website organizes all the different trade offers that are posted.
5 |
6 |
7 | turn it on, then open this in a browser: http://localhost:8090/main.html
8 |
9 |
10 | Turning it on and off
11 | =======
12 |
13 | First make sure you have an Amoveo node running and fully synced, and that the keys are unlocked on that node.
14 |
15 | If you need to resync your full node, be sure to turn off this p2p_derivatives tool first.
16 |
17 | ```
18 | sh start.sh
19 | ```
20 |
21 | To connect to it, so you can give it commands:
22 | ```
23 | sh attach.sh
24 | ```
25 | If it says "Node is not running!", this means that the Amoveo p2p derivatives explorer is shut off and there is nothing for you to connect to. So try using start.sh to turn it on.
26 |
27 | To disconnect, and allow it to run in the background, hold the CTRL key, and press D.
28 |
29 | Then to turn it off, make sure you are attached, and run:
30 |
31 | ```
32 | utils:off().
33 | ```
34 | then run:
35 | ```
36 | halt().
37 | ```
38 |
39 | Syncing smart contracts
40 | ============
41 | ```
42 | scalar_contracts:sync({159,89,87,58}, 8090).
43 | buy_veo_orders:sync({159,89,87,58}, 8090).
44 | ```
45 |
46 | this will pull all the oracle text, and what you need to settle the scalar contracts.
--------------------------------------------------------------------------------
/js/server.js:
--------------------------------------------------------------------------------
1 | //make ip and port as input things.
2 |
3 | local_ip = [127,0,0,1];
4 | local_port = 8090;
5 | var server_ip = document.createElement("INPUT");
6 | server_ip.setAttribute("type", "text");
7 | //server_ip.value = "159.89.106.253";// server
8 | server_ip.value = document.URL.split("/")[2].split(":")[0];
9 | var server_ip_info = document.createElement("h8");
10 | server_ip_info.innerHTML = "channel node IP: ";
11 | var server_port = document.createElement("INPUT");
12 | //server_port.value = "8080";// server
13 | //console.log(server_port.value);
14 | var URL_REGEX = /^(https?)?(?:[\:\/]*)([a-z0-9\.-]*)(?:\:([0-9]+))?(\/[^?#]*)?(?:\?([^#]*))?(?:#(.*))?$/i;
15 | var match = document.URL.match(URL_REGEX);
16 | //console.log(match);
17 | if (match !== null){
18 | var host = match[2];
19 | var port = match[3];
20 | console.log(port);
21 | if (document.URL[0] == 'f') {
22 | console.log("running stand-alone light node");
23 | } else {
24 | console.log("running light node served from a full node");
25 | server_port.value = port;
26 | // server_port.value = document.URL.split(":")[2].substring(0, 4);
27 | };
28 | };
29 | server_port.setAttribute("type", "text");
30 | var server_port_info = document.createElement("h8");
31 | server_port_info.innerHTML = "port: ";
32 | /*
33 | document.body.appendChild(server_ip_info);
34 | document.body.appendChild(server_ip);
35 | document.body.appendChild(server_port_info);
36 | document.body.appendChild(server_port);
37 |
38 | document.body.appendChild(document.createElement("br"));
39 | document.body.appendChild(document.createElement("br"));
40 | */
41 |
42 | function get_port() {
43 | return parseInt(server_port.value, 10);
44 | }
45 | function get_ip() {
46 | //return JSON.parse(server_ip.value);
47 | return server_ip.value;
48 | }
49 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/swap_full.erl:
--------------------------------------------------------------------------------
1 | -module(swap_full).
2 | -behaviour(gen_server).
3 | -export([start_link/0,code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2]).
4 | -export([read/1, add/3, remove/1]).
5 |
6 | %for storing the entire data of swap offers
7 |
8 | %-record(swap_offer, {
9 | % acc1, start_limit, end_limit, salt,
10 | % amount1, cid1, type1, %this is what acc1 gives.
11 | % amount2, cid2, type2, %this is what acc2 gives.
12 | % fee1, %what acc1 pays in fees
13 | % fee2}).
14 | %-record(swap_offer2, {
15 | % acc1, start_limit, end_limit,
16 | % cid1, type1, amount1,
17 | % cid2, type2, amount2,
18 | % salt, start_nonce, parts}).
19 |
20 | -define(LOC, "swap_full.db").
21 |
22 | init(ok) ->
23 | process_flag(trap_exit, true),
24 | X = db:read(?LOC),
25 | Y = if
26 | (X == "") -> dict:new();
27 | true -> X
28 | end,
29 | {ok, Y}.
30 | start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, ok, []).
31 | code_change(_OldVsn, State, _Extra) -> {ok, State}.
32 | terminate(_, X) ->
33 | db:save(?LOC, X),
34 | io:format("swap full died!"),
35 | ok.
36 | handle_info(_, X) -> {noreply, X}.
37 | handle_cast({add, ID, S, T}, X) ->
38 | X2 = dict:store(ID, {S, T}, X),
39 | {noreply, X2};
40 | handle_cast({remove, ID}, X) ->
41 | X2 = dict:erase(ID, X),
42 | {noreply, X2};
43 | handle_cast(_, X) -> {noreply, X}.
44 | handle_call({read, ID}, _From, X) ->
45 | Z = dict:find(ID, X),
46 | {reply, Z, X};
47 | handle_call(_, _From, X) -> {reply, X, X}.
48 |
49 | read(ID) -> gen_server:call(?MODULE, {read, ID}).
50 | add(ID, S, X) -> gen_server:cast(?MODULE, {add, ID, S, X}).
51 | remove(ID) -> gen_server:cast(?MODULE, {remove, ID}).
52 |
53 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/file_handler.erl:
--------------------------------------------------------------------------------
1 | -module(file_handler).
2 |
3 | -export([init/3, handle/2, terminate/3]).
4 | %example of talking to this handler:
5 | %httpc:request(post, {"http://127.0.0.1:3011/", [], "application/octet-stream", "echo"}, [], []).
6 | %curl -i -d '[-6,"test"]' http://localhost:3011
7 | handle(Req, _) ->
8 | {F, _} = cowboy_req:path(Req),
9 | PrivDir0 = "../../../../js",
10 | PrivDir = list_to_binary(PrivDir0),
11 | true = case F of
12 | <<"/add.js">> -> true;
13 | <<"/active_oracles.js">> -> true;
14 | <<"/active_oracles.html">> -> true;
15 | <<"/glossary.js">> -> true;
16 | <<"/utils.js">> -> true;
17 | <<"/oracle_list.js">> -> true;
18 | <<"/favicon.ico">> -> true;
19 | <<"/main.html">> -> true;
20 | <<"/test.html">> -> true;
21 | <<"/main.js">> -> true;
22 | <<"/rpc.js">> -> true;
23 | <<"/server.js">> -> true;
24 | X ->
25 | io:fwrite("ext file handler block access to: "),
26 | io:fwrite(X),
27 | io:fwrite("\n"),
28 | false
29 | end,
30 | %File = << PrivDir/binary, <<"/external_web">>/binary, F/binary>>,
31 | File = << PrivDir/binary, F/binary>>,
32 | %{ok, _Data, _} = cowboy_req:body(Req),
33 | {ok, _Data, _} = cowboy_req:read_body(Req),
34 | Headers = [{<<"content-type">>, <<"text/html">>},
35 | {<<"Access-Control-Allow-Origin">>, <<"*">>}],
36 | Text = read_file(File),
37 | {ok, Req2} = cowboy_req:reply(200, Headers, Text, Req),
38 | {ok, Req2, File}.
39 | read_file(F) ->
40 | {ok, File } = file:open(F, [read, binary, raw]),
41 | {ok, O} =file:pread(File, 0, filelib:file_size(F)),
42 | file:close(File),
43 | O.
44 | init(_Type, Req, _Opts) -> {ok, Req, []}.
45 | terminate(_Reason, _Req, _State) -> ok.
46 |
--------------------------------------------------------------------------------
/js/rpc.js:
--------------------------------------------------------------------------------
1 | function getter(t, u, callback){
2 | var xmlhttp=new XMLHttpRequest();
3 | xmlhttp.onreadystatechange = callback;
4 | xmlhttp.open("POST",u,true);
5 | xmlhttp.send(JSON.stringify(t));
6 | return xmlhttp
7 | }
8 | function get(t, callback) {
9 | return general_get(t, get_port(), callback)
10 | }
11 | function general_get(t, port, callback) {
12 | u = url(port, get_ip());
13 | return getter(t, u, callback);
14 | }
15 | function url(port, ip) { return "http://".concat(ip).concat(":").concat(port.toString().concat("/")); }
16 | function xml_check(x) {
17 | return ((x.readyState === 4) && (x.status === 200)); };
18 | function xml_out(x) { return x.responseText; }
19 | function refresh_helper(x, cmd, innercallback, callback, n) {
20 | if (n < 1) { return "failed to connect"; }
21 | else if (x.status == 400) {
22 | //the data we sent to the server got mixed up along the way, so it looks invalid to the server.
23 | //So lets re-send the command.
24 | setTimeout(function() {
25 | return variable_public_get(cmd, innercallback);
26 | }, 200); }
27 | else if (x.status == 0) {
28 | //this means that the server got our message, and it is still processing a response for us. So lets wait a bit, and then check if it is ready.
29 | setTimeout(function() {
30 | return refresh_helper(x, cmd, innercallback,
31 | callback, n - 1);
32 | }, 150);
33 | }
34 | else if (xml_check(x)) {
35 | //this means that the server got our message, and it sent a response. The response is ready to read, so lets read it.
36 | callback(xml_out(x));}
37 | else {
38 | //console.log(x.readyState);
39 | //console.log(x.status);
40 | setTimeout(function() {return refresh_helper(x, cmd, innercallback, callback, n);}, 10);}
41 | }
42 |
43 | my_status = "nil";
44 |
45 | //function variable_get(cmd, callback) {
46 | // var x = local_get(cmd);
47 | // var_get(x, callback);
48 | //}
49 | function variable_public_get(cmd, callback) {
50 | var foobar = get(cmd);
51 | var_get(foobar, callback, cmd);
52 | }
53 | function var_get(x, callback, cmd) {
54 | refresh_helper(x, cmd, callback, function(){
55 | p = JSON.parse(xml_out(x));
56 | callback(p[1]);
57 | }, 100);
58 | }
59 | function messenger(cmd, callback) {
60 | var foobar = general_get(cmd, 8088);
61 | var_get(foobar, callback, cmd);
62 | }
63 |
--------------------------------------------------------------------------------
/js/utils.js:
--------------------------------------------------------------------------------
1 | function br() {
2 | return document.createElement("br");
3 | };
4 | function button_maker2(val, fun) {
5 | var button = document.createElement("input");
6 | button.type = "button";
7 | button.value = val;
8 | button.onclick = fun;
9 | return button;
10 | };
11 | function text(a) {
12 | var x2 = document.createElement("h8");
13 | x2.innerHTML = a;
14 | return x2;
15 | };
16 | function text_input(query, div) {
17 | var x = document.createElement("INPUT");
18 | x.type = "text";
19 | var q = text(query);
20 | div.appendChild(q);
21 | div.appendChild(x);
22 | return x;
23 | };
24 | function token_units() { return 100000000 }; // VEO
25 | function s2c(x) { return x / token_units(); }
26 | function c2s(x) {
27 | return Math.floor(parseFloat(x.value, 10) * token_units());
28 | }
29 |
30 | function oracle_limit(oid, callback) {
31 | return variable_public_get(["oracle", oid], function(x) {
32 | console.log(atob(x[1][4]));
33 | var question = atob(x[1][4]);
34 | //console.log(question);
35 | //measured_upper.value = (largest_number(question, 0, 0)).toString();
36 | return callback(oracle_limit_grabber(question));
37 | });
38 | function oracle_limit_grabber(question) {
39 | //console.log("oracle limit grabber");
40 | if (question.length < 4) {
41 | return "";
42 | }
43 | var f = question.slice(0, 4);
44 | if (f == "from") {
45 | return olg2(question.slice(4));
46 | }
47 | return oracle_limit_grabber(question.slice(1));
48 | }
49 | function olg2(question) {
50 | //console.log("olg2");
51 | //console.log(question);
52 | if (question.length < 2) {
53 | return "";
54 | }
55 | var f = question.slice(0, 2);
56 | if (f == "to") {
57 | //console.log("calling olg3 ");
58 | return olg3(question.slice(2), "");
59 | }
60 | return olg2(question.slice(1));
61 | }
62 | function olg3(question, n) {
63 | //console.log(n);
64 | if (question.length < 1) { return n; }
65 | var l = question[0];
66 | if (((l >= "0") && (l <= "9")) || (l == ".")) {
67 | var n2 = n.concat(l);
68 | return olg3(question.slice(1), n2);
69 | } else if (n == "") {
70 | return olg3(question.slice(1), n);
71 | } else {
72 | return n;
73 | }
74 | };
75 | };
76 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/utils.erl:
--------------------------------------------------------------------------------
1 | -module(utils).
2 | -export([cron_job/2, off/0, server_url/1, talk/1,
3 | trade_id/1, market_id/1]).
4 |
5 | -include("records.hrl").
6 |
7 | test_mode() ->
8 | case application:get_env(amoveo_p2p_derivatives_explorer, test_mode) of
9 | {ok, B} -> B;
10 | _ -> false
11 | end.
12 |
13 | server_url(T) ->
14 | L = case T of
15 | internal -> "1";
16 | external -> "0"
17 | end,
18 | TM = test_mode(),
19 | if
20 | TM -> "http://127.0.0.1:301"++L;
21 | true -> "http://127.0.0.1:808"++L
22 | end.
23 | talk(X) ->
24 | TM = test_mode(),
25 | Port =
26 | if
27 | TM -> 3011;
28 | true -> 8081
29 | end,
30 | talker:talk(X, {{127,0,0,1}, Port}).
31 |
32 |
33 | cron_job(Period, F) ->
34 | spawn(fun() ->
35 | timer:sleep(1000),
36 | cron2(F, Period) end).
37 | cron2(F, P) ->
38 | spawn(F),
39 | timer:sleep(P * 1000),
40 | cron2(F, P).
41 |
42 | off() ->
43 | amoveo_p2p_derivatives_explorer_sup:stop(),
44 | ok = application:stop(amoveo_p2p_derivatives_explorer).
45 |
46 | trade_id(Salt, Pub) ->
47 | hash:doit(<>).
49 | trade_id(SO) when is_record(SO, swap_offer2)->
50 | #swap_offer2{
51 | salt = Salt,
52 | acc1 = Acc
53 | } = SO,
54 | trade_id(Salt, Acc);
55 | trade_id(SO) when is_record(SO, swap_offer)->
56 | #swap_offer{
57 | salt = Salt,
58 | acc1 = Acc
59 | } = SO,
60 | trade_id(Salt, Acc).
61 |
62 | market_id(S) when is_record(S, swap_offer2) ->
63 | #swap_offer2{
64 | cid1 = CID1,
65 | type1 = T1,
66 | cid2 = CID2,
67 | type2 = T2
68 | } = S,
69 | make_id(CID1, T1, CID2, T2);
70 | % hash:doit(<>);
74 | market_id(S) when is_record(S, swap_offer) ->
75 | #swap_offer{
76 | cid1 = CID1,
77 | type1 = T1,
78 | cid2 = CID2,
79 | type2 = T2
80 | } = S,
81 | make_id(CID1, T1, CID2, T2).
82 | % hash:doit(<>).
86 |
87 | %make_id(CID1, Type1, CID2, Type2) ->
88 | % hash:doit(<>);
92 | make_id(CID1, Type1, CID2, Type2) ->
93 | <> = CID1,
94 | <> = CID2,
95 | if
96 | ((N1+Type1) =< (N2+Type2)) ->
97 | X = <>,
101 | %io:fwrite(base64:encode(X)),
102 | hash:doit(X);
103 | true ->
104 | make_id(CID2, Type2, CID1, Type1)
105 | end.
106 |
--------------------------------------------------------------------------------
/js/main.js:
--------------------------------------------------------------------------------
1 | (function main() {
2 | console.log("hello world.");
3 | //This contract is valid as of block 64255
4 | //eventually it will become invalid, so if you want to run the test you need to make a different contract to replcae this one.
5 | /*
6 | If this test succeeds, the javascript console shows this:
7 |
8 | [-6,["v","6shH4FO3E3mZ7gBKwWv71NxT0FvUTqaVjhZ7ygMnfCI=",20000]]
9 | main.js:20 ["oracle","6shH4FO3E3mZ7gBKwWv71NxT0FvUTqaVjhZ7ygMnfCI=",[-6],[-6,"Xy9Tecb4Xx88W4D+NW2CQgYrDIM+9m3r7d/zy6YNe7o="],"UCA9IHRoZSBwcmljZSBvZiBVU0QgaW4gVkVPIG9uIHF0cmFkZS5pbyBmcm9tIDAgdG8gMC4wNSBvbiBNYXkgMzEsIDIwMTksIGF0IDEyOjAwIE5vb24gR01UOyByZXR1cm4gUCAqIDEwMjQgLyAwLjA1IGJpdCBudW1iZXIgMA==",69420]
10 | main.js:23 [-6,["channel_offer","Xy9Tecb4Xx88W4D+NW2CQgYrDIM+9m3r7d/zy6YNe7o=","6shH4FO3E3mZ7gBKwWv71NxT0FvUTqaVjhZ7ygMnfCI=",614,2,64339,10,10000,10000,2,"BBEuaxBNwXiTpEMTZI2gExMGpxCwAapTyFrgWMu5n4cIcqPojDz40Trf7xdWDlHL8KH+AvrTc2dhSC+35eSjmaQ="]]
11 | main.js:26 [-6,[-6,2,3000,5000,"BBEuaxBNwXiTpEMTZI2gExMGpxCwAapTyFrgWMu5n4cIcqPojDz40Trf7xdWDlHL8KH+AvrTc2dhSC+35eSjmaQ=",0,1000000,10000,10000,"6shH4FO3E3mZ7gBKwWv71NxT0FvUTqaVjhZ7ygMnfCI=",64239,1000,[-7,2,"MEQCIEvjwRnANgJrhLfKiPyd3YHSvFXL7XA098Acw9fXrS46AiByuwStQoVjBetI2+GNhmCHA569JSjSxqoAhhAoL+ZRgg=="],"AAD67xOHJw/qyEfgU7cTeZnuAErBa/vU3FPQW9ROppWOFnvKAyd8IjBFAiEA8Y2dZkonQU4QXfm6LZqK3les3GP3HlkXRXoJxbiIDY0CIEVn/yOB7CazFCHLeFGUjhk3XkTUVsWYQFkw4Pz2xCPy",1,2,"Xy9Tecb4Xx88W4D+NW2CQgYrDIM+9m3r7d/zy6YNe7o=",10,818,0,0],["signed",["nc_offer","BBEuaxBNwXiTpEMTZI2gExMGpxCwAapTyFrgWMu5n4cIcqPojDz40Trf7xdWDlHL8KH+AvrTc2dhSC+35eSjmaQ=",10,64339,10000,10000,1000,1000,"Xy9Tecb4Xx88W4D+NW2CQgYrDIM+9m3r7d/zy6YNe7o=","nPwN6mIWS4JUIo2neplltEEifucqc43ytORXToDFtco="],"MEUCIQCwxOaubh3Y7yuPBWZUKJy1jnhqYhLy+U1vRLZNO/pU1AIgX81qJ8HVp0r/Ac48tqG6F7yyYC7gKhcEka4qVk18G9U=",[-6]]]
12 |
13 | */
14 | var contract = [-6,[-6,2,3000,5000,"BBEuaxBNwXiTpEMTZI2gExMGpxCwAapTyFrgWMu5n4cIcqPojDz40Trf7xdWDlHL8KH+AvrTc2dhSC+35eSjmaQ=",0,1000000,10000,10000,"6shH4FO3E3mZ7gBKwWv71NxT0FvUTqaVjhZ7ygMnfCI=",64239,1000,[-7,2,"MEQCIEvjwRnANgJrhLfKiPyd3YHSvFXL7XA098Acw9fXrS46AiByuwStQoVjBetI2+GNhmCHA569JSjSxqoAhhAoL+ZRgg=="],"AAD67xOHJw/qyEfgU7cTeZnuAErBa/vU3FPQW9ROppWOFnvKAyd8IjBFAiEA8Y2dZkonQU4QXfm6LZqK3les3GP3HlkXRXoJxbiIDY0CIEVn/yOB7CazFCHLeFGUjhk3XkTUVsWYQFkw4Pz2xCPy",1,2,"Xy9Tecb4Xx88W4D+NW2CQgYrDIM+9m3r7d/zy6YNe7o=",10,818,0,0],["signed",["nc_offer","BBEuaxBNwXiTpEMTZI2gExMGpxCwAapTyFrgWMu5n4cIcqPojDz40Trf7xdWDlHL8KH+AvrTc2dhSC+35eSjmaQ=",10,64339,10000,10000,1000,1000,"Xy9Tecb4Xx88W4D+NW2CQgYrDIM+9m3r7d/zy6YNe7o=","nPwN6mIWS4JUIo2neplltEEifucqc43ytORXToDFtco="],"MEUCIQCwxOaubh3Y7yuPBWZUKJy1jnhqYhLy+U1vRLZNO/pU1AIgX81qJ8HVp0r/Ac48tqG6F7yyYC7gKhcEka4qVk18G9U=",[-6]]];
15 | variable_public_get(["add", contract], function(X) {
16 | variable_public_get(["oracle_list"], function(X) {
17 | console.log(JSON.stringify(X));
18 | var OID = X[1][1];
19 | variable_public_get(["oracle", OID], function(Oracle) {
20 | console.log(JSON.stringify(Oracle[1]));
21 | var CID = Oracle[1][3][1];
22 | variable_public_get(["get_offers", [-6, CID]], function(Oracle) {
23 | console.log(JSON.stringify(Oracle));
24 | });
25 | variable_public_get(["get_offer_contract", CID], function(C) {
26 | console.log(JSON.stringify(C[1]));
27 | });
28 | });
29 | });
30 | });
31 | })();
32 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/talker.erl:
--------------------------------------------------------------------------------
1 | -module(talker).
2 | -export([talk/2, talk/3, talk_timeout/3]).
3 |
4 | -define(RETRY, 3).
5 |
6 | talk_timeout(Msg, {IP, Port}, X) ->
7 | P = build_string_peer(IP, Port),
8 | talk_helper(Msg, P, ?RETRY, X).
9 |
10 | talk(Msg, {IP, Port}) ->
11 | talk(Msg, build_string_peer(IP, Port));
12 |
13 | talk(Msg, Peer) ->
14 | talk_helper(Msg, Peer, ?RETRY, 20000).
15 |
16 | talk(Msg, IP, Port) ->
17 | talk(Msg, build_string_peer(IP, Port)).
18 | ip2string2(X) ->
19 | (integer_to_list(X)) ++ (".").
20 | ip2string([A,B,C,D]) ->
21 | ip2string({A,B,C,D});
22 | ip2string({A,B,C,D}) ->
23 | ip2string2(A) ++
24 | ip2string2(B) ++
25 | ip2string2(C) ++
26 | integer_to_list(D).
27 | build_string_peer(IP, Port) ->
28 | T = ip2string(IP),
29 | P = integer_to_list(Port),
30 | "http://" ++ T ++ ":" ++ P ++ "/".
31 | check_print(S) ->
32 | io:fwrite(S).
33 | % case sync_mode:check() of
34 | % normal -> ok;
35 | % quick -> io:fwrite(S)
36 | % end.
37 |
38 | talk_helper(_, _, 0, _) ->
39 | check_print("talk helper fail\n"),
40 | bad_peer;
41 | %{error, failed_connect};
42 | talk_helper(Msg, Peer, N, TimeOut) ->
43 | PM = packer:pack(Msg),
44 | %check_print("sending message "),
45 | %check_print(PM),
46 | %check_print("\n"),
47 | %timer:sleep(500),
48 | Msg = packer:unpack(PM),
49 | case httpc:request(post, {Peer, [], "application/octet-stream", iolist_to_binary(PM)}, [{timeout, TimeOut}], []) of
50 | {ok, {{_, 500, _}, _Headers, []}} ->
51 | check_print("server crashed. Will ignore peer. "),
52 | check_print(element(1, Msg)),
53 | check_print(" \n"),
54 | bad_peer;
55 | %talk_helper(Msg, Peer, 0, TimeOut);
56 | {ok, {Status, _Headers, []}} ->
57 | check_print("talk_helper weird response. Attempting to reconnect. \n"),
58 | check_print(packer:pack(Status)),
59 | talk_helper(Msg, Peer, N - 1, TimeOut);
60 | {ok, {_, _, R}} ->
61 | %check_print("talker peer is "),
62 | %check_print(Peer),
63 | %check_print("\n"),
64 | %check_print("talker msg is "),
65 | %check_print(packer:pack(Msg)),
66 | %check_print("\n"),
67 | %check_print("talker response is "),
68 | %check_print(R),
69 | %check_print("\n"),
70 | DoubleOK = packer:pack({ok, ok}),
71 | if
72 | R == DoubleOK -> 0;
73 | true ->
74 | packer:unpack(R)
75 | end;
76 | {error, socket_closed_remotely} ->
77 | %check_print("talk_helper socket closed remotely. attempting to reconnect \n"),
78 | talk_helper(Msg, Peer, N - 1, TimeOut);
79 | {error, timeout} ->
80 | check_print("talk_helper timeout. attempting to reconnect \n"),
81 | check_print(element(1, Msg)),
82 | check_print("\n"),
83 | talk_helper(Msg, Peer, N - 1, TimeOut);
84 | {error, failed_connect} ->
85 | check_print("talk_helper failed_connect 0. will ignore this peer. \n"),
86 | bad_peer;
87 | %talk_helper(Msg, Peer, N - 1, TimeOut);
88 | {error, {failed_connect, _}} ->
89 | %check_print("talk_helper failed_connect 1. will ignore this peer. \n"),
90 | %check_print(PM),
91 | bad_peer;
92 | %talk_helper(Msg, Peer, N - 1, TimeOut);
93 | X -> check_print("talk helper unexpected error"),
94 | check_print(X),
95 | error
96 | end.
97 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/swap_history.erl:
--------------------------------------------------------------------------------
1 | -module(swap_history).
2 | -behaviour(gen_server).
3 | -export([start_link/0,code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2,
4 | add/4, remove/2, read/2, garbage_cron/0
5 | ]).
6 |
7 | %this is for storing a history of how the swap order books were created. That way it is easy to follow along with the current state of the market by downloading the parts of the history that you missed.
8 |
9 | -include("records.hrl").
10 | -define(LOC, "swap_history.db").
11 | -record(sh, {nonce = 1, l}).
12 | -record(add, {tid, a1, a2, ts}).
13 | -record(remove, {tid, ts}).
14 |
15 | init(ok) ->
16 | process_flag(trap_exit, true),
17 | X = db:read(?LOC),
18 | Y = if
19 | (X == "") -> dict:new();
20 | true -> X
21 | end,
22 | {ok, Y}.
23 | start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, ok, []).
24 | code_change(_OldVsn, State, _Extra) -> {ok, State}.
25 | terminate(_, X) ->
26 | db:save(?LOC, X),
27 | io:format("swap history died!"),
28 | ok.
29 | handle_info(_, X) -> {noreply, X}.
30 | handle_cast(garbage, X) ->
31 | Keys = dict:fetch_keys(X),
32 | Now = erlang:timestamp(),
33 | X2 = garbage2(X, Now, Keys),
34 | {noreply, X2};
35 | handle_cast({remove, MID, TID}, X) ->
36 | TS = erlang:timestamp(),
37 | case dict:find(MID, X) of
38 | empty ->
39 | io:fwrite("can't remove from a non-existant market"),
40 | {noreply, X};
41 | {ok, #sh{nonce = N1,
42 | l = L}} ->
43 | SH2 = #sh{
44 | nonce = N1 + 1,
45 | l = [#remove{tid = TID, ts = TS}|L]
46 | },
47 | X2 = dict:store(MID, SH2, X),
48 | {noreply, X2}
49 | end;
50 | handle_cast(_, X) -> {noreply, X}.
51 | handle_call({add, MID, TID, A1, A2}, _, X) ->
52 | TS = erlang:timestamp(),
53 | E = #add{tid = TID, a1 = A1, a2 = A2, ts = TS},
54 | %E = {add, TID, A1, A2, TS},
55 | Y = case dict:find(MID, X) of
56 | error ->
57 | #sh{l = [E]};
58 | {ok, #sh{nonce = N1,
59 | l = L}} ->
60 | #sh{
61 | nonce = N1 + 1,
62 | l = [E|L]
63 | }
64 | end,
65 | X2 = dict:store(MID, Y, X),
66 | N = Y#sh.nonce,
67 | {reply, N, X2};
68 | handle_call(read_all, _From, X) ->
69 | {reply, X, X};
70 | handle_call({read, MarketID, Nonce}, _From, X) ->
71 | R = case dict:find(MarketID, X) of
72 | error -> [];
73 | A ->
74 | #sh{
75 | nonce = N,
76 | l = L
77 | } = A,
78 | Many = min(length(L), N - Nonce),
79 | {L2, _} = lists:split(Many, L),
80 | L2
81 | end,
82 | {reply, R, X};
83 | handle_call(_, _From, X) -> {reply, X, X}.
84 |
85 |
86 | add(MarketID, TradeID, Amount1, Amount2) ->
87 | gen_server:call(?MODULE, {add, MarketID, TradeID, Amount1, Amount2}).
88 | remove(MarketID, TradeID) ->
89 | gen_server:cast(?MODULE, {remove, MarketID, TradeID}).
90 | read(Market, Nonce) ->
91 | %returns history since Nonce.
92 | read2(Market, Nonce, 30000).
93 | read2(_, _, N) when N < 0 -> [];
94 | read2(Market, Nonce, N) ->
95 | case gen_server:call(?MODULE, {read, Market, Nonce}) of
96 | [] ->
97 | T = 100,
98 | timer:sleep(T),
99 | read2(Market, Nonce, N-T);
100 | X -> X
101 | end.
102 | garbage() ->
103 | gen_server:cast(?MODULE, garbage).
104 |
105 | garbage2(Dict, _, []) -> Dict;
106 | garbage2(Dict, Now, [M|T]) ->
107 | SH = dict:fetch(M, Dict),
108 | L = SH#sh.l,
109 | L2 = remove_old(L, Now),
110 | SH2 = SH#sh{l = L2},
111 | Dict2 = dict:store(M, SH2, Dict),
112 | garbage2(Dict2, Now, T).
113 | remove_old([], _) -> [];
114 | remove_old([A|T], Now) when is_record(A, add) ->
115 | #add{ts = TS} = A,
116 | remove_old2(TS, A, T, Now);
117 | remove_old([R|T], Now) ->
118 | #remove{ts = TS} = R,
119 | remove_old2(TS, R, T, Now).
120 |
121 | remove_old2(TS, A, T, Now) ->
122 | Seconds = timer:now_diff(Now, TS) div 1000000,
123 | if
124 | Seconds > 600 -> %600 seconds is 10 minutes
125 | [];
126 | true -> [A|remove_old(T, Now)]
127 | end.
128 |
129 |
130 | garbage_cron() ->
131 | spawn(fun() ->
132 | timer:sleep(60000),
133 | garbage(),
134 | garbage_cron()
135 | end).
136 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/binary_contracts.erl:
--------------------------------------------------------------------------------
1 | -module(binary_contracts).
2 | -behaviour(gen_server).
3 | -export([start_link/0,code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2,
4 | add/2, add/4, read_contract/1]).
5 |
6 | %this is for storing the data needed to enforce the outcome for any binary contract type subcurrency being used
7 | %so if you want to post a swap tx, the subcurrencies being swapped need to have enforcement data.
8 | -define(LOC, "binary_contracts.db").
9 |
10 | -record(binary, {text, height, now, source = <<0:256>>, source_type = 0}).
11 |
12 | init(ok) ->
13 | process_flag(trap_exit, true),
14 | X = db:read(?LOC),
15 | Y = if
16 | (X == "") -> dict:new();
17 | true -> X
18 | end,
19 | {ok, Y}.
20 | start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, ok, []).
21 | code_change(_OldVsn, State, _Extra) -> {ok, State}.
22 | terminate(_, X) ->
23 | db:save(?LOC, X),
24 | io:format("binary contracts died!"),
25 | ok.
26 | handle_info(_, X) -> {noreply, X}.
27 | handle_cast({add, CID, Text, Height, Source, SourceType}, X) ->
28 | Now = erlang:timestamp(),
29 | C = #binary{text = Text,
30 | height = Height,
31 | now = Now,
32 | source = Source,
33 | source_type = SourceType},
34 | X2 = dict:store(CID, C, X),
35 | {noreply, X2};
36 | handle_cast({add, CID, Text, Height}, X) ->
37 | Now = erlang:timestamp(),
38 | C = #binary{text = Text, height = Height, now = Now},
39 | X2 = dict:store(CID, C, X),
40 | {noreply, X2};
41 | handle_cast(_, X) -> {noreply, X}.
42 | handle_call({check, CID}, _From, X) ->
43 | {reply, dict:find(CID, X), X};
44 | handle_call(_, _From, X) -> {reply, X, X}.
45 |
46 | add(OracleText, OracleHeight, Source, SourceType) ->
47 | CID = cid_maker(OracleText, OracleHeight, Source, SourceType),
48 | gen_server:cast(?MODULE, {add, CID, OracleText, OracleHeight, Source, SourceType}),
49 | CID.
50 | add(OracleText, OracleHeight) ->
51 | CID = cid_maker(OracleText, OracleHeight),
52 | gen_server:cast(?MODULE, {add, CID, OracleText, OracleHeight}),
53 | CID.
54 |
55 | read_contract(<<0:256>>) ->
56 | true;
57 | read_contract(CID) ->
58 | gen_server:call(?MODULE, {check, CID}).
59 |
60 |
61 | cid_maker(OracleText, OracleHeight) ->
62 | cid_maker(OracleText, OracleHeight, <<0:256>>, 0).
63 | cid_maker(OracleText, OracleHeight, Source, SourceType) ->
64 | true = is_binary(OracleText),
65 | QuestionHash = hash:doit(OracleText),
66 | OID = hash:doit(<>),
70 | BinaryCodeStatic = <<" OID ! \
71 | macro [ nil ; \
72 | macro , swap cons ; \
73 | macro ] swap cons reverse ; \
74 | macro even_split [ int 2147483648 , int 2147483647 , int 0 ] ; \
75 | macro maximum int 4294967295 ; \
76 | car drop car swap drop car swap drop car drop \
77 | int 32 split \
78 | OID @ \
79 | == if else fail then \
80 | drop drop int 1 split swap drop binary 3 AAAA swap ++ \
81 | int 3 == if \
82 | [ int 0 , int 0 , maximum ] int 0 int 1000 \
83 | else drop \
84 | int 1 == if \
85 | [ maximum , int 0 , int 0 ] int 0 int 1000 \
86 | else drop \
87 | int 2 == if \
88 | [ int 0 , maximum, int 0 ] int 0 int 1000 \
89 | else drop drop \
90 | even_split int 5000 int 10 \
91 | then \
92 | then \
93 | then ">>,
94 | BinaryCodeInner = <<" binary 32 ",
95 | (base64:encode(OID))/binary,
96 | BinaryCodeStatic/binary
97 | >>,
98 | ContractBytecode = compiler_chalang:doit(BinaryCodeInner),
99 | BinaryHash = hash:doit(ContractBytecode),
100 | %BinaryCode = <<" def ",
101 | % BinaryCodeInner/binary,
102 | % " ; ">>,
103 | %BinaryDerivative = compiler_chalang:doit(BinaryCode),
104 | %BinaryHash = hd(vm(BinaryDerivative)),
105 | ToHash = <>,
109 | CID = hash:doit(ToHash),
110 | io:fwrite("binary contracts tohash is "),
111 | io:fwrite(packer:pack(ToHash)),
112 | io:fwrite("\n"),
113 | io:fwrite("cid is \n"),
114 | io:fwrite(packer:pack(CID)),
115 | io:fwrite("\n"),
116 | CID.
117 | %vm(Code) ->
118 | % ExampleData = chalang:data_maker(1000000,1000000,1000,1000,<<>>,<<>>,chalang:new_state(0,0,0),32,2,false),
119 | % chalang:stack(chalang:run5(Code, ExampleData)).
120 |
121 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/buy_veo_orders.erl:
--------------------------------------------------------------------------------
1 | -module(buy_veo_orders).
2 | -behaviour(gen_server).
3 | -export([start_link/0,code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2,
4 | add/1, read_contract/1, clean/0,
5 | keys/0, sync/2, cron/0]).
6 |
7 | -define(LOC, "buy_veo_orders.db").
8 | -record(contract,
9 | {cid, source = <<0:256>>,
10 | source_type = 0, choose_address_timeout,
11 | oracle_start_height, blockchain,
12 | amount, ticker, date, trade_id, now
13 | }).
14 |
15 | init(ok) ->
16 | process_flag(trap_exit, true),
17 | X = db:read(?LOC),
18 | Y = if
19 | (X == "") -> dict:new();
20 | true -> X
21 | end,
22 | {ok, Y}.
23 | start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, ok, []).
24 | code_change(_OldVsn, State, _Extra) -> {ok, State}.
25 | terminate(_, X) ->
26 | db:save(?LOC, X),
27 | io:format("buy veo orders died!"),
28 | ok.
29 | handle_info(_, X) -> {noreply, X}.
30 | handle_cast({add, C1, CID2}, X) ->
31 | Now = erlang:timestamp(),
32 | C = C1#contract{
33 | now = Now
34 | },
35 | CID = C#contract.cid,
36 | %CID2 = cid_maker(C),
37 | %CID2 = CID,
38 | if
39 | (not(CID == CID2)) ->
40 | io:fwrite("buy veo orders, cids don't match\n"),
41 | {noreply, X};
42 | true ->
43 |
44 | X2 = case dict:find(CID, X) of
45 | error ->
46 | io:fwrite("adding contract\n"),
47 | io:fwrite(packer:pack(CID)),
48 | io:fwrite("\n"),
49 | dict:store(CID, C, X);
50 | _ ->
51 | %io:fwrite(dict:find(CID, X)),
52 | %io:fwrite("\n"),
53 | io:fwrite("not adding contract, id taken\n"),
54 | X
55 | end,
56 | {noreply, X2}
57 | end;
58 | handle_cast(backup, X) ->
59 | db:save(?LOC, X),
60 | {noreply, X};
61 | handle_cast({remove, CID}, X) ->
62 | %unused
63 | {noreply, dict:erase(CID, X)};
64 | handle_cast(_, X) -> {noreply, X}.
65 | handle_call({read_contract, CID}, _From, X) ->
66 | {reply, dict:find(CID, X), X};
67 | handle_call(keys, _From, X) ->
68 | {reply, dict:fetch_keys(X), X};
69 | handle_call(_, _From, X) -> {reply, X, X}.
70 |
71 | cid_maker(Contract) ->
72 | #contract{
73 | source = Source,
74 | source_type = SourceType,
75 | choose_address_timeout =
76 | ChooseAddressTimeout,
77 | oracle_start_height = OracleStartHeight,
78 | blockchain = Blockchain,
79 | amount = Amount,
80 | ticker = Ticker,
81 | date = Date,
82 | trade_id = TID
83 | } = Contract,
84 | PrivDir = "../../../../../amoveo/apps/amoveo_core/priv",
85 | {ok, CodeStatic} = file:read_file(PrivDir ++ "/buy_veo.fs"),
86 | {ok, CodeStatic2} = file:read_file(PrivDir ++ "/buy_veo_part2.fs"),
87 |
88 | OSHS = integer_to_binary(OracleStartHeight),
89 | ReusableSettings =
90 | <<" int4 ",
91 | OSHS/binary,
92 | " .\" ",
93 | Blockchain/binary,
94 | "\" .\" ",
95 | Amount/binary,
96 | "\" .\" ",
97 | Ticker/binary,
98 | "\" .\" ",
99 | Date/binary,
100 | "\" ">>,
101 | Settings = <<" int ",
102 | (integer_to_binary(ChooseAddressTimeout))/binary,
103 | " ",
104 | ReusableSettings/binary,
105 | " int 1 binary 32 ",
106 | (base64:encode(TID))/binary>>,
107 | %the 1 is the trade nonce.
108 | Gas = 100000,
109 | HashStatic2 = base64:encode(hd(chalang:stack(chalang:test(compiler_chalang:doit(<>), Gas, Gas, Gas, Gas, [])))), %contract hash of the static part.
110 | HashStatic2def =
111 | <<" macro part2 binary 32 ",
112 | HashStatic2/binary,
113 | " ; ">>,
114 | StaticBytes = compiler_chalang:doit(<>),
115 | SettingsBytes = compiler_chalang:doit(Settings),
116 | FullContract = <>,
117 | CH = hash:doit(FullContract),
118 | CID = hash:doit(<>),
122 | CID.
123 |
124 |
125 |
126 | clean() ->
127 | %TODO
128 | %if the offer expired, or was canceled.
129 | ok.
130 | sync(IP, Port) ->
131 | %TODO
132 | %add instructions to readme.
133 |
134 | %doit({contracts, 2}) ->
135 | {ok, CIDS} =
136 | talker:talk(
137 | {contracts, 2},
138 | {IP, Port}),
139 | %sync_contracts([hd(CIDS)], {IP, Port}).
140 | sync_contracts(CIDS, {IP, Port}).
141 | sync_contracts([], _) -> ok;
142 | sync_contracts([CID|T], Peer) ->
143 | {ok, Contract} =
144 | talker:talk({read, 3, CID}, Peer),
145 | add(Contract),
146 | sync_contracts(T, Peer).
147 |
148 | backup() ->
149 | gen_server:cast(?MODULE, backup).
150 | keys() ->
151 | gen_server:call(?MODULE, keys).
152 | add(0) -> ok;
153 | add(Contract) when is_record(Contract, contract) ->
154 | %we can trust them to give the correct CID, because 256 bytes is too much space to find a collision, and because the light node can detect an incorrect cid from the contract data.
155 | %TODO, check the contract data is reasonably sized, and of the correct format.
156 | CID2 = cid_maker(Contract),
157 | gen_server:cast(?MODULE, {add, Contract, CID2}),
158 | CID2.
159 |
160 | read_contract(CID) ->
161 | gen_server:call(?MODULE, {read_contract, CID}).
162 |
163 | cron() ->
164 | timer:sleep(60000),
165 | backup(),
166 | spawn(fun() -> clean() end),
167 | cron().
168 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/scalar_contracts.erl:
--------------------------------------------------------------------------------
1 | -module(scalar_contracts).
2 | -behaviour(gen_server).
3 | -export([start_link/0,code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2,
4 | add/3, add/5, read_contract/1,
5 | clean/0, keys/0, sync/2,
6 | cron/0]).
7 |
8 | %-record(c, {string, max_price, oracle_start_height}).
9 |
10 | %this is for storing the data needed to enforce the outcome for any scalar type contract
11 | %so if you want to post a swap tx, the subcurrencies being swapped need to have enforcement data.
12 | -define(LOC, "scalar_contracts.db").
13 | -record(scalar, {text, height, max_price, now, source = <<0:256>>, source_type = 0}).
14 |
15 | init(ok) ->
16 | process_flag(trap_exit, true),
17 | X = db:read(?LOC),
18 | Y = if
19 | (X == "") -> dict:new();
20 | true -> X
21 | end,
22 | {ok, Y}.
23 | start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, ok, []).
24 | code_change(_OldVsn, State, _Extra) -> {ok, State}.
25 | terminate(_, X) ->
26 | db:save(?LOC, X),
27 | io:format("scalar contracts died!"),
28 | ok.
29 | handle_info(_, X) -> {noreply, X}.
30 | handle_cast({add, CID, Text, Height, MaxPrice, Source, SourceType}, X) ->
31 | Now = erlang:timestamp(),
32 | C = #scalar{text = Text,
33 | height = Height,
34 | max_price = MaxPrice,
35 | now = Now,
36 | source = Source,
37 | source_type = SourceType},
38 | X2 = dict:store(CID, C, X),
39 | {noreply, X2};
40 | handle_cast({add, CID, Text, Height, MaxPrice}, X) ->
41 | Now = erlang:timestamp(),
42 | C = #scalar{text = Text,
43 | height = Height,
44 | max_price = MaxPrice,
45 | now = Now},
46 | X2 = dict:store(CID, C, X),
47 | {noreply, X2};
48 | handle_cast({remove, CID}, X) ->
49 | {noreply, dict:erase(CID, X)};
50 | handle_cast(backup, X) ->
51 | db:save(?LOC, X),
52 | {noreply, X};
53 | handle_cast(_, X) -> {noreply, X}.
54 | handle_call(keys, _From, X) ->
55 | {reply, dict:fetch_keys(X), X};
56 | handle_call({check, CID}, _From, X) ->
57 | {reply, dict:find(CID, X), X};
58 | handle_call(_, _From, X) -> {reply, X, X}.
59 |
60 | sync(IP, Port) ->
61 | %talking to other server.
62 | {ok, CIDS} =
63 | talker:talk(
64 | {contracts},
65 | {IP, Port}),
66 | sync_contracts(CIDS, {IP, Port}).
67 | sync_contracts([], _) -> ok;
68 | sync_contracts([CID|T], Peer) ->
69 | {ok, Contract} =
70 | talker:talk({read, 3, CID}, Peer),
71 | #scalar
72 | {text = Text,
73 | height = Height,
74 | max_price = MaxPrice,
75 | source = Source,
76 | source_type = SourceType
77 | } = Contract,
78 | add(Text, Height, MaxPrice,
79 | Source, SourceType),
80 | sync_contracts(T, Peer).
81 |
82 | clean() ->
83 | IN = utils:server_url(internal),
84 | {ok, H1} = talker:talk({height}, IN),
85 | {ok, H2} = talker:talk({height, 1}, IN),
86 | TestMode = case application:get_env(amoveo_p2p_derivatives_explorer, test_mode) of
87 | {ok, B} -> B;
88 | _ -> false
89 | end,
90 | if
91 | ((not TestMode) and (H1 < 130000)) ->
92 | io:fwrite("need to sync the full node first before cleaning scalar contracts");
93 | not(H1 == H2) ->
94 | io:fwrite("need to sync the blocks in the full node first before syncing scalar contracts.");
95 | true ->
96 | D = gen_server:call(?MODULE, read_dict),
97 | clean_internal(D)
98 | end.
99 | clean_internal(D) ->
100 | Ks = dict:fetch_keys(D),
101 | clean_internal2(D, Ks).
102 | clean_internal2(_, []) -> ok;
103 | clean_internal2(D, [K|T]) ->
104 | A = dict:fetch(K, D),
105 | #scalar{
106 | text = Question,
107 | now = Then,
108 | height = Start
109 | } = A,
110 | FN = utils:server_url(external),
111 | IN = utils:server_url(internal),
112 | {ok, Contract} = talker:talk({contracts, K}, FN),
113 | %and this contract was not created on-chain
114 | B1 = (Contract == 0),
115 | Now = erlang:timestamp(),
116 | DiffSeconds =
117 | timer:now_diff(Now, Then) / 1000000,
118 | %if more than 100 minutes passed,
119 | B2 = DiffSeconds > (60*100),
120 | %and we aren't storing any open offer for this.
121 | B3 = not(swap_books:using_contract(K)),
122 | QH = hash:doit(Question),
123 | OID = hash:doit(<>),
124 | {ok, Oracle} = talker:talk({oracle, OID}, IN),
125 | %if this oracle was already posted on-chain.
126 | B4 = not(Oracle == 0),
127 | if
128 | (B1 and B2 and B3) or
129 | (not(B1) and B4) ->
130 | gen_server:cast(?MODULE, {remove, K});
131 | true -> ok
132 | end,
133 | clean_internal2(D, T).
134 |
135 |
136 |
137 | cid_maker(Text, Height, MaxPrice) ->
138 | cid_maker(Text, Height, MaxPrice, <<0:256>>, 0).
139 | cid_maker(Text, _Height, MaxPrice, Source, SourceType) ->
140 | true = is_binary(Text),
141 | StaticContract = base64:decode(
142 | "bpYZNRc5AzAyj4cUGIYWjDpGFBRHFHBxSG8AAAAAAXgAAAAAAngWAAAAAAN4gxSDFhSDFhSDFKyHAAAAAAJ5jBWGhgAAAAABeQAAAAADeYw6RhQUAgAAAAEwRxSQjIcWFBYCAAAAIGRuan/EdSKkhbAp0OEF6cQDv9x9li1vx5O6vqNMm3KlcUiGKIYoO0ZHDUiNhxYUAgAAAAEBO0ZHDUiEAAAAAAN5FoIA/////wAAAAADeTMWgoiMBAPo"),
143 |
144 | %"bpYZNRc5AzAyj4cUGIYWjDpGFBRHFHBxSG8AAAAAAXgAAAAAAngWAAAAAAN4gxSDFhSDFhSDFKyHAAAAAAF5jBWGhgAAAAACeQAAAAADeYw6RhQUAgAAAAEwRxSQjIcWFBYCAAAAIGRuan/EdSKkhbAp0OEF6cQDv9x9li1vx5O6vqNMm3KlcUiGKIYoO0ZHDUiNhxYUAgAAAAEBO0ZHDUiEAAAAAAN5FoIA/////wAAAAADeTMWgoiMBAPo"),
145 | OracleTextPart = "MaxPrice = " ++ integer_to_list(MaxPrice) ++ "; MaxVal = 4294967295; B = " ++ binary_to_list(Text) ++ " from $0 to $MaxPrice; max(0, min(MaxVal, (B * MaxVal / MaxPrice)) is ",
146 | L = length(OracleTextPart),
147 | %FullContract = <<0, Height:32, 2, L:32, (list_to_binary(OracleTextPart))/binary, StaticContract/binary>>,
148 | FullContract = <<22, 2, L:32, (list_to_binary(OracleTextPart))/binary, StaticContract/binary>>,
149 | CH = hash:doit(FullContract),
150 | CID = hash:doit(<>),
154 | CID.
155 |
156 | add(Text, Height, MaxPrice, Source, SourceType) ->
157 | CID = cid_maker(Text, Height, MaxPrice, Source, SourceType),
158 | gen_server:cast(?MODULE, {add, CID, Text, Height, MaxPrice, Source, SourceType}),
159 | CID.
160 | add(Text, Height, MaxPrice) ->
161 | CID = cid_maker(Text, Height, MaxPrice),
162 | gen_server:cast(?MODULE, {add, CID, Text, Height, MaxPrice}),
163 | CID.
164 | backup() ->
165 | gen_server:cast(?MODULE, backup).
166 | read_contract(<<0:256>>) ->
167 | true;
168 | read_contract(CID) ->
169 | gen_server:call(?MODULE, {check, CID}).
170 | keys() ->
171 | gen_server:call(?MODULE, keys).
172 |
173 | cron() ->
174 | timer:sleep(60000),
175 | backup(),
176 | spawn(fun() -> clean() end),
177 | cron().
178 |
--------------------------------------------------------------------------------
/js/oracle_list.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | var div = document.createElement("div");
3 | document.body.appendChild(div);
4 |
5 | var title2 = document.createElement("h3");
6 | title2.innerHTML = "Raw Contract";
7 | div.appendChild(title2);
8 | glossary.link2(div, "accepting_channel_offer", "how to accept a trade");
9 | var contract_div = document.createElement("div");
10 | div.appendChild(contract_div);
11 |
12 | var title1 = document.createElement("h3");
13 | title1.innerHTML = "Trades";
14 | div.appendChild(title1);
15 | var offers = document.createElement("div");
16 | div.appendChild(offers);
17 |
18 | var title = document.createElement("h3");
19 | title.innerHTML = "Oracles, click to see related trades";
20 | div.appendChild(title);
21 |
22 | variable_public_get(["oracle_list"], function(X) {
23 | console.log(JSON.stringify(X));
24 | var l = X.slice(1);
25 | offers.innerHTML = "";
26 | display_oracles(l);
27 | });
28 | function display_oracles(l) {
29 | if (JSON.stringify(l) == "[]") {
30 | return 0;
31 | } else {
32 | var h = l[0];
33 | console.log(JSON.stringify(h));
34 | variable_public_get(["oracle", h[1]], function(Oracle) {
35 | //variable_public_get(["oracle", h], function(Oracle) {
36 | if(Oracle == "error") {
37 | console.log("non existant oracle.");
38 | } else {
39 | console.log(JSON.stringify(Oracle));
40 | var t = text(atob(Oracle[1][4]));
41 | var button = button_maker2("display trades", function() { return display_oracle(Oracle[1][2], Oracle[1][3]) });
42 | div.appendChild(button);
43 | div.appendChild(t);
44 | div.appendChild(br());
45 | };
46 | //display_oracles(l.slice(1));
47 | });
48 | display_oracles(l.slice(1));
49 | };
50 | };
51 | function display_oracle(Buys, Sells) {
52 | console.log(JSON.stringify([Buys, Sells]));
53 | var l = Buys.concat(Sells.slice(1));
54 | variable_public_get(["get_offers", l], function(l2) {
55 | console.log(JSON.stringify(l2));
56 | offers.innerHTML = "";
57 | return display_offers(l2.slice(1));
58 | });
59 | };
60 | function display_offers(l) {
61 | if (JSON.stringify(l) == "[]") {
62 | return 0;
63 | } else {
64 | var h = l[0];
65 | var t = document.createElement("div");
66 | var type;
67 | if (h[9] == 1) {
68 | type = "binary";
69 | price = h[3];
70 | return display_offers2(l, h, t, type, price, " or ", "");
71 | } else if (h[9] == 2) {
72 | var oid = h[2];
73 | type = "scalar"
74 | oracle_limit(oid, function(oracle_max) {
75 | console.log("oracle_list callback");
76 | console.log(oracle_max);
77 | var direction = h[4];
78 | if (direction == 2) {
79 | price = (1023 - h[3]) * oracle_max / 1023;
80 | } else if (direction == 1) {
81 | price = h[3] * oracle_max / 1023;
82 | } else {
83 | console.log("fail");
84 | return 0
85 | };
86 | return display_offers2(l, h, t, type, price, " veo/stablecoin or ", " stablecoin/veo;");
87 | });
88 | } else {
89 | console.log(h[9]);
90 | console.log("contract type not supported.");
91 | }
92 | }
93 | };
94 | function display_offers2(l, h, t, type, price, d1message, d2message) {
95 | var direction;
96 | if (h[4] == 2) {
97 | if (type == "binary") {
98 | direction = "the result is true";
99 | } else if (type == "scalar") {
100 | direction = "the price of stablecoin measured in veo increases";
101 | }
102 | } else {
103 | if (type == "binary") {
104 | direction = "the result is false";
105 | } else if (type == "scalar") {
106 | direction = "the price of stablecoin measured in veo decreases";
107 | }
108 | }
109 | var text = "bet type: ".concat(type).concat("; price = ").concat(price.toFixed(5)).concat(d1message).concat((1/price).toFixed(5)).concat(d2message).concat(" you win if ").concat(direction).concat("; they pay = ").concat(s2c(h[7])).concat("; you pay = ").concat(s2c(h[8])).concat("; expires: ").concat(h[5]);
110 | t.innerHTML = text;
111 | offers.appendChild(t);
112 | var button = button_maker2("display a copy/pasteable version of this contract", function() { display_contract(h, type) });
113 | offers.appendChild(button);
114 | offers.appendChild(br());
115 | display_offers(l.slice(1));
116 | };
117 | function plus_encode(s) {
118 | if (s == "") { return ""; }
119 | var h = s[0];
120 | if (h == "+") { h = "%2B"; }
121 | return h.concat(plus_encode(s.slice(1)));
122 | };
123 | function display_contract(h, type) {
124 | var CID = h[1];
125 | variable_public_get(["get_offer_contract", CID], function(C) {
126 | var copy_contract_link = document.createElement("div");
127 | var contract_type = type;
128 | console.log(JSON.stringify(h));
129 | console.log(JSON.stringify(C));
130 | var oid = plus_encode(h[2]);
131 | var UL = C[1][1][18];
132 | var LL = C[1][1][19];
133 | F = function(X){
134 | var Y = parseInt(X) / 100000000;
135 | return(Y.toFixed(8));
136 | };
137 | //var direction = C[1][2][1][2];//either 1 or 2.
138 | var direction = C[1][1][1];//either 1 or 2.
139 | var d_string;
140 | if (direction == 1) {
141 | d_string = "false";
142 | } else if (direction == 2) {
143 | d_string = "true";
144 | } else {
145 | console.log(JSON.stringify(C[1][2][1]));
146 | console.log(direction);
147 | console.log("badly formed contract offer");
148 | return(0);
149 | }
150 | contract_div.innerHTML = JSON.stringify(C[1]);
151 | var our_amount = F(C[1][2][1][5]);
152 | var their_amount = F(C[1][2][1][4]);
153 | var oracle_height = C[1][1][22];
154 | copy_contract_link.innerHTML = "open this contract in the contract-editor");
155 | contract_div.appendChild(copy_contract_link);
156 | contract_div.appendChild(br());
157 | //console.log(JSON.stringify(C[1]));
158 | });
159 | };
160 | })();
161 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/swap_verify.erl:
--------------------------------------------------------------------------------
1 | -module(swap_verify).
2 | -export([doit/2, keep_longer/3, doit/3]).
3 |
4 | -include("records.hrl").
5 | -record(trade, {nonce, value}).
6 | -define(verbose, true).
7 |
8 | doit(TID, S) ->
9 | FN = utils:server_url(external),
10 | {ok, Height} = talker:talk({height}, FN),
11 | doit(TID, S, Height).
12 | doit(TID, S, Height) ->
13 | %FN = utils:server_url(external),
14 | %%FNL = utils:server_url(internal),
15 |
16 | Offer = element(2, S),
17 | {SL, Fee1, Amount1, CID1, CID2, Acc1} =
18 | case Offer of
19 | #swap_offer{
20 | start_limit = SL0,
21 | fee1 = Fee10,
22 | amount1 = Amount10,
23 | cid1 = CID10,
24 | cid2 = CID20,
25 | acc1 = Acc10
26 | } ->
27 | {SL0, Fee10, Amount10,
28 | CID10, CID20, Acc10};
29 | #swap_offer2{
30 | start_limit = SL1,
31 | amount1 = Amount11,
32 | cid1 = CID11,
33 | cid2 = CID21,
34 | acc1 = Acc11
35 | } ->
36 | {SL1, 0, Amount11, CID11, CID21, Acc11}
37 | end,
38 |
39 | B1 = sign:verify_sig(Offer, element(3, S), Acc1),
40 |
41 | %check acc1 is putting some minimum amount into it.
42 | %B2 = Fee1 + Amount1 > 1000000,
43 | B2 = true,%Fee1 + Amount1 > 1000000,
44 |
45 | %check that we aren't already storing a trade with this id
46 | B4 = error == swap_full:read(TID),
47 |
48 | %check that the start height limit has already occured.
49 | B5 = (Height >= SL),
50 | io:fwrite(packer:pack([Height, SL])),
51 | io:fwrite("\n"),
52 |
53 | %TODO verify that all the contract ids are in the binary_contracts database. `binary_contracts:read(CID)`
54 | B6 = ((not(error == binary_contracts:read_contract(CID1)))
55 | or (not(error == scalar_contracts:read_contract(CID1)))
56 | or (not(error == buy_veo_orders:read_contract(CID1)))),
57 | B7 = ((not(error == binary_contracts:read_contract(CID2)))
58 | or (not(error == scalar_contracts:read_contract(CID2)))
59 | or (not(error == buy_veo_orders:read_contract(CID2)))),
60 | B8 = B1 and B2 and B4 and B5 and B6 and B7,
61 | if
62 | (?verbose and (not B8))->
63 | io:fwrite("swap verify, bad offer.\n"),
64 | io:fwrite(packer:pack([B1, B2, B4, B5, B6, B7])),
65 | io:fwrite("\n"),
66 | false;
67 | (not B8) -> false;
68 | true -> keep_longer(Offer, Height, TID)
69 | end.
70 |
71 | %keep_longer(Offer, Height, TID) when is_record(Offer, swap_offer) ->
72 | % 1=2,
73 | % %UNUSED VERSION
74 | % FNL = utils:server_url(internal),
75 | % FN = utils:server_url(external),
76 | % #swap_offer{
77 | % end_limit = EL,
78 | % amount1 = Amount1,
79 | % %amount2 = Amount2,
80 | % salt = Salt,
81 | % acc1 = Acc1,
82 | % cid1 = CID1,
83 | % type1 = Type1,
84 | % nonce = Nonce
85 | % } = Offer,
86 | %
87 | % %check that it isn't expired.
88 | % B2 = (Height =< EL),
89 | %
90 | % %check the nonce.
91 | % {ok, [_, BlockHash]} = talker:talk({top, 1}, FNL),
92 | % B3 = case CID1 of
93 | % <<0:256>> ->
94 | % {ok, Acc} = talker:talk({account, Acc1, BlockHash}, FNL),
95 | % {ok, Acc0} = talker:talk({account, Acc1}, FNL),
96 | % if
97 | % Acc == 0 -> false;
98 | % true ->
99 | % (Acc0#acc.nonce =< Nonce)
100 | % and (Acc#acc.balance >= Amount1)
101 | % end;
102 | % _ ->
103 | % %Key = sub_accounts:make_key(Acc1, CID1, Type1),
104 | % {ok, SubAcc} = talker:talk({sub_account, Acc1, CID1, Type1, BlockHash}, FNL),
105 | % {ok, SubAcc0} = talker:talk({sub_account, Acc1, CID1, Type1}, FNL),
106 | % if
107 | % SubAcc == 0 -> false;
108 | % true ->
109 | % (SubAcc0#sub_acc.nonce =< Nonce)
110 | % and (SubAcc#sub_acc.balance >= Amount1)
111 | % end
112 | % end,
113 | %
114 | % %check that the trade id isn't already consumed
115 | % B4 = {ok, 0} == talker:talk({trade, TID}, FNL),
116 | %
117 | % {ok, Txs} = talker:talk({txs}, FN),
118 | % B5 = no_repeats(Acc1, Salt, Txs),
119 | %
120 | % B6 = B2 and B3 and B4 and B5,
121 | % if
122 | % not(B4) ->
123 | % trade_accepted;
124 | % (?verbose and not(B6)) ->
125 | % io:fwrite(packer:pack(swap_full:read(TID))),
126 | % io:fwrite("\n"),
127 | % io:fwrite(packer:pack([B2, B3, B4, B5])),
128 | % io:fwrite("\n"),
129 | % false;
130 | % not(B6) ->
131 | % false;
132 | % true ->
133 | % true
134 | % end;
135 | keep_longer(Offer, Height, TID) when is_record(Offer, swap_offer2)->
136 | FNL = utils:server_url(internal),
137 | %FN = utils:server_url(external),
138 | #swap_offer2{
139 | end_limit = EL,
140 | start_nonce = SN,
141 | parts = Parts,
142 | acc1 = Acc1,
143 | amount1 = Amount1,
144 | type1 = Type1,
145 | cid1 = CID1
146 | } = Offer,
147 | %check that it isn't expired.
148 | B2 = (Height < EL),
149 | %balance check
150 | %{ok, [_, BlockHash]} = talker:talk({top, 1}, FNL),
151 | B3 = case CID1 of
152 | <<0:256>> ->
153 | {ok, Acc} = talker:talk({account, Acc1}, FNL),
154 | if
155 | Acc == 0 -> false;
156 | true ->
157 | (Acc#acc.balance >= Amount1)
158 | end;
159 | _ -> true
160 | %{ok, SubAcc} = talker:talk({sub_account, Acc1, CID1, Type1}, FNL),
161 | %if
162 | % SubAcc == 0 -> false;
163 | % true ->
164 | % (SubAcc#sub_acc.balance >= Amount1)
165 | %end
166 | end,
167 |
168 | %check that the trade id isn't already consumed
169 | B4 = case talker:talk({trade, TID}, FNL) of
170 | {ok, 0} -> true;
171 | {ok, Trade} ->
172 | #trade{value = V} = Trade,
173 | V < (SN + Parts);
174 | X -> io:fwrite({X, TID})
175 | end,
176 | %B4 = {ok, 0} == talker:talk({trade, TID}, FNL),
177 | B6 = B2 and B3 and B4,
178 | if
179 | not(B4) ->
180 | already_accepted;
181 | (?verbose and not(B6)) ->
182 | io:fwrite(packer:pack(swap_full:read(TID))),
183 | io:fwrite("\n"),
184 | io:fwrite(packer:pack([B2, B3, B4])),
185 | io:fwrite("\n"),
186 | false;
187 | not(B6) ->
188 | false;
189 | true ->
190 | true
191 | end.
192 |
193 |
194 |
195 |
196 | no_repeats(_, _, []) -> true;
197 | no_repeats(Acc, Salt,
198 | [{signed,
199 | #swap_tx{
200 | offer =
201 | {signed,
202 | #swap_offer{
203 | acc1 = Acc,
204 | salt = Salt
205 | },
206 | _, _}
207 | }, _, _}|_]) ->
208 | false;
209 | no_repeats(Acc, Salt, [_|T]) ->
210 | no_repeats(Acc, Salt, T).
211 |
212 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/http_handler.erl:
--------------------------------------------------------------------------------
1 | -module(http_handler).
2 | -export([init/3, handle/2, terminate/3, doit/1, init/2]).
3 | -include("records.hrl").
4 | init(Req0, Opts) ->
5 | handle(Req0, Opts).
6 | init(_Type, Req, _Opts) -> {ok, Req, no_state}.
7 | terminate(_Reason, _Req, _State) -> ok.
8 | handle(Req, State) ->
9 | %{ok, Data0, Req2} = cowboy_req:body(Req),
10 | {ok, Data0, Req2} = cowboy_req:read_body(Req),
11 | %{{IP, _}, Req3} = cowboy_req:peer(Req2),
12 | {IP, _} = cowboy_req:peer(Req2),
13 | %io:fwrite("http handler got message: "),
14 | %io:fwrite(Data0),
15 | %io:fwrite("\n"),
16 | Data1 = jiffy:decode(Data0),
17 | Data = packer:unpack_helper(Data1),
18 | D = packer:pack(doit(Data)),
19 | %Headers = #{ <<"content-type">> => <<"application/octet-stream">>,
20 | % <<"Access-Control-Allow-Origin">> => <<"*">>},
21 | %Headers=[{<<"content-type">>,<<"application/octet-stream">>},
22 | %{<<"Access-Control-Allow-Origin">>, <<"*">>}],
23 | Headers = #{ <<"content-type">> => <<"application/octet-stream">>,
24 | <<"Access-Control-Allow-Origin">> => <<"*">>},
25 | %{ok, Req4} = cowboy_req:reply(200, Headers, D, Req2),
26 | Req4 = cowboy_req:reply(200, Headers, D, Req2),
27 | {ok, Req4, State}.
28 | doit({test}) -> {ok, "success"};
29 |
30 | doit({add, 2, Text, Height}) ->
31 | CID = binary_contracts:add(Text, Height),
32 | {ok, CID};
33 | doit({add, 3, Text, Height, MaxPrice, Source, SourceType}) ->
34 | io:fwrite("http handler.erl adding a scalar contract.\n"),
35 | CID = scalar_contracts:add(Text, Height, MaxPrice, Source, SourceType),
36 | {ok, CID};
37 | doit({add, 3, Text, Height, MaxPrice}) ->
38 | CID = scalar_contracts:add(Text, Height, MaxPrice),
39 | {ok, CID};
40 | doit({add, 4, BuyVeoContract}) ->
41 | io:fwrite("http handler adding buy veo contract \n"),
42 | CID = buy_veo_orders:add(BuyVeoContract),
43 | {ok, CID};
44 | doit({add, SwapOffer, SecondOffer}) ->
45 | %gives the server a new swap offer.
46 | io:fwrite("http handler swap add start \n"),
47 | io:fwrite(packer:pack(SwapOffer)),
48 | io:fwrite("\n"),
49 | S = element(2, SwapOffer),
50 | TID = utils:trade_id(S),
51 | true = swap_verify:doit(TID, SwapOffer),
52 | true = 2000 > size(term_to_binary(SecondOffer)),
53 | {Amount1, Amount2,
54 | CID1, Type1,
55 | CID2, Type2} =
56 | case S of
57 | #swap_offer{} ->
58 | #swap_offer
59 | {amount1 = Amount10,
60 | amount2 = Amount20,
61 | cid1 = CID10,
62 | type1 = Type10,
63 | cid2 = CID20,
64 | type2 = Type20
65 | } = S,
66 | {Amount10, Amount20,
67 | CID10, Type10,
68 | CID20, Type20};
69 | #swap_offer2{} ->
70 | #swap_offer2
71 | {amount1 = Amount11,
72 | amount2 = Amount21,
73 | cid1 = CID11,
74 | type1 = Type11,
75 | cid2 = CID21,
76 | type2 = Type21
77 | } = S,
78 | {Amount11, Amount21,
79 | CID11, Type11,
80 | CID21, Type21}
81 | end,
82 | <> = <<-1:32>>,
83 | Price = Amount1 * Max div Amount2,
84 | MID = utils:market_id(S),
85 | Nonce = swap_history:add(MID, TID, Amount1, Amount2),%cronological order, so we can sync faster.
86 | swap_books:add(MID, TID, Price, Amount1, Nonce, CID1, Type1, CID2, Type2),%order book
87 | swap_full:add(TID, SwapOffer, SecondOffer),%full swap data
88 | io:fwrite("http handler swap add end \n"),
89 | {ok, 0};
90 | doit({add, 2, Text, Height, Source, SourceType}) ->
91 | CID = binary_contracts:add(Text, Height, Source, SourceType),
92 | {ok, CID};
93 | doit({contracts}) ->
94 | {ok, scalar_contracts:keys()};
95 | doit({contracts, 2}) ->
96 | {ok, buy_veo_orders:keys()};
97 | doit({read, 3, CID}) ->
98 | case binary_contracts:read_contract(CID) of
99 | error ->
100 | case scalar_contracts:read_contract(CID) of
101 | error ->
102 | case buy_veo_orders:read_contract(CID) of
103 | error -> {ok, 0};
104 | Z -> Z
105 | end;
106 | Y -> Y
107 | end;
108 | X -> X
109 | end;
110 | doit({history, MID, Nonce}) ->
111 | %returns the history of updates to market ID since Nonce.
112 | %if Nonce is up to date, it waits a while before responding.
113 | {ok, swap_history:read(MID, Nonce)};
114 | doit({read, 2, ID}) ->
115 | %returns the full content of the trade with this ID
116 | {ok, {X, _}} = swap_full:read(ID),
117 | {ok, X};
118 | doit({read, ID}) ->
119 | %returns the current state of market ID
120 | {ok, swap_books:read(ID)};
121 | doit({markets}) ->
122 | %list of active markets.
123 | %we should also say something about the currencies being traded in each market.
124 | %X = swap_markets:read(),
125 | X = swap_books:markets(),
126 | {ok, X};
127 | doit({markets, 2}) ->
128 | X = swap_books:markets2(),
129 | {ok, X};
130 |
131 | %doit({oracle_list, 2}) ->
132 | % {ok, active_oracles:read()};
133 | %doit({oracle_list}) ->
134 | % {ok, volume_order:read()};
135 | %doit({oracle, OID}) ->
136 | % {ok, oracles:read(OID)};
137 | %doit({get_offers, L}) ->%list of CIDs
138 | % FN = utils:server_url(external),
139 | % L2 = case talker:talk({txs}, FN) of
140 | % bad_peer -> L;
141 | % {ok, Txs} ->
142 | % BadCIDs = read_filter(Txs),
143 | % list_subtract(L, BadCIDs)
144 | % end,
145 | % {ok, channel_offers_ram:read(L2)};
146 | %doit({get_offers, 2, L}) ->%list of Oracle IDs
147 | % S1 = lists:map(fun(X) -> oracles:read(X) end,
148 | % L),
149 | % R = get_offers_loop(S1, L, erlang:timestamp(), 60),
150 | %grab starting state of L.
151 | %keep checking to see if it changes.
152 | %if R is 0, nothing changed. if it is 1, then something changed.
153 | % {ok, R};
154 | %doit({get_offer_contract, CID}) ->
155 | % {ok, channel_offers_hd:read(CID)};
156 | %doit({add, 2, X}) -> {ok, close_offers:add(X)};
157 | %doit({read, 2, X}) -> {ok, close_offers:read(X)};
158 | doit(X) ->
159 | io:fwrite("http handler doit fail"),
160 | io:fwrite(X),
161 | error.
162 |
163 | is_in(X, []) -> false;
164 | is_in(X, [X|_]) -> true;
165 | is_in(X, [_|T]) ->
166 | is_in(X, T).
167 |
168 | %test() ->
169 | % C = <<"[-6,[-6,2,3000,5000,\"BBEuaxBNwXiTpEMTZI2gExMGpxCwAapTyFrgWMu5n4cIcqPojDz40Trf7xdWDlHL8KH+AvrTc2dhSC+35eSjmaQ=\",0,1000000,10000,10000,\"6shH4FO3E3mZ7gBKwWv71NxT0FvUTqaVjhZ7ygMnfCI=\",64239,1000,[-7,2,\"MEQCIEvjwRnANgJrhLfKiPyd3YHSvFXL7XA098Acw9fXrS46AiByuwStQoVjBetI2+GNhmCHA569JSjSxqoAhhAoL+ZRgg==\"],\"AAD67xOHJw/qyEfgU7cTeZnuAErBa/vU3FPQW9ROppWOFnvKAyd8IjBFAiEA8Y2dZkonQU4QXfm6LZqK3les3GP3HlkXRXoJxbiIDY0CIEVn/yOB7CazFCHLeFGUjhk3XkTUVsWYQFkw4Pz2xCPy\",1,2,\"Xy9Tecb4Xx88W4D+NW2CQgYrDIM+9m3r7d/zy6YNe7o=\",10,818,0,0],[\"signed\",[\"nc_offer\",\"BBEuaxBNwXiTpEMTZI2gExMGpxCwAapTyFrgWMu5n4cIcqPojDz40Trf7xdWDlHL8KH+AvrTc2dhSC+35eSjmaQ=\",10,64339,10000,10000,1000,1000,\"Xy9Tecb4Xx88W4D+NW2CQgYrDIM+9m3r7d/zy6YNe7o=\",\"nPwN6mIWS4JUIo2neplltEEifucqc43ytORXToDFtco=\"],\"MEUCIQCwxOaubh3Y7yuPBWZUKJy1jnhqYhLy+U1vRLZNO/pU1AIgX81qJ8HVp0r/Ac48tqG6F7yyYC7gKhcEka4qVk18G9U=\",[-6]]]">>,
170 | % doit({add, packer:unpack(C)}),
171 | % http_handler:doit({oracle_list}).
172 |
173 | %read_filter([]) -> [];
174 | %read_filter([{signed, T, _, _}|R]) when (element(1, T) == nc_accept) ->
175 | % SOffer = element(3, T),
176 | % {signed, Offer, _, _} = SOffer,
177 | % CID = element(9, Offer),
178 | % [CID|read_filter(R)];
179 | %read_filter([_|T]) ->
180 | % read_filter(T).
181 | %list_subtract([], _) -> [];
182 | %list_subtract([H|T], L) ->
183 | % B = is_in(H, L),
184 | % if
185 | % B -> list_subtract(T, L);
186 | % true -> [H|list_subtract(T, L)]
187 | % end.
188 |
189 |
190 | %get_offers_loop(S1, L, TS, TimeLimit) ->
191 | % Now = erlang:timestamp(),
192 | % D = timer:now_diff(Now, TS) div 1000000,%in seconds
193 | % S2 = lists:map(fun(X) -> oracles:read(X) end,
194 | % L),%we could use a different database that keeps a record of thetimes when each oracle is changed. That way we don't need to read so much data out of a slow dictionary.
195 | % if
196 | % D > TimeLimit -> 0;
197 | % S1 == S2 ->
198 | % timer:sleep(100),%miliseconds
199 | % get_offers_loop(S1, L, TS, TimeLimit);
200 | % true -> 1
201 | % end.
202 |
203 |
204 |
205 |
206 |
--------------------------------------------------------------------------------
/apps/amoveo_p2p_derivatives_explorer/src/swap_books.erl:
--------------------------------------------------------------------------------
1 | -module(swap_books).
2 | -behaviour(gen_server).
3 | -export([start_link/0,code_change/3,handle_call/3,handle_cast/2,handle_info/2,init/1,terminate/2,
4 | add/9, read/1, markets/0, markets2/0, garbage_cron/0, using_contract/1,
5 | garbage/0
6 | ]).
7 |
8 | %this is for storing the current order books for all the markets of swap offers.
9 |
10 |
11 | -define(LOC, "swap_books.db").
12 | -define(cron, 60000).%for production we probably want this higher than 1 second.
13 | -include("records.hrl").
14 |
15 | -record(market, {nonce = 1, mid, cid1, type1, cid2, type2, orders}).
16 | -record(order, {price, amount, tid}).
17 |
18 | new_order(TID, Price, Amount) ->
19 | #order{tid = TID,
20 | price = Price,
21 | amount = Amount}.
22 |
23 | init(ok) ->
24 | process_flag(trap_exit, true),
25 | X = db:read(?LOC),
26 | Y = if
27 | (X == "") -> dict:new();
28 | true -> X
29 | end,
30 | {ok, Y}.
31 |
32 | start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, ok, []).
33 | code_change(_OldVsn, State, _Extra) -> {ok, State}.
34 | terminate(_, X) ->
35 | db:save(?LOC, X),
36 | io:format("swap books died!"),
37 | ok.
38 | handle_info(_, X) -> {noreply, X}.
39 | handle_cast({add, MID, S, Nonce, CID1, Type1, CID2, Type2}, X) ->
40 | M2 = case dict:find(MID, X) of
41 | error -> #market{orders = [S], mid = MID,
42 | cid1 = CID1, type1 = Type1,
43 | cid2 = CID2, type2 = Type2
44 | };
45 | {ok, M} ->
46 | L2 = merge(S, M#market.orders),
47 | M#market{orders = L2,
48 | nonce = Nonce}
49 | end,
50 | X2 = dict:store(MID, M2, X),
51 | {noreply, X2};
52 | handle_cast({garbage, Height}, X) ->
53 | X2 = garbage(X, Height),
54 | {noreply, X2};
55 | handle_cast(_, X) -> {noreply, X}.
56 | handle_call({read, MID}, _From, X) ->
57 | Z = dict:find(MID, X),
58 | {reply, Z, X};
59 | handle_call(markets2, _From, X) ->
60 | Y = lists:map(
61 | fun(Z) ->
62 | {ok, Market} = dict:find(Z, X),
63 | %Market#market{orders = 0},
64 | #market{cid1 = CID1, cid2 = CID2} = Market,
65 | T1 = scalar_contracts:read_contract(CID1),
66 | T2 = scalar_contracts:read_contract(CID2),
67 | R1 = case T1 of
68 | {ok, Text1} -> Text1;
69 | _ -> ""
70 | end,
71 | R2 = case T2 of
72 | {ok, Text2} -> Text2;
73 | _ -> ""
74 | end,
75 | {Market#market{orders = 0},
76 | R1, R2}
77 | end,
78 | dict:fetch_keys(X)),
79 | {reply, Y, X};
80 | handle_call(markets, _From, X) ->
81 | Y = lists:map(
82 | fun(Z) ->
83 | {ok, Market} = dict:find(Z, X),
84 | Market#market{orders = 0}
85 | end,
86 | dict:fetch_keys(X)),
87 | {reply, Y, X};
88 | handle_call({using_contract, CID}, _From, X) ->
89 | %checks if we are using this contract. scans all the markets.
90 | K = dict:fetch_keys(X),
91 | B = using_contract_internal(CID, X, K),
92 | {reply, B, X};
93 | handle_call(_, _From, X) -> {reply, X, X}.
94 |
95 | using_contract_internal(_, _, []) ->
96 | false;
97 | using_contract_internal(CID, X, [H|T]) ->
98 | M = dict:fetch(H, X),
99 | if
100 | M#market.cid1 == CID -> true;
101 | M#market.cid2 == CID -> true;
102 | true ->
103 | using_contract_internal(CID, X, T)
104 | end.
105 |
106 | using_contract(X) ->
107 | gen_server:call(?MODULE, {using_contract, X}).
108 |
109 | add(MID, TID, Price, Amount, Nonce, CID1, Type1, CID2, Type2) ->
110 | S = new_order(TID, Price, Amount),
111 | gen_server:cast(?MODULE, {add, MID, S, Nonce, CID1, Type1, CID2, Type2}).
112 | read(ID) ->
113 | gen_server:call(?MODULE, {read, ID}).
114 | markets() ->
115 | gen_server:call(?MODULE, markets).
116 | markets2() ->
117 | gen_server:call(?MODULE, markets2).
118 | garbage() ->
119 | FN = utils:server_url(external),
120 | X = talker:talk({height}, FN),
121 | case X of
122 | {ok, Height} ->
123 | gen_server:cast(?MODULE, {garbage, Height});
124 | _ -> ok
125 | end.
126 |
127 | garbage(D, Height) ->
128 | % FN = utils:server_url(external),
129 | % X = talker:talk({height}, FN),
130 | % case X of
131 | % {ok, Height} ->
132 | K = dict:fetch_keys(D),
133 | garbage2(K, D, Height).
134 | % _ -> D
135 | % end.
136 | garbage2([], D, _) -> D;
137 | garbage2([MID|T], D, Height) ->
138 | Market = dict:fetch(MID, D),
139 | Orders = Market#market.orders,
140 | Orders2 = garbage_orders(Orders, MID, Height),
141 | D2 = if
142 | ([] == Orders2) ->
143 | dict:erase(MID, D);
144 | true ->
145 | Market2 =
146 | Market#market{
147 | orders = Orders2},
148 | dict:store(MID, Market2, D)
149 | end,
150 | garbage2(T, D2, Height).
151 | garbage_orders([], _, _) -> [];
152 | garbage_orders([H|T], MID, Height) ->
153 | TID = H#order.tid,
154 | F = case swap_full:read(TID) of
155 | error -> [];
156 | {ok, {S, Second}} ->
157 | Offer = element(2, S),
158 | B = swap_verify:keep_longer(
159 | Offer, Height, TID),
160 | if
161 | (B == true) -> [H];
162 | (B == already_accepted) ->
163 | if
164 | not(Second == 0) ->
165 | http_handler:doit({add, Second, 0});
166 | true -> ok
167 | end,
168 | [];
169 | true ->
170 | []
171 | % swap_history:remove(MID, TID),
172 | % case Second of
173 | % 0 -> ok;
174 | % _ -> re_absorb_cron(
175 | % Second, Height)
176 | % end,
177 | % swap_full:remove(TID),
178 | % []
179 | end
180 | end,
181 | F ++ garbage_orders(T, MID, Height).
182 |
183 |
184 | merge(S, []) -> [S];
185 | merge(S, [H|T]) ->
186 | if
187 | S#order.price > H#order.price ->
188 | [S|[H|T]];
189 | true ->
190 | [H|merge(S, T)]
191 | end.
192 |
193 |
194 | garbage_cron() ->
195 | spawn(fun() ->
196 | timer:sleep(?cron),
197 | garbage()
198 | end),
199 | spawn(fun() ->
200 | timer:sleep(?cron),
201 | timer:sleep(?cron),
202 | garbage_cron()
203 | end).
204 |
205 |
206 |
207 | re_absorb_cron(SignedOffer, Height) ->
208 | FN = utils:server_url(external),
209 | spawn(fun()->
210 | re_absorb_cron2(
211 | SignedOffer, Height)
212 | end).
213 | %re_absorb_cron_per_block(SignedOffer, Start, Recent) ->
214 | % %If the first offer is accepted, then we add the second to the pool.
215 | % FN = utils:server_url(external),
216 | % {ok, HeightNow} = talker:talk({height}, FN),
217 | % Offer = element(2, SignedOffer),
218 | % TID = utils:trade_id(Offer),
219 | % if
220 | % (HeightNow > (Start + 2)) ->
221 | % %out of time. try adding one last time.
222 | % http_handler:doit({add, SignedOffer, 0});
223 | % %swap_verify:doit(TID, SignedOffer,
224 | % HeightNow);
225 | % (HeightNow == Recent) ->
226 | % %wait longer for the next block.
227 | % timer:sleep(?cron),
228 | % re_absorb_cron_per_block(
229 | % SignedOffer, Start, Recent);
230 | % (HeightNow > Recent) ->
231 | % %maybe we can add it now.
232 | % B = swap_verify:keep_longer(Offer, Height2, TID),
233 | % if
234 | % B ->
235 | % http_handler:doit({add, SignedOffer, 0});
236 | % % swap_verify:doit(
237 | % TID, SignedOffer, HeightNow);
238 | % true ->
239 | % timer:sleep(?cron),
240 | % re_absorb_cron_per_block(
241 | % SignedOffer, Start, HeightNow)
242 | % end
243 | % end.
244 |
245 | re_absorb_cron2(SignedOffer, Height1) ->
246 | %for 2 blocks, keep trying to re-add this offer to the order book.
247 | io:fwrite("re absorb cron\n"),
248 | FN = utils:server_url(external),
249 | {ok, Height2} = talker:talk({height}, FN),
250 | Offer = element(2, SignedOffer),
251 | TID = utils:trade_id(Offer),
252 | B = swap_verify:keep_longer(Offer, Height2, TID),
253 | if
254 | Height2 > (Height1 + 2) ->
255 | io:fwrite("re absorb cron deleted\n"),
256 | %deleting the 2nd offer.
257 | ok;
258 | B ->
259 | io:fwrite("re absorb cron succeeded\n"),
260 | http_handler:doit({add, SignedOffer, 0});
261 | true ->
262 | timer:sleep(?cron),
263 | re_absorb_cron2(SignedOffer, Height1)
264 | end.
265 |
266 |
--------------------------------------------------------------------------------