├── .dockerignore
├── .drone.yml
├── .gitignore
├── .rspec
├── .ruby-version
├── Dockerfile
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── README.md
├── Rakefile
├── VERSION
├── bin
├── install.sh
├── install_webhook
├── quick-test.sh
├── set-env.sh
└── start.sh
├── compose
└── .gitkeep
├── config.ru
├── config
├── app.yml
├── applogic
│ └── .gitkeep
├── arke
│ └── .gitkeep
├── barong
│ ├── authz_rules.yml
│ └── barong.yml
├── frontend
│ └── .gitkeep
├── gateway
│ └── .gitkeep
├── influxdb
│ ├── arke.sql
│ ├── build_candles.sql
│ └── peatio.sql
├── mailer
│ └── templates
│ │ ├── deposit_accepted.en.html.erb
│ │ ├── email_confirmation.en.html.erb
│ │ ├── email_confirmation.ru.html.erb
│ │ ├── label.en.html.erb
│ │ ├── new_beneficiary.en.html.erb
│ │ ├── password_reset.en.html.erb
│ │ ├── password_reset.ru.html.erb
│ │ ├── session_create.en.html.erb
│ │ └── withdraw_succeed.en.html.erb
├── mysql
│ └── innodb.cnf
├── peatio
│ ├── plugins.yml
│ └── seed
│ │ └── .gitkeep
├── secrets
│ └── .gitkeep
└── utils.yml
├── data
├── mysql
│ ├── barong_production.sql
│ └── peatio_production.sql
└── parity
│ └── .gitkeep
├── docs
├── aws-install.md
├── images
│ └── OpenDAX-authorization.png
├── troubleshoot-barong-authz.md
└── ubuntu-install.md
├── lib
├── opendax
│ ├── payload.rb
│ ├── renderer.rb
│ ├── vault.rb
│ └── webhook.rb
└── tasks
│ ├── db.rake
│ ├── docker.rake
│ ├── payload.rake
│ ├── render.rake
│ ├── service.rake
│ ├── terraform.rake
│ ├── toolbox.rake
│ ├── vault.rake
│ ├── vendor.rake
│ ├── versions.rake
│ └── wallets.rake
├── spec
├── opendax
│ ├── payload_spec.rb
│ ├── renderer_spec.rb
│ └── server_spec.rb
└── spec_helper.rb
├── templates
├── .env.erb
├── compose
│ ├── app.yaml.erb
│ ├── arke.yaml.erb
│ ├── backend.yaml.erb
│ ├── cryptonodes.yaml.erb
│ ├── daemons.yaml.erb
│ ├── frontend.yaml.erb
│ ├── gateway.yaml.erb
│ ├── monitoring.yaml.erb
│ ├── proxy.yaml.erb
│ ├── superset.yaml.erb
│ └── vendor.yaml.erb
├── config
│ ├── applogic.env.erb
│ ├── applogic
│ │ ├── management_api_v2.yml.erb
│ │ └── schedule.yml.erb
│ ├── arke.env.erb
│ ├── arke
│ │ └── strategies.yml.erb
│ ├── barong.env.erb
│ ├── barong
│ │ ├── abilities.yml.erb
│ │ ├── management_api.yml.erb
│ │ └── seeds.yml.erb
│ ├── bitcoin.conf.erb
│ ├── finex
│ │ ├── config.yaml.erb
│ │ └── rsa-key.pub.erb
│ ├── frontend
│ │ ├── env.js.erb
│ │ └── tower.js.erb
│ ├── gateway
│ │ └── envoy.yaml.erb
│ ├── litecoin.conf.erb
│ ├── mailer.yml.erb
│ ├── mysql
│ │ └── innodb.cnf.erb
│ ├── peatio.env.erb
│ ├── peatio
│ │ ├── abilities.yml.erb
│ │ ├── management_api_v1.yml.erb
│ │ └── seed
│ │ │ ├── accounts.yml.erb
│ │ │ ├── blockchains.yml.erb
│ │ │ ├── currencies.yml.erb
│ │ │ ├── engines.yml.erb
│ │ │ ├── markets.yml.erb
│ │ │ ├── trading_fees.yml.erb
│ │ │ └── wallets.yml.erb
│ ├── rango.env.erb
│ ├── toolbox.yaml.erb
│ └── vault
│ │ ├── barong.hcl.erb
│ │ ├── finex_engine.hcl.erb
│ │ ├── peatio_crypto.hcl.erb
│ │ ├── peatio_matching.hcl.erb
│ │ ├── peatio_rails.hcl.erb
│ │ └── peatio_upstream.hcl.erb
├── terraform
│ └── terraform.tfvars.erb
└── webhook.service
├── terraform
├── main.tf
└── variables.tf
└── vendor
└── .gitkeep
/.dockerignore:
--------------------------------------------------------------------------------
1 | Dockerfile
2 | .dockerignore
3 | .git
4 | .gitignore
5 | LICENSE
6 | README
7 |
--------------------------------------------------------------------------------
/.drone.yml:
--------------------------------------------------------------------------------
1 | kind: pipeline
2 | name: default
3 |
4 | steps:
5 | - name: Run rspec
6 | image: ruby:2.6.5
7 | commands:
8 | - gem install bundler
9 | - bundle
10 | - bundle exec rspec
11 | when:
12 | event:
13 | - pull_request
14 | - name: Bump and tag
15 | image: quay.io/openware/sdk-tools:0.0.3
16 | environment:
17 | BRANCH_NAME: ${DRONE_BRANCH}
18 | REPO_NAME: ${DRONE_REPO}
19 | BOT_USERNAME: kite-bot
20 | BOT_NAME: Kite Bot
21 | BOT_EMAIL: kite-bot@heliostech.fr
22 | GITHUB_API_KEY:
23 | from_secret: kite_bot_key
24 | commands:
25 | - BUNDLE_GEMFILE=/sdk/Gemfile bundle exec rake --rakefile=/sdk/Rakefile release:push
26 | when:
27 | event: [push]
28 | branch: [master]
29 |
30 | image_pull_secrets:
31 | - dockerconfigjson
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | config/acme.json
2 | config/frontend/*.js
3 | config/gateway/mapping.yaml
4 | config/peatio/management_api_v1.yml
5 | config/barong/management_api.yml
6 | config/finex/*
7 | config/toolbox.yaml
8 | config/traefik.toml
9 | config/*.env
10 | config/secrets/*
11 | !config/secrets/.gitkeep
12 | config/peatio/seed/*
13 | !config/peatio/seed/.gitkeep
14 | config/applogic/*
15 | !config/applogic/.gitkeep
16 | vendor/
17 | !vendor/.gitkeep
18 | .terraform/
19 | *.tfvars
20 | terraform.tfstate*
21 | !data/parity/.gitkeep
22 |
--------------------------------------------------------------------------------
/.rspec:
--------------------------------------------------------------------------------
1 | --require spec_helper
2 |
--------------------------------------------------------------------------------
/.ruby-version:
--------------------------------------------------------------------------------
1 | ruby-2.6.6
2 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ruby:2.6.1
2 |
3 | ENV APP_HOME=/home/app
4 |
5 | ARG UID=1000
6 | ARG GID=1000
7 |
8 | RUN groupadd -r --gid ${GID} app \
9 | && useradd --system --create-home --home ${APP_HOME} --shell /sbin/nologin --no-log-init \
10 | --gid ${GID} --uid ${UID} app
11 |
12 | USER app
13 | WORKDIR $APP_HOME
14 |
15 | COPY --chown=app:app . .
16 |
17 | RUN bundle install --jobs=$(nproc) --deployment
18 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6 |
7 | ruby '~>2.6'
8 |
9 | gem 'rake'
10 | gem 'sshkey' # SSH key generation gem
11 |
12 | # webhook server deps
13 | gem 'bump'
14 | gem 'rack'
15 | gem 'sinatra'
16 | gem 'puma'
17 | gem 'rspec'
18 | gem 'jwt'
19 | gem 'faraday'
20 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | bump (0.9.0)
5 | diff-lcs (1.3)
6 | faraday (1.0.0)
7 | multipart-post (>= 1.2, < 3)
8 | jwt (2.2.1)
9 | multipart-post (2.1.1)
10 | mustermann (1.1.1)
11 | ruby2_keywords (~> 0.0.1)
12 | nio4r (2.5.8)
13 | puma (4.3.12)
14 | nio4r (~> 2.0)
15 | rack (2.2.6.2)
16 | rack-protection (2.0.8.1)
17 | rack
18 | rake (13.0.1)
19 | rspec (3.9.0)
20 | rspec-core (~> 3.9.0)
21 | rspec-expectations (~> 3.9.0)
22 | rspec-mocks (~> 3.9.0)
23 | rspec-core (3.9.1)
24 | rspec-support (~> 3.9.1)
25 | rspec-expectations (3.9.0)
26 | diff-lcs (>= 1.2.0, < 2.0)
27 | rspec-support (~> 3.9.0)
28 | rspec-mocks (3.9.1)
29 | diff-lcs (>= 1.2.0, < 2.0)
30 | rspec-support (~> 3.9.0)
31 | rspec-support (3.9.2)
32 | ruby2_keywords (0.0.2)
33 | sinatra (2.0.8.1)
34 | mustermann (~> 1.0)
35 | rack (~> 2.0)
36 | rack-protection (= 2.0.8.1)
37 | tilt (~> 2.0)
38 | sshkey (2.0.0)
39 | tilt (2.0.10)
40 |
41 | PLATFORMS
42 | ruby
43 |
44 | DEPENDENCIES
45 | bump
46 | faraday
47 | jwt
48 | puma
49 | rack
50 | rake
51 | rspec
52 | sinatra
53 | sshkey
54 |
55 | RUBY VERSION
56 | ruby 2.6.3p62
57 |
58 | BUNDLED WITH
59 | 2.1.4
60 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 |
9 |
10 |
11 | # OpenDAX
12 |
13 | OpenDAX is an open-source cloud-native multi-service platform for building a Blockchain/FinTech exchange of digital assets, cryptocurrency and security tokens.
14 |
15 | ## Getting started with OpenDAX
16 |
17 | ### 1. Get a VM
18 |
19 | Minimum VM requirements for OpenDAX:
20 | * 8GB of RAM (12GB recommended)
21 | * 4 cores vCPU (6 cores recommended)
22 | * 300GB disk space (SSD recommended)
23 |
24 | A VM from any cloud provider like DigitalOcean, Vultr, GCP, AWS as well as any dedicated server with Ubuntu, Debian or Centos would work
25 |
26 | ### 2. Prepare the VM
27 |
28 | #### 2.1 Create Unix user
29 | SSH using root user, then create new user for the application
30 | ```bash
31 | useradd -g users -s `which bash` -m app
32 | ```
33 |
34 | #### 2.2 Install Docker and docker compose
35 |
36 | We highly recommend using docker and compose from docker.com install guide instead of the system provided package, which would most likely be deprecated.
37 |
38 | Docker follow instruction here: [docker](https://docs.docker.com/install/)
39 | Docker compose follow steps: [docker compose](https://docs.docker.com/compose/install/)
40 |
41 | #### 2.3 Install ruby in user app
42 |
43 | ##### 2.3.1 Change user using
44 | ```bash
45 | su - app
46 | ```
47 |
48 | ##### 2.3.2 Clone OpenDAX
49 | ```bash
50 | git clone https://github.com/openware/opendax.git
51 | ```
52 |
53 | ##### 2.3.3 Install RVM
54 | ```bash
55 | gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
56 | curl -sSL https://get.rvm.io | bash -s stable
57 | cd opendax
58 | rvm install .
59 | ```
60 |
61 | ### 3. Bundle install dependencies
62 |
63 | ```bash
64 | bundle install
65 | rake -T # To see if ruby and lib works
66 | ```
67 |
68 | Using `rake -T` you can see all available commands, and can create new ones in `lib/tasks`
69 |
70 | ### 4. Run everything
71 |
72 | #### 4.1 Configure your domain
73 | If using a VM you can point your domain name to the VM ip address before this stage.
74 | Recommended if you enabled SSL, for local development edit the `/etc/hosts`
75 |
76 | Insert in file `/etc/hosts`
77 | ```
78 | 0.0.0.0 www.app.local
79 | ```
80 |
81 | #### 4.2 Bring everything up
82 |
83 | ```bash
84 | rake service:all
85 | ```
86 |
87 | You can login on `www.app.local` with the following default users from seeds.yaml
88 | ```
89 | Seeded users:
90 | Email: admin@barong.io, password: 0lDHd9ufs9t@
91 | Email: john@barong.io, password: Am8icnzEI3d!
92 | ```
93 |
94 | ### [Optional] KYCAID
95 |
96 | In order to accelerate customer interaction, reduce risks and simplify business processes you can use KYC Verification Service from KYCaid.
97 | KYC goal is to prevent fraud and to decline users that don’t fulfill certain standards of credibility.
98 | To learn more about KYCaid and pricing you can visit their website - [kycaid.com](https://www.kycaid.com/)
99 |
100 | #### How to configure KYCAID on the platform?
101 |
102 | KYCAID is already integrated into our stack, to use it you'd need to create an account on [kycaid.com](https://www.kycaid.com/), and set up authentification creds there and the callback url: https://example.com/api/v2/barong/public/kyc
103 |
104 | After that all you have to do is to change several lines in `config/app.yml`:
105 |
106 | ```yaml
107 | kyc:
108 | provider: kycaid
109 | authorization_token: changeme # your production API token from the 'Settings' section of kycaid.com
110 | sandbox_mode: true # 'true' for test environments - documents will be verified/rejected automatically, without payment for verification
111 | api_endpoint: https://api.kycaid.com/
112 | ```
113 |
114 | ##### Additional settings for KYCAID
115 |
116 | * Be sure to check `BARONG_REQUIRED_DOCS_EXPIRE` ENV value inside `config/barong.env` to be `false` if you want to include `address` verification in your KYC process. You can set it to `true` if you need the document check only.
117 | * Check if you have the correct list of `document_types` in the `config/barong/barong.yml` file:
118 | - Passport
119 | - Identity card
120 | - Driver license
121 | - Address
122 | * Frontend KYC steps can be configured in `templates/config/frontend/env.js.erb` via the `kycSteps` field
123 | * Tower KYC labels can be configured in `templates/config/frontend/tower.js.erb` via the `labelSwitcher` field
124 |
125 | ## Usage
126 |
127 | ### Initial configuration
128 |
129 | All the OpenDAX deployment files have their confguration stored in `config/app.yml`.
130 |
131 | #### app.yml
132 |
133 | The following table lists the configurable parameters of the config/app.yml configuration file and its default values.
134 |
135 | Parameter | Description | Default
136 | --- | --- | ---
137 | `app.name` | global application name | `"OpenDax"`
138 | `app.domain` | base domain name | `app.local`
139 | `app.subdomain` | subdomain | `www`
140 | `app.show_landing` | enable/disable landing page display for the frontend application | `true`
141 | `render_protect` | enable read-only mode for rendered files | `false`
142 | `csrfEnabled` | enable CSRF protection on Barong | `false`
143 | `ssl.enabled` | enable SSL certificate generation | `false`
144 | `ssl.email` | email address used for SSL certificate issuing | `"support@example.com"`
145 | `updateVersions` | update all image tags by fetching global ones for OpenDAX | `false`
146 | `images` | Docker image tags per component
147 | `vendor.frontend` | optional Git URL for a development frontend repo | `git@github.com:openware/baseapp.git`
148 | `kyc.provider` | KYC provider, can be `kycaid` or `local` | `kycaid`
149 | `kyc.authorization_token` | optional API token for KYCAID use | `changeme`
150 | `kyc.sandbox` | enable KYCAID test mode | `true`
151 | `kyc.api_endpoint` | API endpoint for KYCAID | `https://api.kycaid.com/`
152 | `vault.root_token` | Root Vault authentication token | `changeme `
153 | `vault.peatio_rails_token` | Peatio Server Vault authentication token | `changeme `
154 | `vault.peatio_crypto_token` | Peatio Daemons (cron_job, deposit, deposit_coin_address, withdraw_coin) Vault authentication token | `changeme `
155 | `vault.peatio_upstream_token` | Peatio Upstream Daemon Vault authentication token | `changeme `
156 | `vault.peatio_matching_token` | Peatio Daemons (matching, order_processor, trade_executor) Vault authentication token | `changeme `
157 | `vault.barong_token` | Barong Vault authentication token | `changeme `
158 | `vault.finex_engine_token` | Finex Engine Vault authentication token | `changeme `
159 | `database.adapter`| database adapter kind either `mysql` or `postgresql` |`mysql`
160 | `database.host` | database host name | `db`
161 | `database.port` | database port | `3306 `
162 | `database.user` | database username | `root`
163 | `database.password` | database root password | `changeme`
164 | `storage.provider` | object storage provider | `"Google"`
165 | `storage.bucketname` | storage bucket name | `"opendax-barong-docs-bucket"`
166 | `storage.endpoint` | S3-compatible storage API endpoint | `"https://fra1.digitaloceanspaces.com"`
167 | `storage.region` | storage region | `"fra1"`
168 | `storage.signatureVersion` | S3-compatible storage API signature version(2 or 4) | `"fra1"`
169 | `storage.secretkey`, `storage.accesskey` | storage access keys | `"changeme"`
170 | `twilio` | [Twilio](https://www.twilio.com/) SMS provider configs
171 | `gaTrackerKey` | [Google Analytics](https://analytics.google.com/) tracker key inserted into the frontend app
172 | `smtp` | SMTP configs used for sending platform emails
173 | `captcha` | captcha configuration([Recaptcha](https://www.google.com/recaptcha) or [Geetest](https://www.geetest.com))
174 | `wallets` | configs for wallets seeded during the initial deployment of Peatio
175 | `parity` | Parity cryptonode configuration
176 | `bitcoind` | Bitcoind cryptonode configuration
177 | `litecoind` | Litecoind cryptonode configuration
178 | `terraform.credentials` | local path to a GCP service account JSON key | `"~/safe/opendax.json"`
179 | `terraform.project` | GCP project name | `"example-opendax"`
180 |
181 | ### utils.yml
182 |
183 | The following table lists configurable parameters of the `config/utils.yml` file:
184 |
185 | Parameter | Description | Default
186 | --- | --- | ---
187 | images | Docker image tags per component |
188 | superset | Superset BI tool configs |
189 | arke | Arke liquidity bot configs |
190 |
191 | Once you're done with the configuration, render the files using `rake render:config`. You can easily apply your changes at any time by running this command.
192 |
193 | Note: be sure to append all the subdomains based on app.domain to your
194 | /etc/hosts file if you're running OpenDax locally
195 |
196 | ### Bringing up the stack
197 |
198 | The OpenDAX stack can be brought up using two ways:
199 |
200 | 1. Bootstrap all the components at once using `rake service:all[start]`
201 | 2. Start every component one-by-one using `rake service:*component*[start]`
202 |
203 | The components included in the stack are:
204 |
205 | - `proxy` - [Traefik](https://traefik.io/), a robust cloud-native edge router/reverse proxy written in Go
206 | - `backend` - [Vault](https://www.vaultproject.io), [MySQL](https://www.mysql.com), [Redis](https://redis.io) and [RabbitMQ](https://www.rabbitmq.com) grouped together
207 | - `cryptonodes` - cryptocurrency nodes such as [parity](https://github.com/paritytech/parity-ethereum) **[Optional]**
208 | - `daemons` - Peatio and Ranger daemons **[Optional]**
209 | - `setup` - setup hooks for Peatio and Barong to run before the application starts (DB migration etc.)
210 | - `app` - Peatio is the [crypto exchange software](https://www.openware.com/), [Barong](https://github.com/openware/barong) and the [Ambassador](https://www.getambassador.io) API gateway
211 | - `frontend` - the frontend application located at `vendor/frontend`
212 | - `tower` - the Tower admin panel application located at `vendor/tower`
213 | - `monitoring` - [cAdvisor](https://github.com/google/cadvisor) and [Node Exporter](https://github.com/prometheus/node_exporter) monitoring tools **[Optional]**
214 |
215 | For example, to start the `backend` services, you'll simply need to run `rake service:backend[start]`
216 |
217 | Note: all the components marked as [Optional] need to be installed using
218 | rake service:*component*[start] explicitly
219 |
220 | Go ahead and try your own OpenDAX exchange deployment!
221 |
222 | ### Stopping and restarting components
223 |
224 | Any component from the stack can be easily stopped or restarted using `rake service:*component*[stop]` and `rake service:*component*[restart]`.
225 |
226 | For example, `rake service:frontend[stop]` would stop the frontend application container and `rake service:proxy[restart]` would completely restart the reverse proxy container.
227 |
228 | # Managing component deployments
229 |
230 | Each component has a config file (ex. `config/frontend/tower.js`) and a compose file (ex. `compose/frontend.yaml`).
231 |
232 | All config files are mounted into respective component container, except from `config/app.yml` - this file contains all the neccessary configuration of opendax deployment
233 |
234 | Compose files contain component images, environment configuration etc.
235 |
236 | These files get rendered from their respective templates that are located under `templates` directory.
237 |
238 | ## How to update component image?
239 |
240 | Modify `config/app.yml` with correct image and run `rake service:all`
241 | This will rerender all the files from `templates` directory and restart all the running services.
242 |
243 | Alternitavely you can update the following files:
244 | * `config/app.yml`
245 | * `templates/compose/*component*.yml`
246 | * `compose/*component*.yml`
247 | And run `rake service:component[start]`
248 |
249 | ## How to update component config?
250 |
251 | Modify `config/*component*/*config*` and run `rake service:component[start]`,
252 | if you want the changes to be persistent, you also need to update `templates/config/*components*/*config*`
253 |
254 | #### Render compose file
255 | ```
256 | # Delete all generated files
257 | git clean -fdx
258 |
259 | # Re-generate config from config/app.yml values
260 | rake render:config
261 |
262 | # Restart the container you need to reload config
263 | docker-compose up frontend -Vd
264 | ```
265 |
266 | #### Clone the vendors and start
267 | ```
268 | source ./bin/set-env.sh
269 | rake vendor:clone
270 | docker-compose -f compose/vendor.yaml up -d
271 | ```
272 |
273 | ## Vault management
274 | Opendax uses [Vault Policies](https://www.vaultproject.io/docs/concepts/policies) to restrict components' access to sensitive data. Each component has its own Vault token which allows granular access only to the data required.
275 |
276 | OpenDAX has 2 rake tasks for Vault management:
277 | ```sh
278 | rake vault:setup # Initial Vault configuration (root token generation, unseal, endpoints configuration)
279 | rake vault:load_policies # Components' Vault token generation
280 | ```
281 |
282 | ### Troubleshooting
283 | #### Vault is sealed
284 |
285 | In case of such error:
286 | 1. Run `rake vault:setup`
287 | 2. Restart the component
288 |
289 | Make sure you're not using an existing Docker volume for Vault(i.e. one left after a different Vault container deployment):
290 | ```sh
291 | docker volume ls | grep vault
292 | ```
293 |
294 | In case there are existing volumes, remove the running Vault container via `docker rm -f *id*` and run `docker volume rm -f *volume name*`
295 | Afterward, run `docker-compose up -Vd vault` and re-run `rake vault:setup`.
296 |
297 | #### Vault permission denied
298 | Usually, this means that one of your Vault tokens has expired.
299 |
300 | To fix the issue:
301 | 1. Run `rake vault:load_policies`
302 | 2. Run `rake render:config`
303 | 3. Restart Vault dependant components:
304 |
305 | ```
306 | docker-compose up -Vd barong peatio cron_job deposit deposit_coin_address withdraw_coin upstream
307 |
308 | # If you are using Finex
309 | docker-compose up -Vd finex-engine
310 |
311 | # If you are using Peatio Matching Engine
312 | docker-compose up -Vd matching order_processor trade_executor
313 | ```
314 |
315 | ## Terraform Infrastructure as Code Provisioning
316 |
317 | You can easily deploy OpenDAX from scratch on Google Cloud Platform using [Terraform](https://www.terraform.io)!
318 |
319 | To do this, just follow these simple steps:
320 | - Fill `app.yml` with correct values
321 | - Run `rake terraform:apply`
322 | - Access your VM from the GCP Cloud Console
323 |
324 | To destroy the provisioned infrastructure, just run `rake terraform:destroy`
325 |
326 | ## Installer tool
327 |
328 | ```
329 | ruby -e "$(curl -fsSL https://raw.githubusercontent.com/openware/opendax/master/bin/install)"
330 | ```
331 |
332 | ## Using an OpenDAX deployment for local frontend development
333 |
334 | If you'd like to use a real API from an existing OpenDAX deployment when developing frontend components(e.g. [baseapp](https://github.com/openware/baseapp)), modify `templates/config/gateway/envoy.yaml.erb` file the following way:
335 |
336 | 1. Set `allow_origin` as `"*"`
337 |
338 | 2. Configure all the needed HTTP methods in `allow_methods`. For example: `allow_methods: "PUT, GET, POST, DELETE, PATCH"`
339 |
340 | 3. Add `'total, page, x-csrf-token'` to `allow_headers` value
341 |
342 | 4. Configure `expose_headers` in a similar way `expose_headers: "total, page, x-csrf-token"`
343 |
344 | 5. Add `allow_credentials: true` to your CORS configuration
345 |
346 | After completing these steps, you should have the following config:
347 | ```
348 | cors:
349 | allow_origin:
350 | - "*"
351 | allow_methods: "PUT, GET, POST, DELETE, PATCH"
352 | allow_headers: "content-type, x-grpc-web, total, page, x-csrf-token"
353 | expose_headers: "total, page, x-csrf-token"
354 | allow_credentials: true
355 | ```
356 |
357 | Afterwards, apply the config onto your deployment:
358 | ```
359 | rake render:config
360 | docker-compose up -Vd gateway
361 | ```
362 |
363 | ## Happy trading with OpenDAX!
364 |
365 | If you have any comments, feedback and suggestions, we are happy to hear from you here at GitHub or here: [crypto exchange software](https://www.openware.com/)
366 |
367 | ## 2.6 Migration guide
368 |
369 | To migrate from 2.5 to 2.6, do the following:
370 | 1. Pull 2-6-stable branch
371 | While rebasing, rename your `vault.token` to `vault.root_token` in `config/app.yml`
372 | 2. Run `rake render:config`
373 | 3. Run `dc up -Vd vault`
374 | 4. Run `rake service:all`
375 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 | require 'base64'
3 | require 'erb'
4 |
5 | CONFIG_PATH = 'config/app.yml'.freeze
6 | UTILS_PATH = 'config/utils.yml'.freeze
7 |
8 | @config = YAML.load_file(CONFIG_PATH)
9 | @utils = YAML.load_file(UTILS_PATH)
10 |
11 | # Add your own tasks in files placed in lib/tasks ending in .rake
12 | Dir.glob('lib/tasks/*.rake').each do |task|
13 | load task
14 | end
15 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 0.1.57
2 |
--------------------------------------------------------------------------------
/bin/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 |
3 | COMPOSE_VERSION="1.23.2"
4 | COMPOSE_URL="https://github.com/docker/compose/releases/download/$COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)"
5 |
6 | # Opendax bootstrap script
7 | install_core() {
8 | sudo bash < /etc/docker/daemon.json
25 | EOS
26 | }
27 |
28 | # Docker installation
29 | install_docker() {
30 | curl -fsSL https://get.docker.com/ | bash
31 | sudo bash < webhook.service
4 | sed -i s#OPENDAX_DIRECTORY#${PWD}#g webhook.service
5 |
6 | echo "Generated Secret: ${SECRET}"
7 |
8 | sudo mv ./webhook.service /etc/systemd/system/webhook.service
9 | sudo systemctl daemon-reload
10 | sudo systemctl start webhook
11 |
--------------------------------------------------------------------------------
/bin/quick-test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | http --session barong POST http://www.app.local/api/v2/barong/identity/sessions email='admin@barong.io' password='0lDHd9ufs9t@'
6 | http --session barong GET http://www.app.local/api/v2/barong/resource/users/me
7 | http --session barong GET http://www.app.local/api/v2/peatio/account/balances
8 |
--------------------------------------------------------------------------------
/bin/set-env.sh:
--------------------------------------------------------------------------------
1 | export UID=$(id -u)
2 | export GID=$(id -g)
3 | alias dc=docker-compose
4 |
--------------------------------------------------------------------------------
/bin/start.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 |
3 | COMPOSE_VERSION="1.23.2"
4 | COMPOSE_URL="https://github.com/docker/compose/releases/download/$COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)"
5 |
6 | install_opendax() {
7 | sudo -u deploy bash <
2 |
3 | |
4 |
5 |
6 |
7 |
8 | <%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
9 | |
10 |
11 |
12 | | |
13 |
14 |
15 | |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Deposit <%= @record.state %>
27 |
28 | Your deposit #<%= @record.tid %> of <%= @record.amount %> <%= @record.currency %> has been <%= @record.state %>.
29 |
30 |
31 | |
32 |
33 |
34 | |
35 |
36 |
37 |
38 |
39 |
40 |
50 |
51 | |
52 | |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/config/mailer/templates/email_confirmation.en.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | |
4 |
5 |
6 |
7 |
8 | <%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
9 | |
10 |
11 |
12 | | |
13 |
14 |
15 | |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Hello!
27 |
28 | Use this unique link to confirm your email <%= @user.email %>
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Confirm
40 | |
41 |
42 |
43 |
44 | |
45 |
46 |
47 |
48 |
49 | |
50 |
51 |
52 | |
53 |
54 |
55 |
56 |
57 |
58 |
68 |
69 | |
70 | |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/config/mailer/templates/email_confirmation.ru.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | |
4 |
5 |
6 |
7 |
8 | <%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
9 | |
10 |
11 |
12 | | |
13 |
14 |
15 | |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Здравствуйте!
27 |
28 | Используйте эту уникальную ссылку для подтверждения вашей почты <%= @user.email %>
29 |
30 |
31 |
32 |
33 |
34 |
35 |
44 | |
45 |
46 |
47 |
48 |
49 | |
50 |
51 |
52 | |
53 |
54 |
55 |
56 |
57 |
58 |
68 |
69 | |
70 | |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/config/mailer/templates/label.en.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | |
4 |
5 |
6 |
7 |
8 | <%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
9 | |
10 |
11 |
12 | | |
13 |
14 |
15 | |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Hello!
27 |
28 | <% if @record.value == "verified" %>
29 | Congratulations, your account details was successfully upgraded.
30 | <% end %>
31 | <% if @record.value == "rejected" %>
32 | Unfortunately, your account details was rejected.
33 | <% end %>
34 | Your current account level is <%= @record.user.level %>
35 | Your account state is <%= @record.user.state %>
36 |
37 |
38 | <% if @record.key == "profile" %>
39 | Recently your user profile was <%= @record.value %>.
40 | <% end %>
41 | <% if @record.key == "id_document" %>
42 | Recently your main document was <%= @record.value %>.
43 | <% end %>
44 | <% if @record.key == "second_document" %>
45 | Recently your second document was <% @record.value %>.
46 | <% end %>
47 | <% if @record.key == "institutional" %>
48 | Recently your institutional document was <%= @record.value %>.
49 | <% end %>
50 |
51 |
52 | |
53 |
54 |
55 | |
56 |
57 |
58 |
59 |
60 |
61 |
71 |
72 | |
73 | |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/config/mailer/templates/new_beneficiary.en.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | |
4 |
5 |
6 |
7 |
8 | <%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
9 | |
10 |
11 |
12 | | |
13 |
14 |
15 | |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | New <%= @record.currency %> beneficiary <%= @record.name %> created!
27 |
28 | Your pin-code for this beneficiary is <%= @record.pin %>.
29 |
30 |
31 | |
32 |
33 |
34 | |
35 |
36 |
37 |
38 |
39 |
40 |
50 |
51 | |
52 | |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/config/mailer/templates/password_reset.en.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | |
4 |
5 |
6 |
7 |
8 | <%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
9 | |
10 |
11 |
12 | | |
13 |
14 |
15 | |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Hello!
27 |
28 | Use this unique link to reset your password for email <%= @user.email %>
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Reset
40 | |
41 |
42 |
43 |
44 | |
45 |
46 |
47 |
48 |
49 | |
50 |
51 |
52 | |
53 |
54 |
55 |
56 |
57 |
58 |
68 |
69 | |
70 | |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/config/mailer/templates/password_reset.ru.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | |
4 |
5 |
6 |
7 |
8 | <%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
9 | |
10 |
11 |
12 | | |
13 |
14 |
15 | |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Здравствуйте!
27 |
28 | Используйте эту уникальную ссылку для сброса вашего пароля <%= @user.email %>
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Сбросить
40 | |
41 |
42 |
43 |
44 | |
45 |
46 |
47 |
48 |
49 | |
50 |
51 |
52 | |
53 |
54 |
55 |
56 |
57 |
58 |
68 |
69 | |
70 | |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/config/mailer/templates/session_create.en.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | |
4 |
5 |
6 |
7 |
8 | <%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
9 | |
10 |
11 |
12 | | |
13 |
14 |
15 | |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Hello!
27 |
28 | We detected a login to your account.
29 |
30 | IP Address: <%= @record.user_ip %>
31 | User-agent: <%= @record.user_agent %>
32 |
33 | If this was you, please disregard this email.
34 |
35 | If this wasn't you, please change your passwords immediately, as someone else may be accessing your account.
36 |
37 | |
38 |
39 |
40 | |
41 |
42 |
43 |
44 |
45 |
46 |
56 |
57 | |
58 | |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/config/mailer/templates/withdraw_succeed.en.html.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 | |
4 |
5 |
6 |
7 |
8 | <%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
9 | |
10 |
11 |
12 | | |
13 |
14 |
15 | |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Withdrawal <%= @record.state %>
27 |
28 | Your withdrawal #<%= @record.tid %> of <%= @record.amount %> <%= @record.currency %> has been <%= @record.state %>.
29 |
30 |
31 | |
32 |
33 |
34 | |
35 |
36 |
37 |
38 |
39 |
40 |
50 |
51 | |
52 | |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/config/mysql/innodb.cnf:
--------------------------------------------------------------------------------
1 | [mysqld]
2 | innodb_buffer_pool_size = 2G
3 | innodb_buffer_pool_instances = 2
4 | innodb_log_buffer_size = 128M
5 | innodb_log_file_size = 512M
6 | innodb_flush_log_at_trx_commit = 0
7 |
--------------------------------------------------------------------------------
/config/peatio/plugins.yml:
--------------------------------------------------------------------------------
1 | # Be sure to run "bin/install_plugins" when you modify this file.
2 | #
3 | # This file is used for listing Peatio plugins.
4 | # The plugins must be listed as an array. Each element of array described the plugin using the next variables:
5 | #
6 | # * name
7 | # Mandatory. Specify plugin name. The name must be compatible with filesystem rules.
8 | #
9 | # * git
10 | # Mandatory. Specify Git repository URL.
11 | #
12 | # * commit
13 | # Mandatory. Specify commit hash which Peatio will checkout via "bin/install_plugins".
14 | #
15 | # * require
16 | # Optional. Specify relative path to file from vendor/plugins which should be required by Peatio.
17 | # You may set this value to "false" if you don't want Peatio to require the plugin.
18 |
19 | # Example configuration:
20 | #- name: peatio-plugin-example
21 | # git: https://github.com/rubykube/peatio-plugin-example.git
22 | # commit: 11edd2e7c0bef229516f42fde79615a68a008d45
23 |
--------------------------------------------------------------------------------
/config/peatio/seed/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openware/opendax/e204b565e6879bf5afcd3450a93e5d226262d6a6/config/peatio/seed/.gitkeep
--------------------------------------------------------------------------------
/config/secrets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openware/opendax/e204b565e6879bf5afcd3450a93e5d226262d6a6/config/secrets/.gitkeep
--------------------------------------------------------------------------------
/config/utils.yml:
--------------------------------------------------------------------------------
1 | images:
2 | applogic: rubykube/applogic:latest
3 | arke: quay.io/openware/arke:2.6.0-bccb72c
4 | superset: amancevice/superset:0.28.1
5 | superset:
6 | email: superset-admin@openware.com
7 | username: admin
8 | password: changeme
9 | arke:
10 | log_level: INFO
11 | accounts:
12 | - id: 1
13 | driver: bitfaker
14 | debug: false
15 | host: "http://www.app.local"
16 | ws: "ws://www.app.local"
17 | key: ""
18 | secret: ""
19 | delay: 1
20 |
21 | - id: 2
22 | driver: bitfaker
23 | host: "api.binance.com"
24 | key:
25 | secret:
26 | delay: 1
27 |
28 | strategies:
29 | - id: 1
30 | type: copy
31 | debug: true
32 | enabled: true
33 | period: 10
34 | params:
35 | spread_bids: 0.003
36 | spread_asks: 0.003
37 | limit_asks_base: 0.05
38 | limit_bids_base: 0.05
39 | levels_size: 0.25
40 | levels_count: 10
41 | side: both
42 | enable_orderback: false
43 | target:
44 | account_id: 1
45 | market:
46 | id: BTCUSD
47 | base: btc
48 | quote: usd
49 | base_precision: 2
50 | quote_precision: 2
51 | min_ask_amount: 1.5
52 | min_bid_amount: 1.5
53 | sources:
54 | - account_id: 2
55 | market:
56 | id: BTCUSD
57 | base: BTC
58 | quote: USD
59 | base_precision: 8
60 | quote_precision: 8
61 | min_order_back_amount: 1.5
62 |
63 | - id: 2
64 | type: microtrades
65 | debug: true
66 | period: 5
67 | period_random_delay: 10
68 | params:
69 | linked_strategy_id: 1
70 | min_amount: 0.05
71 | max_amount: 10
72 | min_price: 100
73 | max_price: 1000
74 | target:
75 | account_id: 1
76 | market:
77 | id: BTCUSD
78 | base: btc
79 | quote: usd
80 | base_precision: 2
81 | quote_precision: 2
82 | min_ask_amount: 1.5
83 | min_bid_amount: 1.5
84 | strategy:
85 | type: copy
86 | volume_ratio: 0.1
87 | target:
88 | driver: rubykube
89 | market: 'FTHUSD'
90 | host: "http://www.app.local"
91 | key: ""
92 | secret: ""
93 | rate_limit: 1
94 | sources:
95 | - driver: bitfaker
96 | market: 'tETHUSD'
97 | host: "api.bitfinex.com"
98 | key: ""
99 | secret: ""
100 | rate_limit: 0.2
101 | - driver: bitfinex
102 | market: 'tETHUSD'
103 | host: "api.bitfinex.com"
104 | key: ""
105 | secret: ""
106 | rate_limit: 0.2
107 | - driver: binance
108 | market: 'ETHUSDT'
109 | host: "api.binance.com"
110 | key: ""
111 | secret: ""
112 | rate_limit: 0.2
113 |
--------------------------------------------------------------------------------
/data/parity/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openware/opendax/e204b565e6879bf5afcd3450a93e5d226262d6a6/data/parity/.gitkeep
--------------------------------------------------------------------------------
/docs/aws-install.md:
--------------------------------------------------------------------------------
1 | # AWS Installation Guide
2 |
3 | ## Step 1: Prepare the infrastructure
4 |
5 | Infrastructural requirements for the installation are:
6 |
7 | - An EC2 m5.xlarge **Debian** instance with a 200 GB disk storage
8 | - An Elastic Container Registry repository with the baseapp image
9 | - A DNS record to point to the machine(e.g. `example.domain.com`)
10 |
11 | Create these resources before starting the installation and provision them with your RSA key to be able to connect to the VM instance using SSH.
12 |
13 | ## Step 2: Configure the instance
14 |
15 | Connect to the instance over SSH as a `root`/`admin` user and perform the following steps.
16 |
17 | ### Core dependencies
18 |
19 | ```bash
20 | apt-get update
21 | apt-get install -y -q git tmux gnupg2 dirmngr dbus htop curl libmariadbclient-dev-compat build-essential
22 | ```
23 |
24 | ### Docker installation
25 |
26 | ```bash
27 | curl -fsSL https://get.docker.com/ | bash
28 | usermod -a -G docker $USER
29 |
30 | COMPOSE_VERSION="1.23.2"
31 | COMPOSE_URL="https://github.com/docker/compose/releases/download/$COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)"
32 |
33 | curl -L "$COMPOSE_URL" -o /usr/local/bin/docker-compose
34 | chmod +x /usr/local/bin/docker-compose
35 | ```
36 |
37 | ### User creation
38 |
39 | ```bash
40 | groupadd app
41 | useradd --create-home --home /home/app --shell /bin/bash \
42 | --gid app --groups docker,sudo app
43 | ```
44 |
45 | ### Ruby installation
46 |
47 | As the `app` user(`sudo su app`), run:
48 |
49 | ```bash
50 | gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
51 | curl -sSL https://get.rvm.io | bash -s stable
52 | source /home/app/.rvm/scripts/rvm
53 | rvm install --quiet-curl 2.6.1
54 | rvm use --default 2.6.1
55 | gem install bundler
56 | ```
57 |
58 | ## Step 3: Prepare the deployment
59 |
60 | Clone the opendax repo to `/home/app`
61 |
62 | ```bash
63 | git clone git@git.openware.com:opendax
64 | ```
65 |
66 | `cd` into the `opendax` directory and prepare `config/app.yml` according to the [README](../README.md).
67 |
68 | When the configuration is ready, run
69 |
70 | ```bash
71 | bundle install
72 | rake render:config
73 | rake parity:import && \
74 | until rake wallet:create['deposit','http://0.0.0.0:8545','changeme']; do sleep 15; done && \
75 | rake wallet:create['hot','http://0.0.0.0:8545','changeme'] && \
76 | rake wallet:create['warm','http://0.0.0.0:8545','changeme'] && \
77 | rake render:config && \
78 | rake service:all && \
79 | chmod +x bin/install_webhook
80 | ./bin/install_webhook
81 | ```
82 |
83 | After the deployment process is finished, the frontend would be accessible from the domain provided in the configuration.
--------------------------------------------------------------------------------
/docs/images/OpenDAX-authorization.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openware/opendax/e204b565e6879bf5afcd3450a93e5d226262d6a6/docs/images/OpenDAX-authorization.png
--------------------------------------------------------------------------------
/docs/troubleshoot-barong-authz.md:
--------------------------------------------------------------------------------
1 | # Troubleshoot barong authorization process and envoy routing
2 |
3 | ## Architecture overview
4 |
5 | Before establishing a connection to a microservice (for example ***rango***) envoy verifies the authorization by sending a request to ***barong authz***. Barong authz verifies the cookie (when using the UI) and the HMAC signature (when using API) and returns a signed token (JWT) if everything is valid.
6 |
7 | 
8 |
9 |
10 | ## Enable envoy debug logs
11 |
12 | To troubleshoot connection problems with a microservice of the stack, you can enable envoy logs to understand in which step the connection problem appears.
13 |
14 | To do so you need to:
15 |
16 | 1. Edit *templates/compose/gateway.yaml.erb*
17 |
18 | 2. Change *info* by *debug* in the following lines:
19 |
20 | ```yaml
21 | command: /usr/local/bin/envoy -l debug -c /etc/envoy/envoy.yaml
22 | ```
23 |
24 | 3. Render the configuration files
25 |
26 | ```bash
27 | rake render:config
28 | ```
29 |
30 | 4. Restart envoy
31 |
32 | ```bash
33 | docker-compose up -dV gateway
34 | ```
35 |
36 | 5. Finally you can inspect the envoy logs
37 |
38 | ```bash
39 | docker-compose logs -f --tail 100 gateway
40 | ```
41 |
42 | Here are the relevant logs:
43 |
44 | 1. Initial websocket connection
45 | ```log
46 | gateway_1 | [2020-12-02 07:50:30.169][13][debug][http] [source/common/http/conn_manager_impl.cc:580] [C184][S12609685784760114286] request headers complete (end_stream=false):
47 | gateway_1 | ':authority', 'www.app.local'
48 | gateway_1 | ':path', '/api/v2/ranger/private/?stream=global.tickers'
49 | gateway_1 | ':method', 'GET'
50 | gateway_1 | 'user-agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36'
51 | gateway_1 | 'accept-encoding', 'gzip, deflate'
52 | gateway_1 | 'accept-language', 'en-US,en;q=0.9,fr;q=0.8'
53 | gateway_1 | 'cache-control', 'no-cache'
54 | gateway_1 | 'connection', 'Upgrade'
55 | gateway_1 | 'cookie', '_barong_session=4cff598ee40d3d2ec38875ddc904fc46'
56 | gateway_1 | 'origin', 'http://www.app.local'
57 | gateway_1 | 'pragma', 'no-cache'
58 | gateway_1 | 'sec-websocket-key', 'b16LunIyXls4CtNZ1lYWsw=='
59 | gateway_1 | 'sec-websocket-extensions', 'permessage-deflate; client_max_window_bits'
60 | gateway_1 | 'sec-websocket-version', '13'
61 | gateway_1 | 'upgrade', 'websocket'
62 | gateway_1 | 'x-forwarded-for', '172.20.0.1'
63 | gateway_1 | 'x-forwarded-host', 'www.app.local'
64 | gateway_1 | 'x-forwarded-port', '80'
65 | gateway_1 | 'x-forwarded-proto', 'ws'
66 | gateway_1 | 'x-forwarded-server', '41e065adb32e'
67 | gateway_1 | 'x-real-ip', '172.20.0.1'
68 | ```
69 |
70 | 2. Request to Barong authz
71 | ```log
72 | gateway_1 | [2020-12-02 07:50:30.183][13][debug][router] [source/common/router/router.cc:320] [C0][S3254558628791445120] cluster 'barong' match for URL '/api/v2/auth/api/v2/ranger/private/?stream=global.tickers'
73 | gateway_1 | [2020-12-02 07:50:30.184][13][debug][router] [source/common/router/router.cc:381] [C0][S3254558628791445120] router decoding headers:
74 | gateway_1 | ':method', 'GET'
75 | gateway_1 | ':path', '/api/v2/auth/api/v2/ranger/private/?stream=global.tickers'
76 | gateway_1 | ':authority', 'www.app.local'
77 | gateway_1 | ':scheme', 'http'
78 | gateway_1 | 'content-length', '0'
79 | gateway_1 | 'x-forwarded-for', '172.20.0.1,172.20.0.8'
80 | gateway_1 | 'cookie', '_barong_session=4cff598ee40d3d2ec38875ddc904fc46'
81 | gateway_1 | 'user-agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36'
82 | gateway_1 | 'x-forwarded-host', 'www.app.local'
83 | gateway_1 | 'x-forwarded-proto', 'ws'
84 | gateway_1 | 'x-envoy-internal', 'true'
85 | gateway_1 | 'x-envoy-expected-rq-timeout-ms', '1000'
86 | ```
87 |
88 | 3. Routing the connection to rango
89 |
90 | ```log
91 | gateway_1 | [2020-12-02 07:50:30.220][13][debug][filter] [source/extensions/filters/http/ext_authz/ext_authz.cc:175] [C186][S2592169017517480399] ext_authz filter accepted the request
92 | gateway_1 | [2020-12-02 07:50:30.220][13][debug][router] [source/common/router/router.cc:320] [C186][S2592169017517480399] cluster 'rango' match for URL '/api/v2/ranger/private/?stream=global.tickers'
93 | gateway_1 | [2020-12-02 07:50:30.220][13][debug][router] [source/common/router/router.cc:381] [C186][S2592169017517480399] router decoding headers:
94 | gateway_1 | ':authority', 'www.app.local'
95 | gateway_1 | ':path', '/api/v2/ranger/private/?stream=global.tickers'
96 | gateway_1 | ':method', 'GET'
97 | gateway_1 | ':scheme', 'http'
98 | gateway_1 | 'user-agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36'
99 | gateway_1 | 'accept-encoding', 'gzip, deflate'
100 | gateway_1 | 'accept-language', 'en-US,en;q=0.9,fr;q=0.8'
101 | gateway_1 | 'cache-control', 'no-cache'
102 | gateway_1 | 'connection', 'Upgrade'
103 | gateway_1 | 'cookie', '_barong_session=4cff598ee40d3d2ec38875ddc904fc46'
104 | gateway_1 | 'origin', 'http://www.app.local'
105 | gateway_1 | 'pragma', 'no-cache'
106 | gateway_1 | 'sec-websocket-key', 'tocGzAPK8TACk8zzRX7n3g=='
107 | gateway_1 | 'sec-websocket-extensions', 'permessage-deflate; client_max_window_bits'
108 | gateway_1 | 'sec-websocket-version', '13'
109 | gateway_1 | 'upgrade', 'websocket'
110 | gateway_1 | 'x-forwarded-for', '172.20.0.1'
111 | gateway_1 | 'x-forwarded-host', 'www.app.local'
112 | gateway_1 | 'x-forwarded-port', '80'
113 | gateway_1 | 'x-forwarded-proto', 'ws'
114 | gateway_1 | 'x-forwarded-server', '41e065adb32e'
115 | gateway_1 | 'x-real-ip', '172.20.0.1'
116 | gateway_1 | 'content-length', '0'
117 | gateway_1 | 'x-envoy-internal', 'true'
118 | gateway_1 | 'x-request-id', '5b87e64a-4155-498e-916c-b8b998725a71'
119 | gateway_1 | 'x-envoy-expected-rq-timeout-ms', '15000'
120 | gateway_1 | ':status', '200'
121 | gateway_1 | 'authorization', 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE2MDY4OTU0MzAsImV4cCI6MTYwNjg5OTAzMCwic3ViIjoic2Vzc2lvbiIsImlzcyI6ImJhcm9uZyIsImF1ZCI6WyJwZWF0aW8iLCJiYXJvbmciXSwianRpIjoiNTllNGIwNTA3YTgyMGNjMzYzMTIiLCJ1aWQiOiJJRDVGRkE5OERDMjciLCJlbWFpbCI6ImFkbWluQGJhcm9uZy5pbyIsInJvbGUiOiJhZG1pbiIsImxldmVsIjozLCJzdGF0ZSI6ImFjdGl2ZSIsInJlZmVycmFsX2lkIjpudWxsfQ.Br6-yujI5MgU_BktVDYNaEPNtHOMxQZbNS89deQfxNiPPkx6B8ZUDXL9og5DQ6nWBExlHydyPPcCSUvO5BCth_UWiuttY_ldy7TIr_JrXT0td8WN8fq8QadOWFuJ7wvMEklRGVKQmvOrooHNKz_WwcY4xmaSO3SVgQdFSkmt626MOXmo9Wa3nYsL6EafCMe--9PHWop4L-B1w5ndvbGuGLbJaqEktXsudOX0A9Js2sKuHPxSe8QJKN5XwmOFPAWM28-VkaU5cmshMK2CwJaSRhVoL0gIi9VUGpFVVJ1ciD0VHjRfxuFTzph7utRuO_M9N-bweLL8YCCA8RkwlVyuLg'
122 | gateway_1 | 'content-type', 'text/html; charset=utf-8'
123 | gateway_1 | 'cache-control', 'no-cache'
124 | gateway_1 | 'set-cookie', '_barong_session=4cff598ee40d3d2ec38875ddc904fc46; path=/; expires=Thu, 03 Dec 2020 07:50:30 GMT; HttpOnly'
125 | gateway_1 | 'x-request-id', '8ff80928-9091-40b0-b6f0-c0b46f8d72fe'
126 | gateway_1 | 'x-runtime', '0.031033'
127 | gateway_1 | 'vary', 'Origin'
128 | gateway_1 | 'transfer-encoding', 'chunked'
129 | gateway_1 | 'x-envoy-upstream-service-time', '37'
130 | ```
131 |
132 |
133 | ## Authz configuration
134 |
135 | In case of authorization problem check the following configuration files:
136 |
137 | 1. *config/barong/authz_rules.yml*
138 | This file contains the default public endpoints and blocked endpoints.
139 | If you have a problem accessing a public endpoint make sure the URL is present in the *rules.pass* section.
140 |
141 | 2. *templates/config/barong/seeds.yml.erb*
142 | Check the *permissions* section to make sure the role of the user is allowed to access the resource.
143 |
144 | Run the following command to apply the changes:
145 |
146 | ```bash
147 | rake service:setup
148 | ```
149 |
--------------------------------------------------------------------------------
/docs/ubuntu-install.md:
--------------------------------------------------------------------------------
1 | # Install OpenDax in Ubuntu 18.04
2 |
3 | ## Step 1: Install Docker
4 |
5 | To install Docker you will need to do those steps with `sudo` or login as root user with `sudo -i`
6 |
7 | Create a Unix user for holding your application
8 | ```
9 | groupadd app
10 | useradd -d /home/app -s `which bash` -g app -m app
11 | ```
12 |
13 | ### Installing from apt-get
14 |
15 | First, update your existing list of packages:
16 |
17 | ```
18 | apt update
19 | ```
20 |
21 | Next, install a few prerequisite packages which let apt use packages over HTTPS:
22 |
23 | ```
24 | apt install apt-transport-https ca-certificates curl software-properties-common
25 | ```
26 |
27 | Then add the GPG key for the official Docker repository to your system:
28 |
29 | ```
30 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
31 | ```
32 |
33 | Add the Docker repository to APT sources:
34 |
35 | ```
36 | add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
37 | ```
38 |
39 | Next, update the package database with the Docker packages from the newly added repo:
40 |
41 | ```
42 | apt update
43 | ```
44 |
45 | Make sure you are about to install from the Docker repo instead of the default Ubuntu repo:
46 |
47 | Finally, install Docker:
48 |
49 | ```
50 | apt install docker-ce
51 | ```
52 |
53 | Docker should now be installed, the daemon started, and the process enabled to start on boot. Check that it's running:
54 |
55 | ```
56 | systemctl status docker
57 | ```
58 |
59 | Add your app user into the docker group
60 |
61 | ```
62 | usermod -aG docker app
63 | ```
64 |
65 | ## Step 2: Install Docker Compose
66 |
67 | Run this command to download the latest version of Docker Compose:
68 |
69 | ```
70 | curl -L "https://github.com/docker/compose/releases/download/1.23.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
71 |
72 | chmod +x /usr/local/bin/docker-compose
73 | ```
74 |
75 | ## Step 3: Clone OpenDax
76 |
77 | Login to your app user:
78 | ```
79 | su - app
80 | ```
81 |
82 | Clone opendax repository
83 | ```
84 | cd $HOME
85 | git clone https://github.com/rubykube/opendax.git
86 | cd opendax
87 | ```
88 |
89 | ## Step 4: Clone your frontend
90 |
91 | Edit config file `config/app.yml`
92 |
--------------------------------------------------------------------------------
/lib/opendax/payload.rb:
--------------------------------------------------------------------------------
1 | require 'jwt'
2 |
3 | module Opendax
4 |
5 | class Error < StandardError
6 | end
7 |
8 | class Payload
9 | def initialize(params)
10 | @secret = params[:secret]
11 | @expire = params[:expire] || 600
12 |
13 | raise Opendax::Error.new unless @secret
14 | raise Opendax::Error.new unless @expire > 0
15 | end
16 |
17 | def generate!(params)
18 | raise Opendax::Error.new unless params[:service]
19 | raise Opendax::Error.new unless params[:image]
20 |
21 | token = params.merge({
22 | 'iat': Time.now.to_i,
23 | 'exp': (Time.now + @expire).to_i
24 | })
25 |
26 | JWT.encode token, @secret, 'HS256'
27 | end
28 |
29 | def decode!(token)
30 | JWT.decode(token, @secret, true, {
31 | algorithm: 'HS256'
32 | }).first
33 | end
34 |
35 | def safe_decode(token)
36 | begin
37 | decode!(token)
38 | rescue JWT::ExpiredSignature
39 | rescue JWT::ImmatureSignature
40 | rescue JWT::VerificationError
41 | rescue JWT::DecodeError
42 | nil
43 | end
44 | end
45 | end
46 | end
47 |
--------------------------------------------------------------------------------
/lib/opendax/renderer.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'openssl'
4 | require 'sshkey'
5 | require 'pathname'
6 | require 'yaml'
7 | require 'base64'
8 | require 'fileutils'
9 |
10 | module Opendax
11 | # Renderer is class for rendering Opendax templates.
12 | class Renderer
13 | TEMPLATE_PATH = Pathname.new('./templates')
14 |
15 | BARONG_KEY = 'config/secrets/barong.key'
16 | APPLOGIC_KEY = 'config/secrets/applogic.key'
17 | SSH_KEY = 'config/secrets/app.key'
18 |
19 | def render
20 | @config ||= config
21 | @utils ||= utils
22 | @name ||= @config['app']['name'].downcase
23 | @barong_key ||= OpenSSL::PKey::RSA.new(File.read(BARONG_KEY), '')
24 | @applogic_key ||= OpenSSL::PKey::RSA.new(File.read(APPLOGIC_KEY), '')
25 | @barong_private_key ||= Base64.urlsafe_encode64(@barong_key.to_pem)
26 | @barong_public_key ||= Base64.urlsafe_encode64(@barong_key.public_key.to_pem)
27 | @applogic_private_key ||= Base64.urlsafe_encode64(@applogic_key.to_pem)
28 | @applogic_public_key ||= Base64.urlsafe_encode64(@applogic_key.public_key.to_pem)
29 |
30 | Dir.glob("#{TEMPLATE_PATH}/**/*.erb", File::FNM_DOTMATCH).each do |file|
31 | output_file = template_name(file)
32 | FileUtils.chmod 0o644, output_file if File.exist?(output_file)
33 | render_file(file, output_file)
34 | FileUtils.chmod 0o444, output_file if @config['render_protect']
35 | end
36 | end
37 |
38 | def render_file(file, out_file)
39 | puts "Rendering #{out_file}"
40 | result = ERB.new(File.read(file), trim_mode: '-').result(binding)
41 | dir = File.dirname(out_file)
42 | FileUtils.mkdir(dir) unless Dir.exist?(dir)
43 | File.write(out_file, result)
44 | end
45 |
46 | def ssl_helper(arg)
47 | @config['ssl']['enabled'] ? arg << 's' : arg
48 | end
49 |
50 | def template_name(file)
51 | path = Pathname.new(file)
52 | out_path = path.relative_path_from(TEMPLATE_PATH).sub('.erb', '')
53 |
54 | File.join('.', out_path)
55 | end
56 |
57 | def render_keys
58 | generate_key(BARONG_KEY)
59 | generate_key(APPLOGIC_KEY)
60 | generate_key(SSH_KEY, public: true)
61 | end
62 |
63 | def generate_key(filename, public: false)
64 | return if File.file?(filename)
65 |
66 | key = SSHKey.generate(type: 'RSA', bits: 2048)
67 | File.write(filename, key.private_key)
68 | File.write("#{filename}.pub", key.ssh_public_key) if public
69 | end
70 |
71 | def config
72 | YAML.load_file('./config/app.yml')
73 | end
74 |
75 | def utils
76 | YAML.load_file('./config/utils.yml')
77 | end
78 | end
79 | end
80 |
--------------------------------------------------------------------------------
/lib/opendax/vault.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module Opendax
4 | class Vault
5 | POLICIES_NAMES = ["barong", "finex_engine", "peatio_rails", "peatio_crypto", "peatio_upstream", "peatio_matching"]
6 |
7 | def vault_secrets_path
8 | 'config/vault-secrets.yml'
9 | end
10 |
11 | def vault_exec(command)
12 | `docker-compose exec -T vault sh -c '#{command}'`
13 | end
14 |
15 | def secrets(command, endpoints, options = '')
16 | endpoints.each { |endpoint| vault_exec("vault secrets #{command} #{options} #{endpoint}") }
17 | end
18 |
19 | def setup
20 | puts '----- Checking Vault status -----'
21 | vault_status = YAML.safe_load(vault_exec('vault status -format yaml'))
22 |
23 | return if vault_status.nil?
24 |
25 | if vault_status['initialized']
26 | puts '----- Vault is initialized -----'
27 | begin
28 | vault_secrets = YAML.safe_load(File.read(vault_secrets_path))
29 | rescue SystemCallError => e
30 | puts 'Vault keys are missing'
31 | return
32 | end
33 | vault_root_token = vault_secrets['root_token']
34 | unseal_keys = vault_secrets['unseal_keys_b64'][0, 3]
35 | else
36 | puts '----- Initializing Vault -----'
37 | vault_init_output = YAML.safe_load(vault_exec('vault operator init -format yaml --recovery-shares=3 --recovery-threshold=2'))
38 | File.write(vault_secrets_path, YAML.dump(vault_init_output))
39 | vault_root_token = vault_init_output['root_token']
40 | unseal_keys = vault_init_output['unseal_keys_b64'][0, 3]
41 | end
42 |
43 | if vault_status['sealed']
44 | puts '----- Unsealing Vault -----'
45 | unseal_keys.each { |key| vault_exec("vault operator unseal #{key}") }
46 | else
47 | puts '----- Vault is unsealed -----'
48 | end
49 |
50 | return vault_root_token if vault_status['initialized']
51 |
52 | puts '----- Vault login -----'
53 | vault_exec("vault login #{vault_root_token}")
54 |
55 | puts '----- Configuring the endpoints -----'
56 | secrets('enable', %w[totp transit])
57 | secrets('disable', ['secret'])
58 | secrets('enable', ['kv'], '-path=secret -version=1')
59 | vault_root_token
60 | end
61 |
62 | def load_policies(deployment_name, vault_root_token)
63 | puts '----- Vault login -----'
64 | vault_exec("vault login #{vault_root_token}")
65 |
66 | tokens = {}
67 | POLICIES_NAMES.each do |policy|
68 | name = "#{deployment_name.downcase}_#{policy}"
69 |
70 | puts "Loading #{name} policy..."
71 | vault_exec("vault policy write #{name} /tmp/policies/#{policy}.hcl")
72 |
73 | puts "Creating the #{name} token..."
74 | vault_token_create_output = YAML.safe_load(vault_exec("vault token create -policy=#{name} -renewable=true -ttl=240h -period=240h -format=yaml"))
75 | tokens["#{policy}_token"] = vault_token_create_output["auth"]["client_token"]
76 | end
77 |
78 | tokens
79 | end
80 | end
81 | end
82 |
--------------------------------------------------------------------------------
/lib/opendax/webhook.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | require 'json'
3 | require 'yaml'
4 |
5 | require_relative 'payload'
6 | require_relative 'renderer'
7 |
8 | class Webhook < Sinatra::Base
9 | CONFIG_PATH = 'config/app.yml'.freeze
10 |
11 | set :show_exceptions, false
12 |
13 | def initialize
14 | super
15 | @services = %w[barong peatio frontend tower applogic finex-engine finex-api]
16 | secret = ENV['WEBHOOK_JWT_SECRET']
17 | raise 'WEBHOOK_JWT_SECRET is not set' if secret.to_s.empty?
18 | @decoder = Opendax::Payload.new(secret: secret)
19 | end
20 |
21 | def update_config(service, image)
22 | config = YAML.load_file(CONFIG_PATH)
23 | config["images"][service] = image
24 | File.open(CONFIG_PATH, 'w') {|f| f.write config.to_yaml }
25 | end
26 |
27 | before do
28 | content_type 'application/json'
29 | end
30 |
31 | get '/deploy/ping' do
32 | 'pong'
33 | end
34 |
35 | get '/deploy/:token' do |token|
36 | decoded = @decoder.safe_decode(token)
37 | return answer(400, 'invalid token') unless decoded
38 |
39 | service = decoded['service']
40 | image = decoded['image']
41 |
42 | return answer(400, 'service is not specified') unless service
43 | return answer(400, 'image is not specified') unless image
44 | return answer(404, 'unknown service') unless @services.include? service
45 | return answer(400, 'invalid image') if (%r(^(([-_\w\.]){,20}(\/|:))+([-\w\.]{,20})$) =~ image) == nil
46 |
47 | system "docker image pull #{image}"
48 |
49 | unless $?.success?
50 | system("docker image inspect #{image} > /dev/null")
51 | return answer(404, 'invalid image') unless $?.success?
52 | end
53 |
54 | if $?.success?
55 | update_config(service, image)
56 |
57 | renderer = Opendax::Renderer.new
58 | renderer.render
59 |
60 | system "docker-compose up -Vd #{service}"
61 | end
62 |
63 | return answer(500, 'could not restart container') unless $?.success?
64 | return answer(200, "service #{service} updated with image #{image}")
65 | end
66 |
67 | def answer(response_status, message)
68 | status response_status
69 |
70 | {
71 | message: message
72 | }.to_json
73 | end
74 | end
75 |
--------------------------------------------------------------------------------
/lib/tasks/db.rake:
--------------------------------------------------------------------------------
1 | namespace :db do
2 |
3 | def mysql_cli
4 | return "mysql -u root -h db -P 3306 -pchangeme"
5 | end
6 |
7 | desc 'Create database'
8 | task :create do
9 | sh 'docker-compose run --rm peatio bundle exec rake db:create'
10 | sh 'docker-compose run --rm barong bundle exec rake db:create'
11 | end
12 |
13 | desc 'Load database dump'
14 | task :load => :create do
15 | sh %Q{cat data/mysql/peatio_production.sql | docker-compose run --rm db #{mysql_cli} peatio_production}
16 | sh %Q{cat data/mysql/barong_production.sql | docker-compose run --rm db #{mysql_cli} barong_production}
17 | sh 'docker-compose run --rm peatio bundle exec rake db:migrate'
18 | sh 'docker-compose run --rm barong bundle exec rake db:migrate'
19 | end
20 |
21 | desc 'Drop all databases'
22 | task :drop do
23 | sh %q(docker-compose run --rm db /bin/sh -c "mysql -u root -h db -P 3306 -pchangeme -e 'DROP DATABASE peatio_production'")
24 | sh %q(docker-compose run --rm db /bin/sh -c "mysql -u root -h db -P 3306 -pchangeme -e 'DROP DATABASE barong_production'")
25 | sh %q(docker-compose run --rm db /bin/sh -c "mysql -u root -h db -P 3306 -pchangeme -e 'DROP DATABASE superset'")
26 | end
27 |
28 | desc 'Database Console'
29 | task :console do
30 | sh "docker-compose run --rm db #{mysql_cli}"
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/lib/tasks/docker.rake:
--------------------------------------------------------------------------------
1 | namespace :docker do
2 | desc 'Stop all runnning docker contrainers'
3 | task :down do
4 | sh 'docker-compose down'
5 | end
6 |
7 | desc 'Clean up all docker volumes'
8 | task :clean do
9 | sh 'docker volume prune -f'
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/tasks/payload.rake:
--------------------------------------------------------------------------------
1 | require_relative '../opendax/payload'
2 | require 'faraday'
3 |
4 | namespace :payload do
5 | desc 'Generate JWT'
6 | task :send, [:service, :image, :url] do |_, args|
7 | secret = ENV['WEBHOOK_JWT_SECRET']
8 | abort 'WEBHOOK_JWT_SECRET not set' if secret.to_s.empty?
9 | coder = Opendax::Payload.new(secret: secret)
10 | jwt = coder.generate!(service: args.service, image: args.image)
11 | url = "#{args.url}/deploy/#{jwt}"
12 | response = Faraday::Connection.new.get(url) do |request|
13 | request.options.timeout = 300
14 | end
15 | pp response.body
16 | fail unless response.status == 200
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/tasks/render.rake:
--------------------------------------------------------------------------------
1 |
2 | require_relative '../opendax/renderer'
3 |
4 | namespace :render do
5 | desc 'Render configuration and compose files and keys'
6 | task :config do
7 | renderer = Opendax::Renderer.new
8 | renderer.render_keys
9 | renderer.render
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/tasks/service.rake:
--------------------------------------------------------------------------------
1 | namespace :service do
2 | ENV['APP_DOMAIN'] = @config['app']['domain']
3 |
4 | @switch = Proc.new do |args, start, stop|
5 | case args.command
6 | when 'start'
7 | start.call
8 | when 'stop'
9 | stop.call
10 | when 'restart'
11 | stop.call
12 | start.call
13 | else
14 | puts "unknown command #{args.command}"
15 | end
16 | end
17 |
18 | desc 'Run Traefik (reverse-proxy)'
19 | task :proxy, [:command] do |task, args|
20 | args.with_defaults(:command => 'start')
21 |
22 | def start
23 | puts '----- Starting the proxy -----'
24 | File.new('config/acme.json', File::CREAT, 0600) unless File.exist? 'config/acme.json'
25 | sh 'docker-compose up -d proxy'
26 | end
27 |
28 | def stop
29 | puts '----- Stopping the proxy -----'
30 | sh 'docker-compose rm -fs proxy'
31 | end
32 |
33 | @switch.call(args, method(:start), method(:stop))
34 | end
35 |
36 | desc 'Run backend (vault db redis rabbitmq)'
37 | task :backend, [:command] do |task, args|
38 | args.with_defaults(:command => 'start')
39 |
40 | def start
41 | puts '----- Starting dependencies -----'
42 | sh 'docker-compose up -d vault db redis rabbitmq'
43 | sleep 7 # time for db to start, we can get connection refused without sleeping
44 | end
45 |
46 | def stop
47 | puts '----- Stopping dependencies -----'
48 | sh 'docker-compose rm -fs vault db redis rabbitmq'
49 | end
50 |
51 |
52 | @switch.call(args, method(:start), method(:stop))
53 | end
54 |
55 | desc 'Run influxdb'
56 | task :influxdb, [:command] do |task, args|
57 | args.with_defaults(:command => 'start')
58 |
59 | def start
60 | puts '----- Starting influxdb -----'
61 | sh 'docker-compose up -d influxdb'
62 | sh 'docker-compose exec influxdb bash -c "cat peatio.sql | influx"'
63 | end
64 |
65 | def stop
66 | puts '----- Stopping influxdb -----'
67 | sh 'docker-compose rm -fs influxdb'
68 | end
69 |
70 | @switch.call(args, method(:start), method(:stop))
71 | end
72 |
73 | desc '[Optional] Run arke-maker'
74 | task :arke_maker, [:command] do |task, args|
75 | args.with_defaults(:command => 'start')
76 |
77 | def start
78 | puts '----- Starting arke -----'
79 | sh 'docker-compose up -d arke-maker'
80 | end
81 |
82 | def stop
83 | puts '----- Stopping arke -----'
84 | sh 'docker-compose rm -fs arke-maker'
85 | end
86 |
87 | @switch.call(args, method(:start), method(:stop))
88 | end
89 |
90 | desc '[Optional] Run daemons (rango, peatio daemons, barong sidekiq)'
91 | task :daemons, [:command] do |_task, args|
92 | @daemons = %w[rango blockchain cron_job upstream deposit deposit_coin_address withdraw_coin influx_writer barong_sidekiq]
93 |
94 | if @config['finex']['enabled']
95 | @daemons |= %w[finex-engine finex-api]
96 | else
97 | @daemons |= %w[matching order_processor trade_executor]
98 | end
99 |
100 | args.with_defaults(:command => 'start')
101 |
102 | def start
103 | puts '----- Starting daemons -----'
104 | sh "docker-compose up -d #{@daemons.join(' ')}"
105 | end
106 |
107 | def stop
108 | puts '----- Stopping daemons -----'
109 | sh "docker-compose rm -fs #{@daemons.join(' ')}"
110 | end
111 |
112 | @switch.call(args, method(:start), method(:stop))
113 | end
114 |
115 | desc '[Optional] Run cryptonodes'
116 | task :cryptonodes, [:command] do |task, args|
117 | args.with_defaults(:command => 'start')
118 |
119 | def start
120 | puts '----- Starting cryptonodes -----'
121 | sh 'docker-compose up -d parity'
122 | if @config['bitcoind']['enabled']
123 | sh 'docker-compose up -d bitcoind'
124 | end
125 | end
126 |
127 | def stop
128 | puts '----- Stopping cryptonodes -----'
129 | sh 'docker-compose rm -fs parity'
130 | if @config['bitcoind']['enabled']
131 | sh 'docker-compose rm -fs bitcoind'
132 | end
133 | end
134 |
135 | @switch.call(args, method(:start), method(:stop))
136 | end
137 |
138 | desc 'Run setup hooks for peatio, barong'
139 | task :setup, [:command] => ['vault:setup', 'vault:load_policies'] do |task, args|
140 | if args.command != 'stop'
141 | Rake::Task["render:config"].execute
142 | puts '----- Running hooks -----'
143 | sh 'docker-compose run --rm peatio bash -c "./bin/link_config && bundle exec rake db:create db:migrate"'
144 | sh 'docker-compose run --rm peatio bash -c "./bin/link_config && bundle exec rake db:seed"'
145 | sh 'docker-compose run --rm barong bash -c "./bin/init_config && bundle exec rake db:create db:migrate"'
146 | sh 'docker-compose run --rm barong bash -c "./bin/link_config && bundle exec rake db:seed"'
147 | end
148 | end
149 |
150 | desc 'Run mikro app (barong, peatio)'
151 | task :app, [:command] => [:backend, :setup] do |task, args|
152 | args.with_defaults(:command => 'start')
153 |
154 | def start
155 | puts '----- Starting app -----'
156 | sh 'docker-compose up -d peatio barong gateway'
157 | end
158 |
159 | def stop
160 | puts '----- Stopping app -----'
161 | sh 'docker-compose rm -fs peatio barong gateway'
162 | end
163 |
164 | @switch.call(args, method(:start), method(:stop))
165 | end
166 |
167 | desc 'Run the frontend application'
168 | task :frontend, [:command] do |task, args|
169 | args.with_defaults(:command => 'start')
170 |
171 | def start
172 | puts '----- Starting the frontend -----'
173 | sh 'docker-compose up -d frontend'
174 | end
175 |
176 | def stop
177 | puts '----- Stopping the frontend -----'
178 | sh 'docker-compose rm -fs frontend'
179 | end
180 |
181 | @switch.call(args, method(:start), method(:stop))
182 | end
183 |
184 | desc 'Run the tower application'
185 | task :tower, [:command] do |task, args|
186 | args.with_defaults(:command => 'start')
187 |
188 | def start
189 | puts '----- Starting the tower -----'
190 | sh 'docker-compose up -d tower'
191 | end
192 |
193 | def stop
194 | puts '----- Stopping the tower -----'
195 | sh 'docker-compose rm -fs tower'
196 | end
197 |
198 | @switch.call(args, method(:start), method(:stop))
199 | end
200 |
201 | desc '[Optional] Run utils (mailer)'
202 | task :utils, [:command] do |task, args|
203 | args.with_defaults(:command => 'start')
204 |
205 | def start
206 | puts '----- Starting utils -----'
207 | sh 'docker-compose up -d mailer'
208 | end
209 |
210 | def stop
211 | puts '----- Stopping Utils -----'
212 | sh 'docker-compose rm -fs mailer'
213 | end
214 |
215 | @switch.call(args, method(:start), method(:stop))
216 | end
217 |
218 | desc '[Optional] Run monitoring'
219 | task :monitoring, [:command] do |task, args|
220 | args.with_defaults(:command => 'start')
221 |
222 | def start
223 | puts '----- Starting monitoring -----'
224 | sh 'docker-compose up -d node_exporter'
225 | sh 'docker-compose up -d cadvisor'
226 | end
227 |
228 | def stop
229 | puts '----- Stopping monitoring -----'
230 | sh 'docker-compose rm -fs node_exporter'
231 | sh 'docker-compose rm -fs cadvisor'
232 | end
233 |
234 | @switch.call(args, method(:start), method(:stop))
235 | end
236 |
237 | desc '[Optional] Run superset'
238 | task :superset, [:command] do |task, args|
239 | args.with_defaults(:command => 'start')
240 |
241 | def start
242 | conf = @utils['superset']
243 | init_params = [
244 | '--app', 'superset',
245 | '--firstname', 'Admin',
246 | '--lastname', 'Superset',
247 | '--username', conf['username'],
248 | '--email', conf['email'],
249 | '--password', conf['password']
250 | ].join(' ')
251 |
252 | puts '----- Initializing Superset -----'
253 | sh [
254 | 'docker-compose run --rm superset',
255 | 'sh -c "',
256 | "fabmanager create-admin #{init_params}",
257 | '&& superset db upgrade',
258 | '&& superset init"'
259 | ].join(' ')
260 |
261 | puts '----- Starting Superset -----'
262 | sh 'docker-compose up -d superset'
263 | end
264 |
265 | def stop
266 | puts '----- Stopping Superset -----'
267 | sh 'docker-compose rm -fs superset'
268 | end
269 |
270 | @switch.call(args, method(:start), method(:stop))
271 | end
272 | desc 'Set up and start all services with dependencies (does not run optional ones)'
273 | task :all, [:command] => ['versions:update', 'render:config'] do |task, args|
274 | args.with_defaults(:command => 'start')
275 |
276 | def start
277 | Rake::Task["service:proxy"].invoke('start')
278 | Rake::Task["service:backend"].invoke('start')
279 | Rake::Task["service:influxdb"].invoke('start')
280 | puts 'Wait 5 second for backend'
281 | sleep(5)
282 | Rake::Task["service:setup"].invoke('start')
283 | Rake::Task["service:app"].invoke('start')
284 | Rake::Task["service:frontend"].invoke('start')
285 | Rake::Task["service:tower"].invoke('start')
286 | Rake::Task["service:utils"].invoke('start')
287 | Rake::Task["service:daemons"].invoke('start')
288 | end
289 |
290 | def stop
291 | Rake::Task["service:proxy"].invoke('stop')
292 | Rake::Task["service:backend"].invoke('stop')
293 | Rake::Task["service:influxdb"].invoke('stop')
294 | Rake::Task["service:setup"].invoke('stop')
295 | Rake::Task["service:app"].invoke('stop')
296 | Rake::Task["service:frontend"].invoke('stop')
297 | Rake::Task["service:tower"].invoke('stop')
298 | Rake::Task["service:utils"].invoke('stop')
299 | Rake::Task["service:daemons"].invoke('stop')
300 | end
301 |
302 | @switch.call(args, method(:start), method(:stop))
303 | end
304 | end
305 |
--------------------------------------------------------------------------------
/lib/tasks/terraform.rake:
--------------------------------------------------------------------------------
1 | namespace :terraform do
2 | desc 'Initialize the Terraform configuration'
3 | task :init do
4 | Dir.chdir('terraform') { sh 'terraform init' }
5 | end
6 |
7 | desc 'Apply the Terraform configuration'
8 | task :apply => ['render:config', :init] do
9 | Dir.chdir('terraform') { sh 'terraform apply' }
10 | end
11 |
12 | desc 'Destroy the Terraform infrastructure'
13 | task :destroy do
14 | Dir.chdir('terraform') { sh 'terraform destroy' }
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/lib/tasks/toolbox.rake:
--------------------------------------------------------------------------------
1 | namespace :toolbox do
2 | desc 'Run the toolbox'
3 | task :run do
4 | run_cmd = %w[docker-compose run --rm toolbox run]
5 |
6 | YAML.safe_load(File.read('config/toolbox.yaml'))
7 | .transform_keys { |k| '--' << k }
8 | .each_pair { |k, v| run_cmd << k << v.to_s }
9 |
10 | sh *run_cmd
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/lib/tasks/vault.rake:
--------------------------------------------------------------------------------
1 |
2 | require_relative '../opendax/vault'
3 |
4 | namespace :vault do
5 | desc 'Initialize, unseal and set secrets for Vault'
6 | task :setup do
7 | vault = Opendax::Vault.new
8 | vault_root_token = vault.setup
9 | unless vault_root_token.nil?
10 | @config["vault"]["root_token"] = vault_root_token
11 | File.open(CONFIG_PATH, 'w') { |f| YAML.dump(@config, f) }
12 | end
13 | end
14 |
15 | task :load_policies do
16 | vault = Opendax::Vault.new
17 | vault_tokens = vault.load_policies(@config["app"]["name"], @config["vault"]["root_token"])
18 | unless vault_tokens.empty?
19 | vault_tokens.each do |k, v|
20 | @config["vault"][k] = v
21 | File.open(CONFIG_PATH, 'w') { |f| YAML.dump(@config, f) }
22 | end
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/tasks/vendor.rake:
--------------------------------------------------------------------------------
1 | namespace :vendor do
2 | desc 'Clone the frontend apps repos into vendor/'
3 | task :clone do
4 | puts '----- Clone the frontend apps repos -----'
5 | puts
6 | @config['vendor'].each do |name, repo_url|
7 | sh "git clone #{repo_url} vendor/#{name}"
8 | puts
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/tasks/versions.rake:
--------------------------------------------------------------------------------
1 | require 'faraday'
2 |
3 | namespace :versions do
4 | desc 'Fetch global image versions and update config/app.yaml'
5 | task :update do
6 | unless @config['updateVersions']
7 | puts "To enable version updates, set updateVersions to true"
8 | next
9 | end
10 |
11 | puts "Fetching latest global versions"
12 | response = Faraday.get 'https://raw.githubusercontent.com/openware/versions/master/opendax/2-6/versions.yaml'
13 |
14 | if response.status >= 400 || response.status >= 500
15 | raise "Error fetching global versions, got #{response.body}"
16 | end
17 |
18 | versions = YAML.load(response.body)
19 |
20 | versions.each { |k, v| update_image_tag(k, v['image']['tag']) if @config['images'].key? k }
21 |
22 | File.write(CONFIG_PATH, YAML.dump(@config))
23 |
24 | puts 'Version update complete!'
25 | end
26 | end
27 |
28 | def update_image_tag(component, tag)
29 | image = @config['images'][component].split(':')
30 | image[-1] = tag
31 |
32 | @config['images'][component] = image.join(':')
33 | end
34 |
--------------------------------------------------------------------------------
/lib/tasks/wallets.rake:
--------------------------------------------------------------------------------
1 | require 'faraday'
2 | require 'json'
3 | require 'yaml'
4 |
5 | namespace :wallet do
6 | desc 'Generate ethereum wallet from a cryptonode'
7 | task :create, [:kind,:url,:secret] do |_, args|
8 | response = Faraday::Connection.new.post(args.url) do |request|
9 | request.headers["Content-Type"] = "application/json"
10 | request.body = "{\"jsonrpc\":\"2.0\",\"method\":\"personal_newAccount\",\"params\":[\"#{args.secret}\"],\"id\":1}"
11 | request.options.timeout = 300
12 | end
13 | address = JSON.parse(response.body)['result']
14 | puts "----- Generating a new #{args.kind} wallet -----", "Address: " + address
15 |
16 | @config['wallets']['eth'].find { |w| w['kind'] == args.kind }.update('address' => address, 'secret' => args.secret)
17 |
18 | File.open(CONFIG_PATH, 'w') {|f| f.write @config.to_yaml }
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/spec/opendax/payload_spec.rb:
--------------------------------------------------------------------------------
1 | require 'opendax/payload'
2 |
3 | describe Opendax::Payload do
4 | let(:secret) { 'myTailorIsRich42' }
5 | let(:encoder) { Opendax::Payload.new(secret: secret) }
6 | let(:valid_decoder) { encoder }
7 | let(:invalid_decoder) { Opendax::Payload.new(secret: 'randomSecret') }
8 | let(:service) { 'barong' }
9 | let(:image) { 'rubykube/barong:2.0.8-alpha' }
10 | let(:jwt) { encoder.generate!(service: service, image: image) }
11 |
12 | it 'should encode a JWT HMAC' do
13 | token = encoder.generate!(service: service, image: image)
14 |
15 | expect(token).not_to be_nil
16 | expect(token).to match /[A-Za-z0-9\-\._~\+\/]+=*/
17 | end
18 |
19 | it 'should decode a token with valid secret' do
20 | decoded = valid_decoder.safe_decode(jwt)
21 |
22 | expect(decoded).not_to be_nil
23 | expect(decoded['service']).to eq service
24 | expect(decoded['image']).to eq image
25 | end
26 |
27 | it 'should not decode a token with invalid secret' do
28 | decoded = invalid_decoder.safe_decode(jwt)
29 |
30 | expect(decoded).to be_nil
31 | end
32 |
33 | it 'defines an API' do
34 | pgen = Opendax::Payload.new(secret: '0x42', expire: 600)
35 | token = pgen.generate!(service: service, image: image)
36 | pgen.decode!(token)
37 | pgen.safe_decode(token)
38 | end
39 |
40 | it 'expire time should be configurable' do
41 | exp_time = 4200
42 | exp_coder = Opendax::Payload.new(secret: 'ab', expire: exp_time)
43 | encoded = exp_coder.generate!(service: service, image: image)
44 | decoded = exp_coder.decode!(encoded)
45 | computed_exp = decoded['exp'] - decoded['iat']
46 |
47 | expect(computed_exp).to eq exp_time
48 | end
49 | end
50 |
--------------------------------------------------------------------------------
/spec/opendax/renderer_spec.rb:
--------------------------------------------------------------------------------
1 | require 'opendax/renderer'
2 |
3 | describe Opendax::Renderer do
4 | let(:renderer) { Opendax::Renderer.new }
5 | let(:fake_erb_result) { { 'data' => 'this is fake data'} }
6 | let(:config) do
7 | {
8 | 'app' => {
9 | 'name' => 'Opendax',
10 | 'domain' => 'app.test'
11 | },
12 | 'render_protect' => false,
13 | 'ssl' => {
14 | 'enabled' => 'true',
15 | 'email' => 'support@example.com'
16 | },
17 | 'images' => {
18 | 'peatio' => 'rubykube/peatio:latest',
19 | 'barong' => 'rubykube/barong:latest',
20 | 'frontend' => 'rubykube/mikroapp:latest',
21 | 'tower' => 'rubykube/tower:latest'
22 | },
23 | 'vendor' => {
24 | 'frontend' => 'https://github.com/rubykube/mikroapp.git'
25 | }
26 | }
27 | end
28 |
29 | it 'should load configuration' do
30 | allow(YAML).to receive(:load_file).and_return(config)
31 | expect(renderer.config).to eq(config)
32 | end
33 |
34 | describe '.config' do
35 | it 'should load configuration' do
36 | allow(YAML).to receive(:load_file).and_return(config)
37 | expect(renderer.config).to eq(config)
38 | end
39 | end
40 |
41 | describe '.generate_key' do
42 | it 'should generate a private RSA key by default' do
43 | renderer.generate_key('config/secrets/barong.key')
44 | expect(File).to exist('config/secrets/barong.key')
45 | end
46 |
47 | it 'should generate a public RSA key in addition when the flag is passed' do
48 | renderer.generate_key('config/secrets/app.key', public: true)
49 | expect(File).to exist('config/secrets/app.key')
50 | expect(File).to exist('config/secrets/app.key.pub')
51 | end
52 | end
53 |
54 | describe '.render_keys' do
55 | it 'should create files with private and public RSA keys' do
56 | renderer.render_keys
57 | expect(File).to exist('config/secrets/barong.key')
58 | expect(File).to exist('config/secrets/app.key')
59 | expect(File).to exist('config/secrets/app.key.pub')
60 | end
61 | end
62 |
63 | describe '.render_file' do
64 | it 'should render file' do
65 | expect(ERB).to receive(:new).once.and_call_original
66 | expect_any_instance_of(ERB).to receive(:result).once.and_return(fake_erb_result)
67 | expect(File).to receive(:write).with('./config/peatio.env', fake_erb_result).once.and_call_original
68 |
69 | renderer.render_file('./templates/config/peatio.env.erb', './config/peatio.env')
70 | end
71 | end
72 |
73 | describe '.template_name' do
74 | it 'should exclude "templates" directory' do
75 | file_name = renderer.template_name('./templates/config/peatio.env.erb')
76 | expect(file_name).not_to start_with('./templates')
77 | end
78 |
79 | it 'should return relative path to file' do
80 | file_name = renderer.template_name('./templates/compose/app.yaml.erb')
81 | expect(file_name).to start_with('.')
82 | end
83 | end
84 |
85 | let(:renderer) { Opendax::Renderer.new }
86 |
87 | describe '.render' do
88 | it 'should call exact amount of helper functions' do
89 | number_of_files = Dir.glob('./templates/**/*.erb', File::FNM_DOTMATCH).length
90 | expect(renderer).to receive(:render_file).exactly(number_of_files).times
91 |
92 | renderer.render
93 | end
94 | end
95 | end
96 |
--------------------------------------------------------------------------------
/spec/opendax/server_spec.rb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openware/opendax/e204b565e6879bf5afcd3450a93e5d226262d6a6/spec/opendax/server_spec.rb
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # This file was generated by the `rspec --init` command. Conventionally, all
2 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3 | # The generated `.rspec` file contains `--require spec_helper` which will cause
4 | # this file to always be loaded, without a need to explicitly require it in any
5 | # files.
6 | #
7 | # Given that it is always loaded, you are encouraged to keep this file as
8 | # light-weight as possible. Requiring heavyweight dependencies from this file
9 | # will add to the boot time of your test suite on EVERY test run, even for an
10 | # individual file that may not need all of that loaded. Instead, consider making
11 | # a separate helper file that requires the additional dependencies and performs
12 | # the additional setup, and require it from the spec files that actually need
13 | # it.
14 | #
15 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16 | RSpec.configure do |config|
17 | # rspec-expectations config goes here. You can use an alternate
18 | # assertion/expectation library such as wrong or the stdlib/minitest
19 | # assertions if you prefer.
20 | config.expect_with :rspec do |expectations|
21 | # This option will default to `true` in RSpec 4. It makes the `description`
22 | # and `failure_message` of custom matchers include text for helper methods
23 | # defined using `chain`, e.g.:
24 | # be_bigger_than(2).and_smaller_than(4).description
25 | # # => "be bigger than 2 and smaller than 4"
26 | # ...rather than:
27 | # # => "be bigger than 2"
28 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true
29 | end
30 |
31 | # rspec-mocks config goes here. You can use an alternate test double
32 | # library (such as bogus or mocha) by changing the `mock_with` option here.
33 | config.mock_with :rspec do |mocks|
34 | # Prevents you from mocking or stubbing a method that does not exist on
35 | # a real object. This is generally recommended, and will default to
36 | # `true` in RSpec 4.
37 | mocks.verify_partial_doubles = true
38 | end
39 |
40 | # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
41 | # have no way to turn it off -- the option exists only for backwards
42 | # compatibility in RSpec 3). It causes shared context metadata to be
43 | # inherited by the metadata hash of host groups and examples, rather than
44 | # triggering implicit auto-inclusion in groups with matching metadata.
45 | config.shared_context_metadata_behavior = :apply_to_host_groups
46 |
47 | # The settings below are suggested to provide a good initial experience
48 | # with RSpec, but feel free to customize to your heart's content.
49 | =begin
50 | # This allows you to limit a spec run to individual examples or groups
51 | # you care about by tagging them with `:focus` metadata. When nothing
52 | # is tagged with `:focus`, all examples get run. RSpec also provides
53 | # aliases for `it`, `describe`, and `context` that include `:focus`
54 | # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
55 | config.filter_run_when_matching :focus
56 |
57 | # Allows RSpec to persist some state between runs in order to support
58 | # the `--only-failures` and `--next-failure` CLI options. We recommend
59 | # you configure your source control system to ignore this file.
60 | config.example_status_persistence_file_path = "spec/examples.txt"
61 |
62 | # Limits the available syntax to the non-monkey patched syntax that is
63 | # recommended. For more details, see:
64 | # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
65 | # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
66 | # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
67 | config.disable_monkey_patching!
68 |
69 | # This setting enables warnings. It's recommended, but in some cases may
70 | # be too noisy due to issues in dependencies.
71 | config.warnings = true
72 |
73 | # Many RSpec users commonly either run the entire suite or an individual
74 | # file, and it's useful to allow more verbose output when running an
75 | # individual spec file.
76 | if config.files_to_run.one?
77 | # Use the documentation formatter for detailed output,
78 | # unless a formatter has already been configured
79 | # (e.g. via a command-line flag).
80 | config.default_formatter = "doc"
81 | end
82 |
83 | # Print the 10 slowest examples and example groups at the
84 | # end of the spec run, to help surface which specs are running
85 | # particularly slow.
86 | config.profile_examples = 10
87 |
88 | # Run specs in random order to surface order dependencies. If you find an
89 | # order dependency and want to debug it, you can fix the order by providing
90 | # the seed, which is printed after each run.
91 | # --seed 1234
92 | config.order = :random
93 |
94 | # Seed global randomization in this process using the `--seed` CLI option.
95 | # Setting this allows you to use `--seed` to deterministically reproduce
96 | # test failures related to randomization by passing the same `--seed` value
97 | # as the one that triggered the failure.
98 | Kernel.srand config.seed
99 | =end
100 | end
101 |
--------------------------------------------------------------------------------
/templates/.env.erb:
--------------------------------------------------------------------------------
1 | COMPOSE_PROJECT_NAME=<%= @config['app']['name'].downcase %>
2 | COMPOSE_FILE=compose/app.yaml:compose/backend.yaml:compose/gateway.yaml:compose/proxy.yaml:compose/daemons.yaml:compose/frontend.yaml:compose/cryptonodes.yaml:compose/arke.yaml:compose/superset.yaml:compose/monitoring.yaml
3 | PEATIO_RAILS_VAULT_TOKEN=<%= @config['vault']['peatio_rails_token'] %>
4 | PEATIO_CRYPTO_VAULT_TOKEN=<%= @config['vault']['peatio_crypto_token'] %>
5 | PEATIO_UPSTREAM_VAULT_TOKEN=<%= @config['vault']['peatio_upstream_token'] %>
6 | PEATIO_MATCHING_VAULT_TOKEN=<%= @config['vault']['peatio_matching_token'] %>
7 |
--------------------------------------------------------------------------------
/templates/compose/app.yaml.erb:
--------------------------------------------------------------------------------
1 | version: '3.6'
2 |
3 | services:
4 | peatio:
5 | restart: always
6 | image: "<%= @config['images']['peatio'] %>"
7 | environment:
8 | - VAULT_TOKEN=${PEATIO_RAILS_VAULT_TOKEN}
9 | env_file:
10 | - ../config/peatio.env
11 | expose:
12 | - "8000"
13 | volumes:
14 | - ../config/peatio/seed:/opt/peatio/config/seed
15 | - ../config/peatio/management_api_v1.yml:/opt/peatio/config/management_api_v1.yml
16 | - ../config/peatio/plugins.yml:/opt/peatio/config/plugins.yml
17 | - ../config/peatio/abilities.yml:/opt/peatio/config/abilities.yml
18 | labels: {}
19 | command: bash -c "bin/link_config && bundle exec puma --config config/puma.rb"
20 |
21 | barong:
22 | restart: always
23 | image: "<%= @config['images']['barong'] %>"
24 | env_file:
25 | - ../config/barong.env
26 | volumes:
27 | - ../config/secrets:/secrets:ro
28 | - ../config/barong/seeds.yml:/home/app/config/seeds.yml
29 | - ../config/barong/barong.yml:/home/app/config/barong.yml
30 | - ../config/barong/authz_rules.yml:/home/app/config/authz_rules.yml
31 | - ../config/barong/management_api.yml:/home/app/config/management_api.yml
32 | - ../config/barong/abilities.yml:/home/app/config/abilities.yml
33 |
34 | <% if @config['finex']['enabled'] %>
35 | finex-api:
36 | restart: always
37 | image: "<%= @config['finex']['image'] %>"
38 | command: "./orderapi"
39 | volumes:
40 | - ../config/finex:/app/config:ro
41 |
42 | finex-engine:
43 | restart: always
44 | image: "<%= @config['finex']['image'] %>"
45 | command: "./finex"
46 | volumes:
47 | - ../config/finex:/app/config:ro
48 | <% end %>
49 |
50 | applogic:
51 | restart: always
52 | image: "<%= @utils['images']['applogic'] %>"
53 | env_file:
54 | - ../config/applogic.env
55 | expose:
56 | - "8081"
57 | volumes:
58 | - ../config/applogic/management_api_v2.yml:/home/app/config/management_api_v2.yml
59 |
--------------------------------------------------------------------------------
/templates/compose/arke.yaml.erb:
--------------------------------------------------------------------------------
1 | version: '3.6'
2 |
3 | services:
4 | arke-maker:
5 | restart: always
6 | image: "<%= @utils['images']['arke'] %>"
7 | env_file:
8 | - ../config/arke.env
9 | volumes:
10 | - ../config/arke/strategies.yml:/home/app/config/strategies.yml
11 | command: bundle exec ./bin/arke start
12 |
--------------------------------------------------------------------------------
/templates/compose/backend.yaml.erb:
--------------------------------------------------------------------------------
1 | version: '3.6'
2 |
3 | services:
4 | db:
5 | restart: always
6 | <%- if @config['database']['adapter'] == 'mysql' %>
7 | image: mysql:5.7
8 | volumes:
9 | - db_data:/var/lib/mysql
10 | - ../config/mysql:/etc/mysql/conf.d
11 | environment:
12 | MYSQL_ROOT_PASSWORD: <%= @config['database']['password'] %>
13 | <%- elsif @config['database']['adapter'] == 'postgresql' %>
14 | image: postgres:13
15 | volumes:
16 | - db_data:/var/lib/postgresql/data
17 | environment:
18 | POSTGRES_USER: <%= @config['database']['user'] %>
19 | POSTGRES_PASSWORD: <%= @config['database']['password'] %>
20 | <%- end %>
21 |
22 | influxdb:
23 | image: influxdb:1.7.10
24 | restart: always
25 | volumes:
26 | - influx_data:/var/lib/influxdb
27 | - ../config/influxdb/build_candles.sql:/build_candles.sql
28 | - ../config/influxdb/arke.sql:/arke.sql
29 | - ../config/influxdb/peatio.sql:/peatio.sql
30 | - ../config/arke/historical_data:/data/historical_data
31 | environment:
32 | INFLUXDB_ADMIN_ENABLED: "true"
33 |
34 | redis:
35 | image: redis:4.0.10
36 | restart: always
37 | volumes:
38 | - redis_data:/data
39 |
40 | rabbitmq:
41 | image: rabbitmq:3.7.6-management
42 | restart: always
43 | volumes:
44 | - rabbitmq_data:/var/lib/rabbitmq
45 |
46 | vault:
47 | image: vault:1.3.0
48 | restart: always
49 | volumes:
50 | - vault_data:/vault
51 | - ../config/vault:/tmp/policies
52 | command:
53 | - server
54 | cap_add:
55 | - IPC_LOCK
56 | environment:
57 | VAULT_LOCAL_CONFIG: '{"storage": {"file": { "path": "/vault/data" }}, "listener": {"tcp":{"address": "0.0.0.0:8200","tls_disable":"1"}}}'
58 | VAULT_ADDR: http://vault:8200
59 |
60 | volumes:
61 | db_data:
62 | rabbitmq_data:
63 | redis_data:
64 | vault_data:
65 | influx_data:
66 |
--------------------------------------------------------------------------------
/templates/compose/cryptonodes.yaml.erb:
--------------------------------------------------------------------------------
1 | version: '3.6'
2 |
3 | services:
4 | parity:
5 | image: parity/parity:v2.7.2-stable
6 | restart: always
7 | command: |
8 | --chain=kovan
9 | --mode=active
10 | --interface=all
11 | --warp=true
12 | --snapshot-peers=10
13 | --min-peers=5
14 | --max-peers=10
15 | --jsonrpc-interface=0.0.0.0
16 | --jsonrpc-cors=all
17 | --jsonrpc-hosts=all
18 | --jsonrpc-apis=all
19 | --db-compaction=ssd
20 | --no-persistent-txqueue
21 | volumes:
22 | - ../data/parity:/home/parity/.local/share/io.parity.ethereum
23 | ports:
24 | - "127.0.0.1:8545:8545"
25 |
26 | bitcoind:
27 | image: quay.io/openware/bitcoind:0.19.1
28 | restart: always
29 | user: root
30 | command: bitcoind
31 | volumes:
32 | - ../data/bitcoin:/bitcoin
33 | - ../config/bitcoin.conf:/bitcoin/.bitcoin/bitcoin.conf
34 |
35 | litecoind:
36 | image: quay.io/openware/litecoind:0.16.3
37 | restart: always
38 | volumes:
39 | - ../data/litecoin:/litecoin
40 | - ../config/litecoin.conf:/litecoin/litecoin.conf
41 |
--------------------------------------------------------------------------------
/templates/compose/daemons.yaml.erb:
--------------------------------------------------------------------------------
1 | version: '3.6'
2 |
3 | x-daemon: &peatio-daemon
4 | image: "<%= @config['images']['peatio'] %>"
5 | restart: always
6 | env_file:
7 | - ../config/peatio.env
8 | volumes:
9 | - ../config/peatio:/opt/peatio/config:ro
10 |
11 | services:
12 | blockchain:
13 | << : *peatio-daemon
14 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/daemons.rb blockchain"
15 |
16 | cron_job:
17 | << : *peatio-daemon
18 | environment:
19 | - VAULT_TOKEN=${PEATIO_CRYPTO_VAULT_TOKEN}
20 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/daemons.rb cron_job"
21 |
22 | deposit:
23 | << : *peatio-daemon
24 | environment:
25 | - VAULT_TOKEN=${PEATIO_CRYPTO_VAULT_TOKEN}
26 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/daemons.rb deposit"
27 |
28 | upstream:
29 | << : *peatio-daemon
30 | environment:
31 | - VAULT_TOKEN=${PEATIO_UPSTREAM_VAULT_TOKEN}
32 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/daemons.rb upstream"
33 |
34 | deposit_coin_address:
35 | << : *peatio-daemon
36 | environment:
37 | - VAULT_TOKEN=${PEATIO_CRYPTO_VAULT_TOKEN}
38 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/amqp_daemon.rb deposit_coin_address"
39 |
40 | withdraw_coin:
41 | << : *peatio-daemon
42 | environment:
43 | - VAULT_TOKEN=${PEATIO_CRYPTO_VAULT_TOKEN}
44 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/amqp_daemon.rb withdraw_coin"
45 |
46 | influx_writer:
47 | << : *peatio-daemon
48 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/amqp_daemon.rb influx_writer"
49 |
50 | rango:
51 | restart: always
52 | image: "<%= @config['images']['rango'] %>"
53 | env_file:
54 | - ../config/rango.env
55 |
56 | <% unless @config['finex']['enabled'] %>
57 | matching:
58 | << : *peatio-daemon
59 | environment:
60 | - VAULT_TOKEN=${PEATIO_MATCHING_VAULT_TOKEN}
61 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/amqp_daemon.rb matching"
62 |
63 | order_processor:
64 | << : *peatio-daemon
65 | environment:
66 | - VAULT_TOKEN=${PEATIO_MATCHING_VAULT_TOKEN}
67 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/amqp_daemon.rb order_processor"
68 |
69 | trade_executor:
70 | << : *peatio-daemon
71 | environment:
72 | - VAULT_TOKEN=${PEATIO_MATCHING_VAULT_TOKEN}
73 | command: bash -c "bin/link_config && bundle exec ruby lib/daemons/amqp_daemon.rb trade_executor"
74 | <% end %>
75 |
76 | mailer:
77 | restart: always
78 | image: "<%= @config['images']['barong'] %>"
79 | env_file:
80 | - ../config/barong.env
81 | volumes:
82 | - ../config/secrets:/secrets:ro
83 | - ../config/mailer/templates:/home/app/app/views/postmaster
84 | - ../config/mailer.yml:/home/app/config/mailer.yml
85 | command: bash -c "bin/mailer run"
86 |
87 | applogic_sidekiq:
88 | restart: always
89 | image: "<%= @utils['images']['applogic'] %>"
90 | env_file:
91 | - ../config/barong.env
92 | volumes:
93 | - ../config/applogic/management_api_v2.yml:/home/app/config/management_api_v2.yml
94 | - ../config/applogic/schedule.yml:/home/app/config/schedule.yml
95 | command: bash -c "bundle exec sidekiq"
96 |
97 | barong_sidekiq:
98 | restart: always
99 | image: "<%= @config['images']['barong'] %>"
100 | env_file:
101 | - ../config/barong.env
102 | volumes:
103 | - ../config/secrets:/secrets:ro
104 | - ../config/barong/seeds.yml:/home/app/config/seeds.yml
105 | - ../config/barong/barong.yml:/home/app/config/barong.yml
106 | - ../config/barong/authz_rules.yml:/home/app/config/authz_rules.yml
107 | - ../config/barong/management_api.yml:/home/app/config/management_api.yml
108 | command: bash -c "bundle exec sidekiq"
109 |
110 | listener:
111 | restart: always
112 | image: "<%= @utils['images']['applogic'] %>"
113 | env_file:
114 | - ../config/applogic.env
115 | volumes:
116 | - ../config/applogic/management_api_v2.yml:/home/app/config/management_api_v2.yml
117 | command: bash -c "bundle exec rake event_api_listener"
118 |
--------------------------------------------------------------------------------
/templates/compose/frontend.yaml.erb:
--------------------------------------------------------------------------------
1 | version: '3.6'
2 |
3 | services:
4 | frontend:
5 | restart: always
6 | image: "<%= @config['images']['frontend'] %>"
7 | volumes:
8 | - ../config/frontend/env.js:/usr/share/nginx/html/config/env.js
9 | labels:
10 | - "traefik.http.routers.frontend-<%= @name %>.rule=Host(`<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>`) && PathPrefix(`/`)"
11 | - "traefik.enable=true"
12 | - "traefik.http.services.frontend-<%= @name %>.loadbalancer.server.port=3000"
13 | <%- if @config['ssl']['enabled'] -%>
14 | - "traefik.http.routers.frontend-<%= @name %>.entrypoints=websecure"
15 | - "traefik.http.routers.frontend-<%= @name %>.tls=true"
16 | - "traefik.http.routers.frontend-<%= @name %>.tls.certresolver=myresolver"
17 | <%- else -%>
18 | - "traefik.http.routers.frontend-<%= @name %>.entrypoints=web"
19 | <%- end -%>
20 |
21 | tower:
22 | restart: always
23 | image: "<%= @config['images']['tower'] %>"
24 | volumes:
25 | - ../config/frontend/tower.js:/home/app/env.js
26 | labels:
27 | - "traefik.http.routers.tower-<%= @name %>.rule=Host(`<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>`) && PathPrefix(`/tower`)"
28 | - "traefik.enable=true"
29 | - "traefik.http.services.tower-<%= @name %>.loadbalancer.server.port=8080"
30 | <%- if @config['ssl']['enabled'] -%>
31 | - "traefik.http.routers.tower-<%= @name %>.entrypoints=websecure"
32 | - "traefik.http.routers.tower-<%= @name %>.tls=true"
33 | - "traefik.http.routers.tower-<%= @name %>.tls.certresolver=myresolver"
34 | <%- else -%>
35 | - "traefik.http.routers.tower-<%= @name %>.entrypoints=web"
36 | <%- end -%>
37 |
--------------------------------------------------------------------------------
/templates/compose/gateway.yaml.erb:
--------------------------------------------------------------------------------
1 | version: '3.6'
2 |
3 | services:
4 | gateway:
5 | restart: always
6 | image: envoyproxy/envoy:v1.10.0
7 | volumes:
8 | - ../config/gateway:/etc/envoy/
9 | command: /usr/local/bin/envoy -l info -c /etc/envoy/envoy.yaml
10 | labels:
11 | - "traefik.http.routers.gateway-<%= @name %>.rule=Host(`<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>`) && PathPrefix(`/api`,`/admin`,`/assets/`)"
12 | - "traefik.enable=true"
13 | - "traefik.http.services.gateway-<%= @name %>.loadbalancer.server.port=8099"
14 | <%- if @config['ssl']['enabled'] -%>
15 | - "traefik.http.routers.gateway-<%= @name %>.entrypoints=websecure"
16 | - "traefik.http.routers.gateway-<%= @name %>.tls=true"
17 | - "traefik.http.routers.gateway-<%= @name %>.tls.certresolver=myresolver"
18 | <%- else -%>
19 | - "traefik.http.routers.gateway-<%= @name %>.entrypoints=web"
20 | <%- end -%>
21 |
--------------------------------------------------------------------------------
/templates/compose/monitoring.yaml.erb:
--------------------------------------------------------------------------------
1 | version: '3.6'
2 |
3 | services:
4 | node_exporter:
5 | image: prom/node-exporter:v0.18.1
6 | container_name: node_exporter
7 | volumes:
8 | - /proc:/host/proc:ro
9 | - /sys:/host/sys:ro
10 | - /:/rootfs:ro
11 | command:
12 | - '--path.procfs=/host/proc'
13 | - '--path.rootfs=/rootfs'
14 | - '--path.sysfs=/host/sys'
15 | - '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
16 | ports:
17 | - 9100:9100
18 |
19 | cadvisor:
20 | image: gcr.io/google-containers/cadvisor:v0.34.0
21 | container_name: cadvisor
22 | volumes:
23 | - /var/run:/var/run:rw
24 | - /var/lib/docker/:/var/lib/docker:ro
25 | - /:/rootfs:ro
26 | - /sys:/sys:ro
27 | ports:
28 | - 8080:8080
29 |
--------------------------------------------------------------------------------
/templates/compose/proxy.yaml.erb:
--------------------------------------------------------------------------------
1 | version: '3.6'
2 |
3 | services:
4 | proxy:
5 | restart: always
6 | image: traefik:2.1.8
7 | ports:
8 | - "80:80"
9 | - "443:443"
10 | volumes:
11 | - /var/run/docker.sock:/var/run/docker.sock
12 | <%- if @config['ssl']['enabled'] -%>
13 | - ../config/acme.json:/acme.json
14 | <%- end -%>
15 | command:
16 | - "--log.level=DEBUG"
17 | - "--api.insecure=true"
18 | - "--providers.docker=true"
19 | - "--providers.docker.exposedbydefault=false"
20 | - "--entryPoints.web.address=:80"
21 | - "--entryPoints.web.forwardedHeaders.insecure"
22 | <%- if @config['ssl']['enabled'] -%>
23 | - "--entryPoints.websecure.address=:443"
24 | - "--entryPoints.websecure.forwardedHeaders.insecure"
25 | - "--certificatesresolvers.myresolver.acme.httpchallenge=true"
26 | - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
27 | - "--certificatesresolvers.myresolver.acme.email=<%= @config['ssl']['email'] %>"
28 | - "--certificatesresolvers.myresolver.acme.storage=/acme.json"
29 | labels:
30 | - "traefik.enable=true"
31 | - "traefik.http.routers.http-catchall.rule=hostregexp(`{host:[a-z-.]+}`)"
32 | - "traefik.http.routers.http-catchall.entrypoints=web"
33 | - "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
34 | - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
35 | - "traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true"
36 | <%- end -%>
37 |
--------------------------------------------------------------------------------
/templates/compose/superset.yaml.erb:
--------------------------------------------------------------------------------
1 | version: '3.6'
2 |
3 | services:
4 | superset:
5 | image: "<%= @utils['images']['superset'] %>"
6 | restart: always
7 | volumes:
8 | - superset_db:/var/lib/superset
9 | labels:
10 | - "traefik.http.routers.superset-<%= @name %>.rule=Host(`superset.<%= @config['app']['domain'] %>`)"
11 | - "traefik.http.services.superset-<%= @name %>.loadbalancer.server.port=8088"
12 | - "traefik.enable=true"
13 | <%- if @config['ssl']['enabled'] -%>
14 | - "traefik.http.routers.superset-<%= @name %>.entrypoints=websecure"
15 | <%- else -%>
16 | - "traefik.http.routers.superset-<%= @name %>.entrypoints=web"
17 | <%- end -%>
18 |
19 | volumes:
20 | superset_db:
21 |
--------------------------------------------------------------------------------
/templates/compose/vendor.yaml.erb:
--------------------------------------------------------------------------------
1 | version: '3.6'
2 |
3 | services:
4 | frontend:
5 | image: node:11
6 | restart: always
7 | user: "${UID}:${GID}"
8 | volumes:
9 | - ../vendor/frontend:/home/node
10 | command:
11 | - sh
12 | - -c
13 | - |
14 | cd /home/node
15 | yarn
16 | yarn start
17 | labels:
18 | - "traefik.http.routers.frontend-<%= @name %>.rule=Host(`<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>`) && PathPrefix(`/`)"
19 | - "traefik.http.services.frontend-<%= @name %>.loadbalancer.server.port=3000"
20 | - "traefik.enable=true"
21 | <%- if @config['ssl']['enabled'] -%>
22 | - "traefik.http.routers.frontend-<%= @name %>.entrypoints=websecure"
23 | - "traefik.http.routers.frontend-<%= @name %>.tls=true"
24 | - "traefik.http.routers.frontend-<%= @name %>.tls.certresolver=myresolver"
25 | <%- else -%>
26 | - "traefik.http.routers.frontend-<%= @name %>.entrypoints=web"
27 | <%- end -%>
28 |
--------------------------------------------------------------------------------
/templates/config/applogic.env.erb:
--------------------------------------------------------------------------------
1 | RAILS_ENV=production
2 | RAILS_ROOT=/home/app
3 |
4 | BARONG_URL=http://barong:8001
5 | PEATIO_URL=http://peatio:8000
6 | REDIS_URL=redis://redis:6379
7 |
8 | PORT=8081
9 | DATABASE_HOST=db
10 | DATABASE_USER=root
11 | DATABASE_PASSWORD=changeme
12 |
13 | EVENT_API_RABBITMQ_HOST=rabbitmq
14 | EVENT_API_RABBITMQ_PORT=5672
15 | EVENT_API_RABBITMQ_USERNAME=guest
16 | EVENT_API_RABBITMQ_PASSWORD=guest
17 |
18 | BARONG_EVENT_API_JWT_PUBLIC_KEY=<%= @barong_public_key %>
19 | BARONG_EVENT_API_JWT_ALGORITHM=RS256
20 |
21 | EVENT_API_APPLICATION=barong
22 | EVENT_API_EVENT_CATEGORY=model
23 | EVENT_API_EVENT_NAME=profile.created
24 |
25 | JWT_PUBLIC_KEY=<%= @barong_public_key %>
26 | JWT_PRIVATE_KEY=<%= @applogic_private_key %>
27 |
28 | RAILS_LOG_TO_STDOUT=true
29 | SECRET_KEY_BASE=b609ebad4856c8f8a4f465fa785c74fb
30 |
--------------------------------------------------------------------------------
/templates/config/applogic/management_api_v2.yml.erb:
--------------------------------------------------------------------------------
1 | barong:
2 | keychain:
3 | applogic:
4 | algorithm: RS256
5 | value: <%= @applogic_private_key %>
6 |
7 | jwt: {}
8 |
9 | actions:
10 | read_users:
11 | required_signatures: ['applogic']
12 | requires_barong_totp: false
13 |
14 | peatio:
15 | keychain:
16 | applogic:
17 | algorithm: RS256
18 | value: <%= @applogic_private_key %>
19 |
20 | jwt: {}
21 |
22 | actions:
23 | read_operations:
24 | required_signatures: ['applogic']
25 | requires_barong_totp: false
26 |
--------------------------------------------------------------------------------
/templates/config/applogic/schedule.yml.erb:
--------------------------------------------------------------------------------
1 | users_sync_job:
2 | cron: "0 0 * * *" # it will retrieve data every 1 day
3 | class: "UsersSyncWorker"
4 | args:
5 | period: '1'
6 | action: 'sync' # you also can start a new job with action 'reg' to pull new users
7 |
--------------------------------------------------------------------------------
/templates/config/arke.env.erb:
--------------------------------------------------------------------------------
1 | PORT=8081
2 |
3 | LOG_LEVEL=debug
4 |
5 | DISABLE_SPRING=true
6 |
7 | RAILS_ENV=production
8 |
9 | SECRET_KEY_BASE=64
10 |
11 | INFLUXDB_HOST=influxdb
12 |
13 | RABBITMQ_HOST=rabbitmq
14 |
--------------------------------------------------------------------------------
/templates/config/arke/strategies.yml.erb:
--------------------------------------------------------------------------------
1 | <%= @utils['arke'].to_yaml %>
2 |
--------------------------------------------------------------------------------
/templates/config/barong.env.erb:
--------------------------------------------------------------------------------
1 | PORT=8001
2 |
3 | LOG_LEVEL=warn
4 |
5 | DISABLE_SPRING=true
6 |
7 | RAILS_ENV=production
8 |
9 | SECRET_KEY_BASE=64
10 |
11 | <%- if @config['database']['adapter'] == 'postgresql' %>
12 | DATABASE_COLLATION=""
13 | DATABASE_ADAPTER="postgresql"
14 | <%- elsif @config['database']['adapter'] == 'mysql' %>
15 | DATABASE_ADAPTER="mysql2"
16 | <%- end %>
17 | DATABASE_HOST=<%= @config['database']['host'] %>
18 | DATABASE_PORT=<%= @config['database']['port'] %>
19 | DATABASE_USER=<%= @config['database']['user'] %>
20 | DATABASE_PASS=<%= @config['database']['password'] %>
21 |
22 | <%- if @config['twilio']['enabled'] -%>
23 | BARONG_PHONE_VERIFICATION=twilio_sms
24 | BARONG_TWILIO_PHONE_NUMBER=<%= @config['twilio']['phone_number'] %>
25 | BARONG_TWILIO_ACCOUNT_SID=<%= @config['twilio']['account_sid'] %>
26 | BARONG_TWILIO_AUTH_TOKEN=<%= @config['twilio']['auth_token'] %>
27 | <%- end -%>
28 |
29 | BARONG_KYC_PROVIDER=<%= @config['kyc']['provider'] %>
30 |
31 | <%- if @config['kyc']['provider'] == 'kycaid' -%>
32 | BARONG_KYCAID_AUTHORIZATION_TOKEN=<%= @config['kyc']['authorization_token'] %>
33 | BARONG_KYCAID_SANDBOX_MODE=<%= @config['kyc']['sandbox_mode'] %>
34 | BARONG_KYCAID_API_ENDPOINT=<%= @config['kyc']['api_endpoint'] %>
35 | <%- end -%>
36 |
37 | BARONG_STORAGE_PROVIDER=<%= @config['storage']['provider'] %>
38 | BARONG_STORAGE_BUCKET_NAME=<%= @config['storage']['bucketName'] %>
39 | BARONG_STORAGE_ACCESS_KEY=<%= @config['storage']['accessKey'] %>
40 | BARONG_STORAGE_SECRET_KEY=<%= @config['storage']['secretKey'] %>
41 | BARONG_STORAGE_ENDPOINT=<%= @config['storage']['endpoint'] %>
42 | BARONG_STORAGE_SIGNATURE_VERSION=<%= @config['storage']['signatureVersion'] %>
43 | BARONG_STORAGE_REGION=<%= @config['storage']['region'] %>
44 |
45 | BARONG_CAPTCHA=<%= @config['captcha']['type'] %>
46 | <% if @config['captcha']['type'] == 'recaptcha' %>
47 | BARONG_RECAPTCHA_SITE_KEY=<%= @config['captcha']['siteKey'] %>
48 | BARONG_RECAPTCHA_SECRET_KEY=<%= @config['captcha']['secretKey'] %>
49 | <% elsif @config['captcha']['type'] == 'geetest' %>
50 | BARONG_GEETEST_ID=<%= @config['captcha']['siteKey'] %>
51 | BARONG_GEETEST_KEY=<%= @config['captcha']['secretKey'] %>
52 | <% end %>
53 |
54 | JWT_PUBLIC_KEY=<%= @barong_public_key %>
55 | JWT_PRIVATE_KEY_PATH=/secrets/barong.key
56 |
57 | BARONG_VAULT_TOKEN=<%= @config['vault']['barong_token'] %>
58 | BARONG_VAULT_ADDRESS=http://vault:8200
59 | BARONG_VAULT_APP_NAME=<%= @config['app']['name'].downcase %>
60 |
61 | REDIS_URL=redis://redis:6379
62 | BARONG_REDIS_URL=redis://redis:6379
63 |
64 | BARONG_EVENT_API_JWT_PRIVATE_KEY=<%= @barong_private_key %>
65 | BARONG_EVENT_API_JWT_ALGORITHM=RS256
66 | BARONG_EVENT_API_RABBITMQ_HOST=rabbitmq
67 | BARONG_EVENT_API_RABBITMQ_PORT=5672
68 | BARONG_EVENT_API_RABBITMQ_USERNAME=guest
69 | BARONG_EVENT_API_RABBITMQ_PASSWORD=guest
70 |
71 | BARONG_SMTP_HOST=<%= @config['smtp']['host'] %>
72 | BARONG_SMTP_PORT=<%= @config['smtp']['port'] %>
73 | BARONG_SMTP_USER=<%= @config['smtp']['user'] %>
74 | BARONG_SMTP_PASSWORD=<%= @config['smtp']['password'] %>
75 | BARONG_SMTP_LOGO_LINK=<%= @config['smtp']['sender_logo'] %>
76 | BARONG_DEFAULT_LANGUAGE=en
77 |
78 | BARONG_SENDER_NAME=<%= @config['smtp']['sender_name'] %>
79 | BARONG_SENDER_EMAIL=<%= @config['smtp']['sender_email'] %>
80 |
81 | BARONG_KYCAID_AUTHORIZATION_TOKEN=<%= @config['kyc']['authorization_token'] %>
82 | BARONG_KYCAID_SANDBOX_MODE=<%= @config['kyc']['sandbox_mode'] %>
83 | BARONG_KYCAID_API_ENDPOINT=<%= @config['kyc']['api_endpoint'] %>
84 |
85 | BARONG_PASSWORD_MIN_ENTROPY=14
86 | BARONG_PASSWORD_USE_DICTIONARY=false
87 |
88 | BARONG_CSRF_PROTECTION=<%= @config['csrfEnabled'] %>
89 |
90 | BARONG_APP_NAME=<%= @config['app']['name'] %>
91 | BARONG_DOMAIN=<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>
92 |
--------------------------------------------------------------------------------
/templates/config/barong/abilities.yml.erb:
--------------------------------------------------------------------------------
1 | roles:
2 | - superadmin
3 | - admin
4 | - technical
5 | - accountant
6 | - compliance
7 | - support
8 |
9 | admin_permissions:
10 | superadmin:
11 | manage:
12 | - Ability
13 | - User
14 | - Level
15 | - Label
16 | - Profile
17 | - Activity
18 | - APIKey
19 | - Permission
20 | - Restriction
21 | - Document
22 | admin:
23 | read:
24 | - Activity
25 | manage:
26 | - Ability
27 | - User
28 | - Level
29 | - Label
30 | - Profile
31 | - APIKey
32 | - Restriction
33 | - Document
34 | technical:
35 | read:
36 | - Ability
37 | - User
38 | - Level
39 | - Label
40 | - Profile
41 | - Activity
42 | manage:
43 | - APIKey
44 | - Restriction
45 | accountant:
46 | read:
47 | - Ability
48 | - User
49 | - Level
50 | - Label
51 | - Profile
52 | - Activity
53 | compliance:
54 | read:
55 | - Ability
56 | - Document
57 | manage:
58 | - User
59 | - Level
60 | - Label
61 | - Profile
62 | support:
63 | read:
64 | - Ability
65 | - Label
66 | - Level
67 | - Profile
68 | - Activity
69 | manage:
70 | - User
71 |
--------------------------------------------------------------------------------
/templates/config/barong/management_api.yml.erb:
--------------------------------------------------------------------------------
1 | keychain:
2 | applogic:
3 | algorithm: RS256
4 | value: <%= @applogic_public_key %>
5 |
6 | scopes:
7 | read_users:
8 | mandatory_signers:
9 | - applogic
10 | permitted_signers:
11 | - applogic
12 |
--------------------------------------------------------------------------------
/templates/config/bitcoin.conf.erb:
--------------------------------------------------------------------------------
1 | <%- bitcoind = @config['bitcoind'] -%>
2 | txindex=1
3 | dnsseed=1
4 | upnp=0
5 | printtoconsole=1
6 |
7 | server=1
8 |
9 | <%- unless bitcoind['network'] == 'mainnet' -%>
10 | <%= "#{bitcoind['network']}=1" %>
11 | [test]
12 | <%- end -%>
13 | rpcuser=<%= bitcoind['rpcuser'] %>
14 | rpcpassword=<%= bitcoind['rpcpassword'] %>
15 | port=<%= bitcoind['port'] %>
16 | rpcport=<%= bitcoind['rpcport'] %>
17 | rpcbind=0.0.0.0
18 | rpcallowip=0.0.0.0/0
19 |
--------------------------------------------------------------------------------
/templates/config/finex/config.yaml.erb:
--------------------------------------------------------------------------------
1 | metrics:
2 | enabled: true
3 | license: <%= @config['finex']['license_key'] %>
4 | influx:
5 | host: influxdb
6 | port: 8086
7 | scheme: http
8 | database: peatio_production
9 | database:
10 | driver: mysql
11 | name: peatio_production
12 | username: <%= @config['database']['user'] %>
13 | password: <%= @config['database']['password'] %>
14 | host: <%= @config['database']['host'] %>
15 | port: <%= @config['database']['port'] %>
16 | log_level:
17 | log_observer: info
18 | vault:
19 | host: http://vault:8200
20 | token: <%= @config['vault']['finex_engine_token'] %>
21 | app_name: <%= @config['app']['name'].downcase %>
22 | messaging:
23 | driver: amqp
24 | username: guest
25 | password: guest
26 | host: rabbitmq
27 | port: 5672
28 | exchanges:
29 | - name: finex.orderapi
30 | type: direct
31 | durable: false
32 | - name: finex.events.websocket
33 | type: topic
34 | durable: false
35 | - name: peatio.events.ranger
36 | type: topic
37 | durable: false
38 | - name: peatio.trade
39 | type: headers
40 | durable: false
41 | - name: peatio.events
42 | type: direct
43 | durable: false
44 | - name: peatio.matching
45 | type: direct
46 | durable: false
47 | queues:
48 | - name: finex.gateway
49 | - name: finex.events.processor
50 | - name: finex.influx.writer
51 | orderbook:
52 | max_publish_size: 300
53 | gateway:
54 | rate:
55 | maker:
56 | - limit: 500
57 | period: 10s
58 | admin:
59 | - limit: 500
60 | period: 10s
61 | superadmin:
62 | - limit: 500
63 | period: 10s
64 | bench:
65 | - limit: 9000
66 | period: 1s
67 | default:
68 | - limit: 50
69 | period: 10s
70 | - limit: 10000
71 | period: 24h
72 | api:
73 | bulk_limit: 100
74 | rate:
75 | maker:
76 | limit: 500
77 | period: 10s
78 | admin:
79 | limit: 500
80 | period: 10s
81 | superadmin:
82 | limit: 500
83 | period: 10s
84 | default:
85 | limit: 5
86 | period: 1s
87 | actions:
88 | trade:
89 | min_level: 2
90 | roles: [member, broker, trader, maker, admin, superadmin]
91 | bulk_api:
92 | min_level: 3
93 | roles: [maker, admin, superadmin]
94 | admin:
95 | min_level: 3
96 | roles: [admin, superadmin]
97 |
--------------------------------------------------------------------------------
/templates/config/finex/rsa-key.pub.erb:
--------------------------------------------------------------------------------
1 | <%= Base64.decode64(@barong_public_key) %>
2 |
--------------------------------------------------------------------------------
/templates/config/frontend/env.js.erb:
--------------------------------------------------------------------------------
1 | window.env = {
2 | api: {
3 | authUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/barong',
4 | tradeUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/peatio',
5 | finexUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/finex',
6 | applogicUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/applogic',
7 | rangerUrl: '<%= ssl_helper('ws') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/ranger',
8 | },
9 | minutesUntilAutoLogout: '35',
10 | withCredentials: false,
11 | finex: <%= config['finex']['enabled'] %>,
12 | gaTrackerKey: '<%= @config['gaTrackerKey'] %>',
13 | rangerReconnectPeriod: '1',
14 | msAlertDisplayTime: '5000',
15 | incrementalOrderBook: true,
16 | isResizable: false,
17 | isDraggable: false,
18 | languages: ['en', 'ru'],
19 | sessionCheckInterval: '15000',
20 | balancesFetchInterval: '3000',
21 | passwordEntropyStep: 14,
22 | showLanding: <%= @config['app']['show_landing'] %>,
23 | sentryEnabled: false,
24 | kycSteps: [
25 | 'email',
26 | 'phone',
27 | 'profile',
28 | 'document',
29 | 'address',
30 | ],
31 | };
32 |
--------------------------------------------------------------------------------
/templates/config/frontend/tower.js.erb:
--------------------------------------------------------------------------------
1 | window.env = {
2 | applogicUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/applogic',
3 | authUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/barong',
4 | peatioUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/peatio',
5 | finexUrl: '<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>/api/v2/finex',
6 | msAlertDisplayTime: '5000',
7 | tablePageLimit: 50,
8 | minutesUntilAutoLogout: '35',
9 | finex: <%= config['finex']['enabled'] %>,
10 | aml: false,
11 | captcha: {
12 | captchaType: '<%= @config['captcha']['type'] %>',
13 | siteKey: '<%= @config['captcha']['siteKey'] %>',
14 | },
15 | labelSwitcher: [
16 | { name: 'email', label: [{ email: 'verified' }] },
17 | { name: 'phone', label: [{ phone: 'verified' }] },
18 | { name: 'identity', label: [{ profile: 'partial' }, { id_document: 'verified' }, { liveness: 'verified' }] },
19 | { name: 'residence', label: [{ document: 'verified' }] },
20 | ],
21 | plugins: [],
22 | roleTypes: [
23 | {
24 | value: 'Admin',
25 | key: 'admin',
26 | },
27 | {
28 | value: 'Member',
29 | key: 'member',
30 | },
31 | {
32 | value: 'Super Admin',
33 | key: 'superadmin',
34 | },
35 | {
36 | value: 'Accountant',
37 | key: 'accountant',
38 | },
39 | {
40 | value: 'Compliance',
41 | key: 'compliance',
42 | },
43 | {
44 | value: 'Technical',
45 | key: 'technical',
46 | },
47 | {
48 | value: 'Support',
49 | key: 'support',
50 | },
51 | {
52 | value: 'Trader',
53 | key: 'trader',
54 | },
55 | {
56 | value: 'Broker',
57 | key: 'broker',
58 | },
59 | ],
60 | allowedRoles: [
61 | 'admin',
62 | 'superadmin',
63 | 'accountant',
64 | 'compliance',
65 | 'support',
66 | 'technical',
67 | 'manager',
68 | ],
69 | withCredentials: false,
70 | sentryEnabled: false,
71 | devMode: true,
72 | minutesBeforeWarningMessage: '1',
73 | };
74 |
--------------------------------------------------------------------------------
/templates/config/gateway/envoy.yaml.erb:
--------------------------------------------------------------------------------
1 | static_resources:
2 | listeners:
3 | - address:
4 | socket_address:
5 | address: 0.0.0.0
6 | port_value: 8099
7 | filter_chains:
8 | - filters:
9 | - name: envoy.http_connection_manager
10 | config:
11 | codec_type: auto
12 | stat_prefix: ingress_http
13 | route_config:
14 | name: local_route
15 | virtual_hosts:
16 | - name: backend
17 | domains:
18 | - "*"
19 | cors:
20 | allow_origin:
21 | - "<%= ssl_helper('http') %>://<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>"
22 | allow_methods: "PUT, GET, POST"
23 | allow_headers: "content-type, x-grpc-web"
24 | filter_enabled:
25 | default_value:
26 | numerator: 100
27 | denominator: HUNDRED
28 | runtime_key: cors.www.enabled
29 | routes:
30 | - match:
31 | prefix: "/api/v2/barong"
32 | route:
33 | cluster: barong
34 | prefix_rewrite: "/api/v2/"
35 | - match:
36 | prefix: "/api/v2/applogic"
37 | route:
38 | cluster: applogic
39 | prefix_rewrite: "/api/v2/"
40 | - match:
41 | prefix: "/api/v2/arke"
42 | route:
43 | cluster: arke
44 | prefix_rewrite: "/api/v2/"
45 | - match:
46 | prefix: "/api/v2/peatio"
47 | route:
48 | cluster: peatio
49 | prefix_rewrite: "/api/v2/"
50 | - match:
51 | prefix: "/api/v2/finex"
52 | route:
53 | cluster: finex
54 | prefix_rewrite: "/api/v2/"
55 | - match:
56 | prefix: "/admin"
57 | route:
58 | cluster: peatio
59 | - match:
60 | prefix: "/assets/"
61 | route:
62 | cluster: peatio
63 | - match:
64 | prefix: "/api/v2/ranger/public"
65 | route:
66 | cluster: rango
67 | prefix_rewrite: ""
68 | upgrade_configs:
69 | upgrade_type: "websocket"
70 | - match:
71 | prefix: "/api/v2/ranger/private"
72 | route:
73 | cluster: rango
74 | prefix_rewrite: ""
75 | upgrade_configs:
76 | upgrade_type: "websocket"
77 | http_filters:
78 | - name: envoy.cors
79 | typed_config: {}
80 | - name: envoy.ext_authz
81 | config:
82 | with_request_body:
83 | max_request_bytes: 90000000
84 | allow_partial_message: true
85 | http_service:
86 | authorization_request:
87 | allowed_headers:
88 | patterns:
89 | - exact: cookie
90 | - exact: x-auth-apikey
91 | - exact: x-auth-nonce
92 | - exact: x-auth-signature
93 | - exact: x-csrf-token
94 | - exact: user-agent
95 | - exact: x-forwarded-host
96 | - exact: x-forwarded-for
97 | - exact: from
98 | - exact: x-forwarded-proto
99 | - exact: proxy-authorization
100 | authorization_response:
101 | allowed_upstream_headers:
102 | patterns:
103 | - exact: authorization
104 | allowed_client_headers:
105 | patterns:
106 | - exact: set-cookie
107 | - exact: proxy-authenticate
108 | - exact: www-authenticate
109 | - exact: location
110 | path_prefix: "/api/v2/auth"
111 | server_uri:
112 | cluster: barong
113 | timeout: 1.000s
114 | uri: http://barong:8001
115 | - name: envoy.router
116 | config: {}
117 | perConnectionBufferLimitBytes: 10000000
118 | clusters:
119 | - name: barong
120 | connect_timeout: 0.25s
121 | type: strict_dns
122 | lb_policy: round_robin
123 | hosts:
124 | - socket_address:
125 | address: barong
126 | port_value: 8001
127 | - name: applogic
128 | connect_timeout: 0.25s
129 | type: strict_dns
130 | lb_policy: round_robin
131 | hosts:
132 | - socket_address:
133 | address: applogic
134 | port_value: 8081
135 | - name: arke
136 | connect_timeout: 0.25s
137 | type: strict_dns
138 | lb_policy: round_robin
139 | hosts:
140 | - socket_address:
141 | address: arke
142 | port_value: 8081
143 | - name: peatio
144 | connect_timeout: 0.25s
145 | type: strict_dns
146 | lb_policy: round_robin
147 | hosts:
148 | - socket_address:
149 | address: peatio
150 | port_value: 8000
151 | - name: finex
152 | connect_timeout: 0.25s
153 | type: strict_dns
154 | lb_policy: round_robin
155 | hosts:
156 | - socket_address:
157 | address: finex-api
158 | port_value: 8080
159 | - name: rango
160 | connect_timeout: 0.25s
161 | type: strict_dns
162 | lb_policy: round_robin
163 | hosts:
164 | - socket_address:
165 | address: rango
166 | port_value: 8080
167 | admin:
168 | access_log_path: "/dev/null"
169 | address:
170 | socket_address:
171 | address: 0.0.0.0
172 | port_value: 9099
173 |
--------------------------------------------------------------------------------
/templates/config/litecoin.conf.erb:
--------------------------------------------------------------------------------
1 | <%- litecoind = @config['litecoind'] -%>
2 | txindex=1
3 | dnsseed=1
4 | upnp=0
5 | printtoconsole=1
6 |
7 | server=1
8 |
9 | onlynet=ipv4
10 |
11 | <%- unless litecoind['network'] == 'mainnet' -%>
12 | <%= "#{litecoind['network']}=1" %>
13 | [test]
14 | <%- end -%>
15 | rpcuser=<%= litecoind['rpcuser'] %>
16 | rpcpassword=<%= litecoind['rpcpassword'] %>
17 | port=<%= litecoind['port'] %>
18 | rpcport=<%= litecoind['rpcport'] %>
19 | rpcbind=0.0.0.0
20 | rpcallowip=0.0.0.0/0
21 |
--------------------------------------------------------------------------------
/templates/config/mailer.yml.erb:
--------------------------------------------------------------------------------
1 | keychain:
2 | barong:
3 | algorithm: RS256
4 | value: "<%= @barong_public_key %>"
5 | peatio:
6 | algorithm: RS256
7 | value: "<%= @barong_public_key %>"
8 |
9 | exchanges:
10 | barong_system:
11 | name: barong.events.system
12 | signer: barong
13 | barong_model:
14 | name: barong.events.model
15 | signer: barong
16 | peatio:
17 | name: peatio.events.model
18 | signer: peatio
19 |
20 | events:
21 | - name: Email Confirmation
22 | key: user.email.confirmation.token
23 | exchange: barong_system
24 | templates:
25 | EN:
26 | subject: Registration Confirmation
27 | template_path: email_confirmation.en.html.erb
28 | RU:
29 | subject: Подтверждение Регистрации
30 | template_path: email_confirmation.ru.html.erb
31 |
32 | - name: Password Reset
33 | key: user.password.reset.token
34 | exchange: barong_system
35 | templates:
36 | EN:
37 | subject: Password Reset
38 | template_path: password_reset.en.html.erb
39 | RU:
40 | subject: Сброс Пароля
41 | template_path: password_reset.ru.html.erb
42 |
43 | - name: Label Created
44 | key: label.created
45 | exchange: barong_model
46 | expression: |
47 | record.key in ["phone", "profile", "document"] &&
48 | record.value in ["verified", "rejected"]
49 | templates:
50 | EN:
51 | subject: Account Details Updated
52 | template_path: label_created.en.html.erb
53 |
54 | - name: Label Updated
55 | key: label.updated
56 | exchange: barong_model
57 | expression: |
58 | record.key in ["phone", "profile", "document"] &&
59 | record.value in ["verified", "rejected"]
60 | templates:
61 | EN:
62 | subject: Account Details Updated
63 | template_path: label_created.en.html.erb
64 |
65 | - name: Deposit Accepted
66 | key: deposit.updated
67 | exchange: peatio
68 | expression: changes.state == "submitted" && record.state == "accepted"
69 | templates:
70 | EN:
71 | subject: Deposit Accepted
72 | template_path: deposit_accepted.en.html.erb
73 |
74 | - name: Session Create
75 | key: session.create
76 | exchange: barong_system
77 | templates:
78 | EN:
79 | subject: New Login
80 | template_path: session_create.en.html.erb
81 |
82 | - name: Withdrawal Succeed
83 | key: withdraw.updated
84 | exchange: peatio
85 | expression: changes.state in ["succeed", "rejected", "canceled", "failed", "accepted"] && record.state in ["succeed", "rejected", "canceled", "failed"]
86 | templates:
87 | EN:
88 | subject: Withdrawal Succeed
89 | template_path: withdraw_succeed.en.html.erb
90 |
91 | - name: New Beneficiary
92 | key: beneficiary.created
93 | exchange: peatio
94 | templates:
95 | EN:
96 | subject: New Beneficiary
97 | template_path: new_beneficiary.en.html.erb
98 |
99 | - name: Resend beneficiary
100 | key: beneficiary.updated
101 | exchange: peatio
102 | expression:
103 | and:
104 | record.state: 'pending'
105 | templates:
106 | EN:
107 | subject: Resend Beneficiary
108 | template_path: new_beneficiary.en.html.erb
109 |
--------------------------------------------------------------------------------
/templates/config/mysql/innodb.cnf.erb:
--------------------------------------------------------------------------------
1 | [mysqld]
2 | innodb_buffer_pool_size = 2G
3 | innodb_buffer_pool_instances = 2
4 | innodb_log_buffer_size = 128M
5 | innodb_log_file_size = 512M
6 | innodb_flush_log_at_trx_commit = 0
7 |
--------------------------------------------------------------------------------
/templates/config/peatio.env.erb:
--------------------------------------------------------------------------------
1 | RAILS_ENV=production
2 | RAILS_ROOT=/home/app
3 |
4 | PORT=8000
5 | URL_HOST=<%= @config['app']['subdomain'] %>.<%= @config['app']['domain'] %>
6 |
7 | LOG_LEVEL=warn
8 |
9 | ADMIN=admin@barong.io
10 |
11 | <%- if @config['database']['adapter'] == 'postgresql' %>
12 | DATABASE_COLLATION=""
13 | DATABASE_ADAPTER="postgresql"
14 | <%- elsif @config['database']['adapter'] == 'mysql' %>
15 | DATABASE_ADAPTER="mysql2"
16 | <%- end %>
17 | DATABASE_HOST=<%= @config['database']['host'] %>
18 | DATABASE_PORT=<%= @config['database']['port'] %>
19 | DATABASE_USER=<%= @config['database']['user'] %>
20 | DATABASE_PASS=<%= @config['database']['password'] %>
21 |
22 | VAULT_ADDR=http://vault:8200
23 | VAULT_TOKEN=
24 | VAULT_APP_NAME=<%= @config['app']['name'].downcase %>
25 |
26 | REDIS_URL=redis://redis:6379
27 |
28 | RABBITMQ_HOST=rabbitmq
29 |
30 |
31 | MARKETS_CONFIG=/opt/peatio/config/seed/markets.yml
32 | CURRENCIES_CONFIG=/opt/peatio/config/seed/currencies.yml
33 | MANAGEMENT_API_V1_CONFIG=/opt/peatio/config/management_api_v1.yml
34 |
35 | JWT_AUDIENCE=peatio,barong
36 | JWT_PUBLIC_KEY=<%= @barong_public_key %>
37 |
38 | INFLUXDB_HOST=influxdb
39 |
40 | EVENT_API_JWT_PRIVATE_KEY=<%= @barong_private_key %>
41 | EVENT_API_JWT_ALGORITHM=RS256
42 | EVENT_API_RABBITMQ_HOST=rabbitmq
43 | EVENT_API_RABBITMQ_PORT=5672
44 | EVENT_API_RABBITMQ_USERNAME=guest
45 | EVENT_API_RABBITMQ_PASSWORD=guest
46 |
47 | MINIMUM_MEMBER_LEVEL_FOR_DEPOSIT=1
48 | MINIMUM_MEMBER_LEVEL_FOR_WITHDRAW=3
49 | MINIMUM_MEMBER_LEVEL_FOR_TRADING=2
50 |
51 | SECRET_KEY_BASE=faiba2shei0Ae5gahCh4aipoh3meyaFi
52 | FORCE_SECURE_CONNECTION="false"
53 |
--------------------------------------------------------------------------------
/templates/config/peatio/abilities.yml.erb:
--------------------------------------------------------------------------------
1 | roles:
2 | - superadmin
3 | - admin
4 | - technical
5 | - accountant
6 | - compliance
7 | - support
8 | - member
9 | - broker
10 | - trader
11 | - maker
12 | - sa_maker
13 |
14 | admin_permissions:
15 | superadmin:
16 | manage:
17 | - Operations::Account
18 | - Operations::Asset
19 | - Operations::Expense
20 | - Operations::Liability
21 | - Operations::Revenue
22 | - Member
23 | - Account
24 | - Beneficiary
25 | - PaymentAddress
26 | - Deposit
27 | - Withdraw
28 | - WithdrawLimit
29 | - Blockchain
30 | - Currency
31 | - Engine
32 | - Market
33 | - TradingFee
34 | - Wallet
35 | - Adjustment
36 | - InternalTransfer
37 | - WhitelistedSmartContract
38 | read:
39 | - Trade
40 | - Order
41 | create:
42 | - Deposits::Fiat
43 | update:
44 | - Order
45 | admin:
46 | manage:
47 | - Operations::Account
48 | - Operations::Asset
49 | - Operations::Expense
50 | - Operations::Liability
51 | - Operations::Revenue
52 | - Beneficiary
53 | - Deposit
54 | - Withdraw
55 | - WithdrawLimit
56 | - Engine
57 | - Market
58 | - TradingFee
59 | - Wallet
60 | - Adjustment
61 | - InternalTransfer
62 | - WhitelistedSmartContract
63 | - Currency
64 | - Blockchain
65 | read:
66 | - Trade
67 | - Order
68 | - Account
69 | - PaymentAddress
70 | - Member
71 | create:
72 | - Deposits::Fiat
73 | update:
74 | - Order
75 | - Member
76 | technical:
77 | read:
78 | - Operations::Account
79 | - Operations::Asset
80 | - Operations::Expense
81 | - Operations::Liability
82 | - Trade
83 | - Order
84 | - Member
85 | - InternalTransfer
86 | manage:
87 | - WithdrawLimit
88 | - Blockchain
89 | - Currency
90 | - Engine
91 | - Market
92 | - TradingFee
93 | - Wallet
94 | - WhitelistedSmartContract
95 | update:
96 | - Order
97 | accountant:
98 | read:
99 | - Operations::Account
100 | - Operations::Asset
101 | - Operations::Expense
102 | - Operations::Liability
103 | - Operations::Revenue
104 | - Member
105 | - Account
106 | - Beneficiary
107 | - PaymentAddress
108 | - Deposit
109 | - Withdraw
110 | - WithdrawLimit
111 | - Blockchain
112 | - Currency
113 | - Engine
114 | - Market
115 | - TradingFee
116 | - Wallet
117 | - Trade
118 | - Order
119 | - Adjustment
120 | - InternalTransfer
121 | create:
122 | - Deposits::Fiat
123 | - Adjustment
124 | compliance:
125 | read:
126 | - Operations::Account
127 | - Operations::Asset
128 | - Operations::Expense
129 | - Operations::Liability
130 | - Member
131 | - Account
132 | - Beneficiary
133 | - PaymentAddress
134 | - Deposit
135 | - Withdraw
136 | - Currency
137 | - Engine
138 | - Market
139 | - Trade
140 | - Order
141 | support:
142 | read:
143 | - Operations::Account
144 | - Operations::Asset
145 | - Operations::Expense
146 | - Operations::Liability
147 | - Member
148 | - Account
149 | - Beneficiary
150 | - PaymentAddress
151 | - Deposit
152 | - Withdraw
153 | - Currency
154 | - Engine
155 | - Market
156 | - Trade
157 | - Order
158 | - InternalTransfer
159 |
160 | user_permissions:
161 | superadmin:
162 | manage: all
163 | admin:
164 | manage: all
165 | technical:
166 | manage: all
167 | accountant:
168 | manage: all
169 | compliance:
170 | manage: all
171 | support:
172 | manage: all
173 | member:
174 | manage: all
175 | broker:
176 | manage: all
177 | trader:
178 | manage: all
179 | maker:
180 | manage: all
181 | sa_maker:
182 | read:
183 | - Operations::Account
184 | - Order
185 | - Trade
186 | - StatsMemberPnl
187 | create:
188 | - Order
189 | update:
190 | - Order
191 |
--------------------------------------------------------------------------------
/templates/config/peatio/management_api_v1.yml.erb:
--------------------------------------------------------------------------------
1 | keychain:
2 | applogic:
3 | algorithm: RS256
4 | value: <%= @applogic_public_key %>
5 |
6 | scopes:
7 | read_operations:
8 | mandatory_signers:
9 | - applogic
10 | permitted_signers:
11 | - applogic
12 |
13 | jwt: {}
14 |
--------------------------------------------------------------------------------
/templates/config/peatio/seed/accounts.yml.erb:
--------------------------------------------------------------------------------
1 | - code: 101
2 | type: asset
3 | kind: main
4 | currency_type: fiat
5 | description: Main Fiat Assets Account
6 | scope: platform
7 |
8 | - code: 102
9 | type: asset
10 | kind: main
11 | currency_type: coin
12 | description: Main Crypto Assets Account
13 | scope: platform
14 |
15 | - code: 201
16 | type: liability
17 | kind: main
18 | currency_type: fiat
19 | description: Main Fiat Liabilities Account
20 | scope: member
21 |
22 | - code: 202
23 | type: liability
24 | kind: main
25 | currency_type: coin
26 | description: Main Crypto Liabilities Account
27 | scope: member
28 |
29 | - code: 211
30 | type: liability
31 | kind: locked
32 | currency_type: fiat
33 | description: Locked Fiat Liabilities Account
34 | scope: member
35 |
36 | - code: 212
37 | type: liability
38 | kind: locked
39 | currency_type: coin
40 | description: Locked Crypto Liabilities Account
41 | scope: member
42 |
43 | - code: 301
44 | type: revenue
45 | kind: main
46 | currency_type: fiat
47 | description: Main Fiat Revenues Account
48 | scope: platform
49 |
50 | - code: 302
51 | type: revenue
52 | kind: main
53 | currency_type: coin
54 | description: Main Crypto Revenues Account
55 | scope: platform
56 |
57 | - code: 401
58 | type: expense
59 | kind: main
60 | currency_type: fiat
61 | description: Main Fiat Expenses Account
62 | scope: platform
63 |
64 | - code: 402
65 | type: expense
66 | kind: main
67 | currency_type: coin
68 | description: Main Crypto Expenses Account
69 | scope: platform
70 |
--------------------------------------------------------------------------------
/templates/config/peatio/seed/blockchains.yml.erb:
--------------------------------------------------------------------------------
1 | - key: eth-<%= @config['parity']['network'] %>
2 | name: Ethereum <%= @config['parity']['network'].capitalize %>
3 | client: parity
4 | server: http://<%= @config['parity']['address'] %>:<%= @config['parity']['rpcport'] %>
5 | height: 8670000
6 | min_confirmations: 6
7 | explorer:
8 | address: https://etherscan.io/address/#{address}
9 | transaction: https://etherscan.io/tx/#{txid}
10 | status: active
11 |
12 | <% if @config['bitcoind']['enabled'] %>
13 | - key: btc-<%= @config['bitcoind']['network'] %>
14 | name: Bitcoin <%= @config['bitcoind']['network'].capitalize %>
15 | client: bitcoin
16 | server: http://<%= @config['bitcoind']['rpcuser'] %>:<%= @config['bitcoind']['rpcpassword'] %>@<%= @config['bitcoind']['address'] %>:<%= @config['bitcoind']['rpcport'] %>
17 | height: 597000
18 | min_confirmations: 6
19 | explorer:
20 | address: https://blockchain.info/address/#{address}
21 | transaction: https://blockchain.info/tx/#{txid}
22 | status: active
23 | <% end %>
24 |
--------------------------------------------------------------------------------
/templates/config/peatio/seed/currencies.yml.erb:
--------------------------------------------------------------------------------
1 | - id: usd
2 | name: US Dollar
3 | type: fiat
4 | precision: 2
5 | base_factor: 1
6 | visible: true
7 | deposit_enabled: true
8 | withdrawal_enabled: true
9 | min_deposit_amount: 0.01
10 | min_collection_amount: 0.01
11 | withdraw_limit_24h: 100
12 | withdraw_limit_72h: 200
13 | deposit_fee: 0
14 | withdraw_fee: 0
15 | position: 1
16 | options: {}
17 |
18 | - id: eth
19 | name: Ethereum
20 | blockchain_key: eth-<%= @config['parity']['network'] %>
21 | type: coin
22 | precision: 8
23 | base_factor: 1_000_000_000_000_000_000
24 | visible: true
25 | deposit_enabled: true
26 | withdrawal_enabled: true
27 | # Deposits with less amount are skipped during blockchain synchronization.
28 | # We advise to set value 10 times bigger than the network fee to prevent losses.
29 | min_deposit_amount: 0.00021
30 | min_collection_amount: 0.00021
31 | withdraw_limit_24h: 0.2
32 | withdraw_limit_72h: 0.5
33 | deposit_fee: 0
34 | withdraw_fee: 0
35 | position: 3
36 | options:
37 | # ETH tx fees configurations.
38 | #
39 | # Maximum amount of gas you're willing to spend on a particular transaction.
40 | gas_limit: 21_000
41 | # Internal price that is paid for running a transaction on the Ethereum network.
42 | gas_price: 1_000_000_000
43 |
44 | - id: trst
45 | name: WeTrust
46 | blockchain_key: eth-<%= @config['parity']['network'] %>
47 | type: coin
48 | precision: 8
49 | base_factor: 1_000_000 # IMPORTANT: Don't forget to update this variable according
50 | # to your ERC20-based currency requirements
51 | # (usually can be found on the official website).
52 | visible: true
53 | deposit_enabled: true
54 | withdrawal_enabled: true
55 | # Deposits with less amount are skipped during blockchain synchronization.
56 | # We advise to set value 10 times bigger than the network fee to prevent losses.
57 | # NOTE: Network fee is paid in ETH but min_deposit_amount is in TRST.
58 | min_deposit_amount: 2
59 | min_collection_amount: 2
60 | withdraw_limit_24h: 300 # (usually can be found on the official website).
61 | withdraw_limit_72h: 600
62 | deposit_fee: 0
63 | withdraw_fee: 0
64 | position: 4
65 | options:
66 | # ERC20 tx fees configurations.
67 | #
68 | # Maximum amount of gas you're willing to spend on a particular transaction.
69 | gas_limit: 90_000
70 | # Internal price that is paid for running a contract on the Ethereum network.
71 | gas_price: 1_000_000_000
72 | #
73 | # ERC20 configuration.
74 | erc20_contract_address: '0x87099add3bcc0821b5b151307c147215f839a110' # Always wrap this value in quotes!
75 | <% if @config['bitcoind']['enabled'] %>
76 | - id: btc
77 | name: Bitcoin
78 | blockchain_key: btc-<%= @config['bitcoind']['network'] %>
79 | type: coin
80 | precision: 8
81 | base_factor: 100_000_000
82 | visible: true
83 | deposit_enabled: true
84 | withdrawal_enabled: true
85 | # Deposits with less amount are skipped during blockchain synchronization.
86 | # We advise to set value 10 times bigger than the network fee to prevent losses.
87 | min_deposit_amount: 0.0000356
88 | min_collection_amount: 0.0000356
89 | withdraw_limit_24h: 0.1
90 | withdraw_limit_72h: 0.2
91 | deposit_fee: 0
92 | withdraw_fee: 0
93 | position: 2
94 | options: {}
95 | <% end %>
96 |
--------------------------------------------------------------------------------
/templates/config/peatio/seed/engines.yml.erb:
--------------------------------------------------------------------------------
1 | - name: peatio-default-engine
2 | driver: peatio
3 | state: online
4 | - name: local-finex-spot-engine
5 | driver: finex-spot
6 | state: online
7 | - name: opendax-finex-spot-engine
8 | driver: opendax
9 | url: https://www.opendax.io/api/v2/finex
10 | key: ""
11 | secret: ""
12 | # The data field for store some special data engine
13 | # Can be used in upstream worker
14 | data: |
15 | {
16 | "rest"=>"https://www.opendax.io/api/v2/finex",
17 | "websocket"=>"wss://www.opendax.io/api/v2/ranger",
18 | "trade_proxy"=>true,
19 | }
20 | state: online
21 |
--------------------------------------------------------------------------------
/templates/config/peatio/seed/markets.yml.erb:
--------------------------------------------------------------------------------
1 | - id: ethusd
2 | engine_name: peatio-default-engine
3 | base_unit: eth
4 | quote_unit: usd
5 | amount_precision: 5
6 | price_precision: 2
7 | min_price: 0.01
8 | max_price: 1000.0
9 | min_amount: 0.00001
10 | position: 2
11 | state: enabled
12 | data: {}
13 |
--------------------------------------------------------------------------------
/templates/config/peatio/seed/trading_fees.yml.erb:
--------------------------------------------------------------------------------
1 | - market_id: any
2 | group: any
3 | maker: 0.002
4 | taker: 0.002
5 |
6 | - market_id: any
7 | group: vip-0
8 | maker: 0.001
9 | taker: 0.002
10 |
11 | - market_id: any
12 | group: vip-1
13 | maker: 0.0008
14 | taker: 0.0018
15 |
16 | - market_id: any
17 | group: vip-2
18 | maker: 0.0006
19 | taker: 0.0016
20 |
21 | - market_id: any
22 | group: vip-3
23 | maker: 0.0
24 | taker: 0.0014
25 |
--------------------------------------------------------------------------------
/templates/config/peatio/seed/wallets.yml.erb:
--------------------------------------------------------------------------------
1 | <% @config['wallets']['eth'].each do |wallet| -%>
2 | - name: Ethereum <%= wallet['kind'].capitalize %> Wallet
3 | blockchain_key: eth-<%= @config['parity']['network'] %>
4 | currency_ids: eth,trst
5 | address: '<%= wallet['address'] %>'
6 | kind: <%= wallet['kind'] %>
7 | max_balance: <%= wallet['max_balance'] %>
8 | status: active
9 | gateway: parity
10 | settings:
11 | uri: http://<%= @config['parity']['address'] %>:<%= @config['parity']['rpcport'] %>
12 | secret: '<%= wallet['secret'] %>'
13 | <% end %>
14 |
15 | <% if @config['bitcoind']['enabled'] %>
16 | <% @config['wallets']['btc'].each do |wallet| -%>
17 | - name: Bitcoin <%= wallet['kind'].capitalize %> Wallet
18 | blockchain_key: btc-<%= @config['bitcoind']['network'] %>
19 | currency_ids: btc
20 | address: '<%= wallet['address'] %>'
21 | kind: <%= wallet['kind'] %>
22 | max_balance: <%= wallet['max_balance'] %>
23 | status: active
24 | gateway: bitcoind
25 | settings:
26 | uri: http://<%= @config['bitcoind']['rpcuser'] %>:<%= @config['bitcoind']['rpcpassword'] %>@<%= @config['bitcoind']['address'] %>:<%= @config['bitcoind']['rpcport'] %>
27 | <% end %>
28 | <% end %>
29 |
--------------------------------------------------------------------------------
/templates/config/rango.env.erb:
--------------------------------------------------------------------------------
1 | RANGER_HOST=0.0.0.0
2 | RANGER_PORT=8080
3 | RANGER_CONNECT_SECURE="false"
4 |
5 | LOG_LEVEL=info
6 |
7 | RABBITMQ_HOST=rabbitmq
8 |
9 | JWT_PUBLIC_KEY=<%= @barong_public_key %>
10 |
--------------------------------------------------------------------------------
/templates/config/toolbox.yaml.erb:
--------------------------------------------------------------------------------
1 | # For other configuration options, see https://github.com/rubykube/toolbox/blob/master/bin/stress_trading
2 |
3 | root-url: http://www.wb.local
4 |
5 | currencies: usd,eur
6 | markets: eurusd
7 |
8 | orders: 100
9 | traders: 10
10 | threads: 5
11 | management-api-v1-jwt-signer: toolbox
12 | api-v2-jwt-key: "<%= @barong_private_key %>"
13 | management-api-v1-jwt-key: "<%= @toolbox_jwt_private_key %>"
14 |
--------------------------------------------------------------------------------
/templates/config/vault/barong.hcl.erb:
--------------------------------------------------------------------------------
1 | # Access system health status
2 | path "sys/health" {
3 | capabilities = ["read", "list"]
4 | }
5 | # Manage the transit secrets engine
6 | path "transit/keys/<%= @config['app']['name'].downcase %>_*" {
7 | capabilities = ["create", "read", "list"]
8 | }
9 | # Encrypt API keys
10 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_apikeys_*" {
11 | capabilities = ["create", "read", "update"]
12 | }
13 | # Decrypt API keys
14 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_apikeys_*" {
15 | capabilities = ["create", "read", "update"]
16 | }
17 | # Renew tokens
18 | path "auth/token/renew" {
19 | capabilities = ["update"]
20 | }
21 | # Lookup tokens
22 | path "auth/token/lookup" {
23 | capabilities = ["update"]
24 | }
25 | # Manage otp keys
26 | path "totp/keys/<%= @config['app']['name'].downcase %>_*" {
27 | capabilities = ["create", "read", "update", "delete"]
28 | }
29 | # Verify an otp code
30 | path "totp/code/<%= @config['app']['name'].downcase %>_*" {
31 | capabilities = ["update"]
32 | }
33 |
--------------------------------------------------------------------------------
/templates/config/vault/finex_engine.hcl.erb:
--------------------------------------------------------------------------------
1 | path "transit/<%= @config['app']['name'].downcase %>_*" {
2 | capabilities = [ "read" ]
3 | }
4 | # Decrypt secrets
5 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_*" {
6 | capabilities = [ "create", "update" ]
7 | }
8 | # Use key for signing
9 | path "transit/sign/<%= @config['app']['name'].downcase %>_*" {
10 | capabilities = ["update"]
11 | }
12 | # Create transit key
13 | path "transit/keys/<%= @config['app']['name'].downcase %>_*" {
14 | capabilities = ["create"]
15 | }
16 | # Renew tokens
17 | path "auth/token/renew" {
18 | capabilities = ["update"]
19 | }
20 | # Lookup tokens
21 | path "auth/token/lookup" {
22 | capabilities = ["update"]
23 | }
24 |
--------------------------------------------------------------------------------
/templates/config/vault/peatio_crypto.hcl.erb:
--------------------------------------------------------------------------------
1 | # Manage the transit secrets engine
2 | path "transit/keys/<%= @config['app']['name'].downcase %>_*" {
3 | capabilities = ["create", "read", "list"]
4 | }
5 | # Encrypt Payment Addresses secrets
6 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_payment_addresses_*" {
7 | capabilities = ["create", "read", "update"]
8 | }
9 | # Decrypt Payment Addresses secrets
10 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_payment_addresses_*" {
11 | capabilities = ["create", "read", "update"]
12 | }
13 | # Decrypt wallets secrets
14 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_wallets_*" {
15 | capabilities = ["create", "read", "update"]
16 | }
17 | # Encrypt blockchains data
18 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_blockchains_*" {
19 | capabilities = ["create", "read", "update"]
20 | }
21 | # Decrypt blockchains data
22 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_blockchains_*" {
23 | capabilities = ["create", "read", "update"]
24 | }
25 | # Renew tokens
26 | path "auth/token/renew" {
27 | capabilities = ["update"]
28 | }
29 | # Lookup tokens
30 | path "auth/token/lookup" {
31 | capabilities = ["update"]
32 | }
33 |
--------------------------------------------------------------------------------
/templates/config/vault/peatio_matching.hcl.erb:
--------------------------------------------------------------------------------
1 | path "transit/<%= @config['app']['name'].downcase %>_*" {
2 | capabilities = [ "read" ]
3 | }
4 | # Decrypt secrets
5 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_*" {
6 | capabilities = [ "create", "update" ]
7 | }
8 | # Use key for signing
9 | path "transit/sign/<%= @config['app']['name'].downcase %>_*" {
10 | capabilities = ["update"]
11 | }
12 | # Create transit key
13 | path "transit/keys/<%= @config['app']['name'].downcase %>_*" {
14 | capabilities = ["create"]
15 | }
16 | # Renew tokens
17 | path "auth/token/renew" {
18 | capabilities = ["update"]
19 | }
20 | # Lookup tokens
21 | path "auth/token/lookup" {
22 | capabilities = ["update"]
23 | }
24 |
--------------------------------------------------------------------------------
/templates/config/vault/peatio_rails.hcl.erb:
--------------------------------------------------------------------------------
1 | # Manage the transit secrets engine
2 | path "transit/keys/<%= @config['app']['name'].downcase %>_*" {
3 | capabilities = ["create", "read", "list"]
4 | }
5 | # Encrypt engines secrets
6 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_engines_*" {
7 | capabilities = ["create", "read", "update"]
8 | }
9 | # Encrypt blockchains data
10 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_blockchains_*" {
11 | capabilities = ["create", "read", "update"]
12 | }
13 | # Decrypt blockchains data
14 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_blockchains_*" {
15 | capabilities = ["create", "read", "update"]
16 | }
17 | # Encrypt wallets secrets
18 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_wallets_*" {
19 | capabilities = ["create", "read", "update"]
20 | }
21 | # Encrypt beneficiaries data
22 | path "transit/encrypt/<%= @config['app']['name'].downcase %>_beneficiaries_*" {
23 | capabilities = [ "create", "read", "update" ]
24 | }
25 | # Decrypt beneficiaries data
26 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_beneficiaries_*" {
27 | capabilities = [ "create", "read", "update" ]
28 | }
29 | # Renew tokens
30 | path "auth/token/renew" {
31 | capabilities = ["update"]
32 | }
33 | # Lookup tokens
34 | path "auth/token/lookup" {
35 | capabilities = ["update"]
36 | }
37 | # Verify an otp code
38 | path "totp/code/<%= @config['app']['name'].downcase %>_*" {
39 | capabilities = ["update"]
40 | }
41 |
--------------------------------------------------------------------------------
/templates/config/vault/peatio_upstream.hcl.erb:
--------------------------------------------------------------------------------
1 | # Manage the transit secrets engine
2 | path "transit/keys/<%= @config['app']['name'].downcase %>_*" {
3 | capabilities = ["create", "read", "list"]
4 | }
5 | # Decrypt Engines secrets
6 | path "transit/decrypt/<%= @config['app']['name'].downcase %>_engines_*" {
7 | capabilities = ["create", "read", "update"]
8 | }
9 | # Renew tokens
10 | path "auth/token/renew" {
11 | capabilities = ["update"]
12 | }
13 | # Lookup tokens
14 | path "auth/token/lookup" {
15 | capabilities = ["update"]
16 | }
17 |
--------------------------------------------------------------------------------
/templates/terraform/terraform.tfvars.erb:
--------------------------------------------------------------------------------
1 | credentials = "<%= @config['terraform']['credentials'] %>"
2 | project = "<%= @config['terraform']['project'] %>"
3 | region = "<%= @config['terraform']['region'] %>"
4 | zone = "<%= @config['terraform']['zone'] %>"
5 | ssh_user = "deploy"
6 | ssh_public_key = "../config/secrets/app.key.pub"
7 | ssh_private_key = "../config/secrets/app.key"
8 | instance_name = "<%= @config['terraform']['instance_name'] %>"
9 | machine_type = "<%= @config['terraform']['machine_type'] %>"
10 | image = "<%= @config['terraform']['image'] %>"
11 |
--------------------------------------------------------------------------------
/templates/webhook.service:
--------------------------------------------------------------------------------
1 | [Unit]
2 | Description=OpenDax Webhook service
3 |
4 | [Service]
5 | User=deploy
6 | Environment="WEBHOOK_JWT_SECRET=GENERATED_HMAC_SECRET"
7 | ExecStart=/bin/bash -c "source ~/.rvm/scripts/rvm; bundle exec rackup config.ru"
8 | Type=simple
9 | Restart=always
10 | WorkingDirectory=OPENDAX_DIRECTORY
11 |
12 | [Install]
13 | WantedBy=multi-user.target
14 |
--------------------------------------------------------------------------------
/terraform/main.tf:
--------------------------------------------------------------------------------
1 | provider "google" {
2 | credentials = file(var.credentials)
3 | project = var.project
4 | region = var.region
5 | }
6 |
7 | provider "random" {
8 | }
9 |
10 | resource "random_id" "opendax" {
11 | byte_length = 2
12 | }
13 |
14 | resource "google_compute_instance" "opendax" {
15 | name = "${var.instance_name}-${random_id.opendax.hex}"
16 | machine_type = var.machine_type
17 | zone = var.zone
18 |
19 | allow_stopping_for_update = true
20 |
21 | boot_disk {
22 | initialize_params {
23 | image = var.image
24 | type = "pd-ssd"
25 | size = 120
26 | }
27 | }
28 |
29 | network_interface {
30 | network = google_compute_network.opendax.name
31 |
32 | access_config {
33 | nat_ip = google_compute_address.opendax.address
34 | }
35 | }
36 |
37 | service_account {
38 | scopes = ["storage-ro"]
39 | }
40 |
41 | tags = ["allow-webhook"]
42 |
43 | metadata = {
44 | sshKeys = "${var.ssh_user}:${file(var.ssh_public_key)}"
45 | }
46 |
47 | provisioner "local-exec" {
48 | command = "mkdir -p /tmp/upload && rsync -rv --exclude=terraform ../ /tmp/upload/"
49 | }
50 |
51 | provisioner "remote-exec" {
52 | inline = [
53 | "mkdir -p /home/${var.ssh_user}/opendax",
54 | ]
55 |
56 | connection {
57 | host = self.network_interface[0].access_config[0].nat_ip
58 | type = "ssh"
59 | user = var.ssh_user
60 | private_key = file(var.ssh_private_key)
61 | }
62 | }
63 |
64 | provisioner "file" {
65 | source = "/tmp/upload/"
66 | destination = "/home/${var.ssh_user}/opendax"
67 |
68 | connection {
69 | host = self.network_interface[0].access_config[0].nat_ip
70 | type = "ssh"
71 | user = var.ssh_user
72 | private_key = file(var.ssh_private_key)
73 | }
74 | }
75 |
76 | provisioner "remote-exec" {
77 | script = "../bin/install.sh"
78 |
79 | connection {
80 | host = self.network_interface[0].access_config[0].nat_ip
81 | type = "ssh"
82 | user = var.ssh_user
83 | private_key = file(var.ssh_private_key)
84 | }
85 | }
86 |
87 | provisioner "remote-exec" {
88 | script = "../bin/start.sh"
89 |
90 | connection {
91 | host = self.network_interface[0].access_config[0].nat_ip
92 | type = "ssh"
93 | user = var.ssh_user
94 | private_key = file(var.ssh_private_key)
95 | }
96 | }
97 | }
98 |
99 | resource "google_compute_firewall" "opendax" {
100 | name = "opendax-firewall-${random_id.opendax.hex}"
101 | network = google_compute_network.opendax.name
102 |
103 | allow {
104 | protocol = "tcp"
105 | ports = ["80", "8080", "1337", "443", "22"]
106 | }
107 |
108 | source_ranges = ["0.0.0.0/0"]
109 |
110 | target_tags = ["allow-webhook"]
111 | }
112 |
113 | resource "google_compute_address" "opendax" {
114 | name = "opendax-ip-${random_id.opendax.hex}"
115 | }
116 |
117 | resource "google_compute_network" "opendax" {
118 | name = "opendax-network-${random_id.opendax.hex}"
119 | }
120 |
121 |
--------------------------------------------------------------------------------
/terraform/variables.tf:
--------------------------------------------------------------------------------
1 | variable "credentials" {
2 | type = string
3 | }
4 |
5 | variable "ssh_user" {
6 | type = string
7 | description = "Name of the SSH user to use"
8 | default = "app"
9 | }
10 |
11 | variable "ssh_public_key" {
12 | type = string
13 | description = "Location of the public RSA key used for SSH-ing onto the main VM"
14 | }
15 |
16 | variable "ssh_private_key" {
17 | type = string
18 | description = "Location of the private RSA key used for SSH-ing onto the main VM"
19 | }
20 |
21 | variable "project" {
22 | type = string
23 | }
24 |
25 | variable "region" {
26 | type = string
27 | }
28 |
29 | variable "zone" {
30 | type = string
31 | }
32 |
33 | variable "machine_type" {
34 | type = string
35 | }
36 |
37 | variable "instance_name" {
38 | type = string
39 | }
40 |
41 | variable "image" {
42 | type = string
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/vendor/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/openware/opendax/e204b565e6879bf5afcd3450a93e5d226262d6a6/vendor/.gitkeep
--------------------------------------------------------------------------------