Initial commit

This commit is contained in:
Yaser
2026-08-13 19:42:08 +03:30
commit d59bf30ef0
173 changed files with 11702 additions and 0 deletions

6
.dockerignore Normal file
View File

@@ -0,0 +1,6 @@
Dockerfile
.dockerignore
.git
.gitignore
LICENSE
README

31
.drone.yml Normal file
View File

@@ -0,0 +1,31 @@
kind: pipeline
name: default
steps:
- name: Run rspec
image: ruby:2.6.5
commands:
- gem install bundler
- bundle
- bundle exec rspec
when:
event:
- pull_request
- name: Bump and tag
image: quay.io/openware/sdk-tools:0.0.3
environment:
BRANCH_NAME: ${DRONE_BRANCH}
REPO_NAME: ${DRONE_REPO}
BOT_USERNAME: kite-bot
BOT_NAME: Kite Bot
BOT_EMAIL: kite-bot@heliostech.fr
GITHUB_API_KEY:
from_secret: kite_bot_key
commands:
- BUNDLE_GEMFILE=/sdk/Gemfile bundle exec rake --rakefile=/sdk/Rakefile release:push
when:
event: [push]
branch: [master]
image_pull_secrets:
- dockerconfigjson

9
.env.example Normal file
View File

@@ -0,0 +1,9 @@
# Generated by `rake render:config` — do not edit manually.
# Copy from .env.example on first setup, then run render:config.
COMPOSE_PROJECT_NAME=fibitex
# Linux/macOS: use colon. Windows: use semicolon (see Docs/06-setup-local.md).
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
PEATIO_RAILS_VAULT_TOKEN=changeme
PEATIO_CRYPTO_VAULT_TOKEN=changeme
PEATIO_UPSTREAM_VAULT_TOKEN=changeme
PEATIO_MATCHING_VAULT_TOKEN=changeme

28
.gitignore vendored Normal file
View File

@@ -0,0 +1,28 @@
config/acme.json
config/frontend/*.js
config/gateway/mapping.yaml
config/peatio/management_api_v1.yml
config/barong/management_api.yml
config/finex/*
config/toolbox.yaml
config/traefik.toml
config/*.env
config/secrets/*
!config/secrets/.gitkeep
config/peatio/seed/*
!config/peatio/seed/.gitkeep
!config/peatio/seed/markets.yml
!config/peatio/seed/currencies.yml
config/applogic/*
!config/applogic/.gitkeep
config/app.local.yml
config/app.staging.yml
config/app.production.yml
config/vault-secrets.yml
.env
vendor/
!vendor/.gitkeep
.terraform/
*.tfvars
terraform.tfstate*
!data/parity/.gitkeep

10
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# CodeStream ignored files
/codestream.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

134
.idea/alvandp.iml generated Normal file
View File

@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="RUBY_MODULE" version="4">
<component name="ModuleRunConfigurationManager">
<shared />
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/features" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
</content>
<orderEntry type="jdk" jdkName="RVM: ruby-2.6.6" jdkType="RUBY_SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="PROVIDED" name="bump (v0.9.0, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="diff-lcs (v1.3, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="faraday (v1.0.0, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="jwt (v2.2.1, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="multipart-post (v2.1.1, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="mustermann (v1.1.1, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="nio4r (v2.5.2, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="puma (v4.3.3, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rack (v2.2.2, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rack-protection (v2.0.8.1, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rake (v13.0.1, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rspec (v3.9.0, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rspec-core (v3.9.1, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rspec-expectations (v3.9.0, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rspec-mocks (v3.9.1, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rspec-support (v3.9.2, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="ruby2_keywords (v0.0.2, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="sinatra (v2.0.8.1, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="sshkey (v2.0.0, RVM: ruby-2.6.6) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="tilt (v2.0.10, RVM: ruby-2.6.6) [gem]" level="application" />
</component>
<component name="RakeTasksCache">
<option name="myRootTask">
<RakeTaskImpl id="rake">
<subtasks>
<RakeTaskImpl id="db">
<subtasks>
<RakeTaskImpl description="Database Console" fullCommand="db:console" id="console" />
<RakeTaskImpl description="Create database" fullCommand="db:create" id="create" />
<RakeTaskImpl description="Drop all databases" fullCommand="db:drop" id="drop" />
<RakeTaskImpl description="Load database dump" fullCommand="db:load" id="load" />
</subtasks>
</RakeTaskImpl>
<RakeTaskImpl id="docker">
<subtasks>
<RakeTaskImpl description="Clean up all docker volumes" fullCommand="docker:clean" id="clean" />
<RakeTaskImpl description="Stop all runnning docker contrainers" fullCommand="docker:down" id="down" />
</subtasks>
</RakeTaskImpl>
<RakeTaskImpl id="payload">
<subtasks>
<RakeTaskImpl description="Generate JWT" fullCommand="payload:send[service,image,url]" id="send[service,image,url]" />
<RakeTaskImpl description="" fullCommand="payload:send" id="send" />
</subtasks>
</RakeTaskImpl>
<RakeTaskImpl id="render">
<subtasks>
<RakeTaskImpl description="Render configuration and compose files and keys" fullCommand="render:config" id="config" />
</subtasks>
</RakeTaskImpl>
<RakeTaskImpl id="service">
<subtasks>
<RakeTaskImpl description="Set up and start all services with dependencies (does not run optional ones)" fullCommand="service:all[command]" id="all[command]" />
<RakeTaskImpl description="Run mikro app (barong, peatio)" fullCommand="service:app[command]" id="app[command]" />
<RakeTaskImpl description="[Optional] Run arke-maker" fullCommand="service:arke_maker[command]" id="arke_maker[command]" />
<RakeTaskImpl description="Run backend (vault db redis rabbitmq)" fullCommand="service:backend[command]" id="backend[command]" />
<RakeTaskImpl description="[Optional] Run cryptonodes" fullCommand="service:cryptonodes[command]" id="cryptonodes[command]" />
<RakeTaskImpl description="[Optional] Run daemons (rango, peatio daemons, barong sidekiq)" fullCommand="service:daemons[command]" id="daemons[command]" />
<RakeTaskImpl description="Run the frontend application" fullCommand="service:frontend[command]" id="frontend[command]" />
<RakeTaskImpl description="Run influxdb" fullCommand="service:influxdb[command]" id="influxdb[command]" />
<RakeTaskImpl description="[Optional] Run monitoring" fullCommand="service:monitoring[command]" id="monitoring[command]" />
<RakeTaskImpl description="Run Traefik (reverse-proxy)" fullCommand="service:proxy[command]" id="proxy[command]" />
<RakeTaskImpl description="Run setup hooks for peatio, barong" fullCommand="service:setup[command]" id="setup[command]" />
<RakeTaskImpl description="[Optional] Run superset" fullCommand="service:superset[command]" id="superset[command]" />
<RakeTaskImpl description="Run the tower application" fullCommand="service:tower[command]" id="tower[command]" />
<RakeTaskImpl description="[Optional] Run utils (mailer)" fullCommand="service:utils[command]" id="utils[command]" />
<RakeTaskImpl description="" fullCommand="service:all" id="all" />
<RakeTaskImpl description="" fullCommand="service:app" id="app" />
<RakeTaskImpl description="" fullCommand="service:arke_maker" id="arke_maker" />
<RakeTaskImpl description="" fullCommand="service:backend" id="backend" />
<RakeTaskImpl description="" fullCommand="service:cryptonodes" id="cryptonodes" />
<RakeTaskImpl description="" fullCommand="service:daemons" id="daemons" />
<RakeTaskImpl description="" fullCommand="service:frontend" id="frontend" />
<RakeTaskImpl description="" fullCommand="service:influxdb" id="influxdb" />
<RakeTaskImpl description="" fullCommand="service:monitoring" id="monitoring" />
<RakeTaskImpl description="" fullCommand="service:proxy" id="proxy" />
<RakeTaskImpl description="" fullCommand="service:setup" id="setup" />
<RakeTaskImpl description="" fullCommand="service:superset" id="superset" />
<RakeTaskImpl description="" fullCommand="service:tower" id="tower" />
<RakeTaskImpl description="" fullCommand="service:utils" id="utils" />
</subtasks>
</RakeTaskImpl>
<RakeTaskImpl id="terraform">
<subtasks>
<RakeTaskImpl description="Apply the Terraform configuration" fullCommand="terraform:apply" id="apply" />
<RakeTaskImpl description="Destroy the Terraform infrastructure" fullCommand="terraform:destroy" id="destroy" />
<RakeTaskImpl description="Initialize the Terraform configuration" fullCommand="terraform:init" id="init" />
</subtasks>
</RakeTaskImpl>
<RakeTaskImpl id="toolbox">
<subtasks>
<RakeTaskImpl description="Run the toolbox" fullCommand="toolbox:run" id="run" />
</subtasks>
</RakeTaskImpl>
<RakeTaskImpl id="vault">
<subtasks>
<RakeTaskImpl description="Initialize, unseal and set secrets for Vault" fullCommand="vault:setup" id="setup" />
<RakeTaskImpl description="" fullCommand="vault:load_policies" id="load_policies" />
</subtasks>
</RakeTaskImpl>
<RakeTaskImpl id="vendor">
<subtasks>
<RakeTaskImpl description="Clone the frontend apps repos into vendor/" fullCommand="vendor:clone" id="clone" />
</subtasks>
</RakeTaskImpl>
<RakeTaskImpl id="versions">
<subtasks>
<RakeTaskImpl description="Fetch global image versions and update config/app.yaml" fullCommand="versions:update" id="update" />
</subtasks>
</RakeTaskImpl>
<RakeTaskImpl id="wallet">
<subtasks>
<RakeTaskImpl description="Generate ethereum wallet from a cryptonode" fullCommand="wallet:create[kind,url,secret]" id="create[kind,url,secret]" />
<RakeTaskImpl description="" fullCommand="wallet:create" id="create" />
</subtasks>
</RakeTaskImpl>
</subtasks>
</RakeTaskImpl>
</option>
</component>
</module>

4
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="RVM: ruby-3.0.0" project-jdk-type="RUBY_SDK" />
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/alvandp.iml" filepath="$PROJECT_DIR$/.idea/alvandp.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

1
.rspec Normal file
View File

@@ -0,0 +1 @@
--require spec_helper

1
.ruby-version Normal file
View File

@@ -0,0 +1 @@
ruby-2.6.6

17
Dockerfile Normal file
View File

@@ -0,0 +1,17 @@
FROM ruby:2.6.1
ENV APP_HOME=/home/app
ARG UID=1000
ARG GID=1000
RUN groupadd -r --gid ${GID} app \
&& useradd --system --create-home --home ${APP_HOME} --shell /sbin/nologin --no-log-init \
--gid ${GID} --uid ${UID} app
USER app
WORKDIR $APP_HOME
COPY --chown=app:app . .
RUN bundle install --jobs=$(nproc) --deployment

19
Gemfile Normal file
View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
ruby '~>2.6'
gem 'rake'
gem 'sshkey' # SSH key generation gem
# webhook server deps
gem 'bump'
gem 'rack'
gem 'sinatra'
gem 'puma'
gem 'rspec'
gem 'jwt'
gem 'faraday'

59
Gemfile.lock Normal file
View File

@@ -0,0 +1,59 @@
GEM
remote: https://rubygems.org/
specs:
bump (0.9.0)
diff-lcs (1.3)
faraday (1.0.0)
multipart-post (>= 1.2, < 3)
jwt (2.2.1)
multipart-post (2.1.1)
mustermann (1.1.1)
ruby2_keywords (~> 0.0.1)
nio4r (2.5.2)
puma (4.3.3)
nio4r (~> 2.0)
rack (2.2.2)
rack-protection (2.0.8.1)
rack
rake (13.0.1)
rspec (3.9.0)
rspec-core (~> 3.9.0)
rspec-expectations (~> 3.9.0)
rspec-mocks (~> 3.9.0)
rspec-core (3.9.1)
rspec-support (~> 3.9.1)
rspec-expectations (3.9.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-mocks (3.9.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.9.0)
rspec-support (3.9.2)
ruby2_keywords (0.0.2)
sinatra (2.0.8.1)
mustermann (~> 1.0)
rack (~> 2.0)
rack-protection (= 2.0.8.1)
tilt (~> 2.0)
sshkey (2.0.0)
tilt (2.0.10)
PLATFORMS
ruby
DEPENDENCIES
bump
faraday
jwt
puma
rack
rake
rspec
sinatra
sshkey
RUBY VERSION
ruby 2.6.3p62
BUNDLED WITH
2.1.4

201
LICENSE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

83
README.md Normal file
View File

@@ -0,0 +1,83 @@
<div dir="rtl">
# Alvand-P — ارکستراسیون Fibitex
**Alvand-P** فورک [OpenDAX](https://github.com/openware/opendax) برای صرافی **Fibitex** است: compose، Vault، Traefik، و render قالب‌ها.
| OpenDAX | Fibitex |
|---------|---------|
| OpenDAX | Alvand-P |
| Peatio | [Dena](../Dena/) |
| Barong | [Dalan](../Dalan/) |
| BaseApp | [Gereh](../Gereh/) / [Shahoo](../Shahoo/) |
## پیش‌نیازها
- Docker Compose v2، Ruby 2.6 + Bundler
- Linux/macOS (staging: Ubuntu) یا Windows + Docker Desktop
- Vault unseal keys (staging/production)
## راه‌اندازی سریع
<div dir="ltr">
```bash
cd Alvand-P
bundle install
cp config/app.local.yml.example config/app.local.yml # لوکال
rake render:config
rake service:all
```
</div>
لوکال Windows: [`start-fibitex.bat`](../start-fibitex.bat) از ریشه Main code.
Staging: [`Docs/Fibitex-staging-deploy.md`](../Docs/Fibitex-staging-deploy.md)
## مستندات
| سند | موضوع |
|-----|--------|
| [`Docs/Fibitex-staging-deploy.md`](../Docs/Fibitex-staging-deploy.md) | Deploy staging (منبع حقیقت) |
| [`Docs/06-setup-local.md`](../Docs/06-setup-local.md) | لوکال Docker |
| [`Docs/07-setup-server.md`](../Docs/07-setup-server.md) | Production |
| [`Docs/05-alvand-p-platform.md`](../Docs/05-alvand-p-platform.md) | معماری Alvand-P |
| [`Docs/QA-troubleshooting.md`](Docs/QA-troubleshooting.md) | عیب‌یابی عملیاتی |
| [`Docs/troubleshoot-barong-authz.md`](Docs/troubleshoot-barong-authz.md) | Barong authz |
| [`Docs/ubuntu-install.md`](Docs/ubuntu-install.md) | نصب Ubuntu |
| [`Docs/README.md`](../Docs/README.md) | فهرست مرکزی |
## دستورات پرکاربرد
<div dir="ltr">
```bash
rake render:config
rake service:all
docker compose -p fibitex up -d --force-recreate # بعد از تغییر logging
rake vault:load_policies
rake service:monitoring # all monitoring service up
```
</div>
## Log rotation
Templateهای compose tierهای `noisy` (10m×3) و `quiet` (5m×2) دارند. بعد از تغییر: `render:config` + `--force-recreate`. جزئیات: Fibitex staging deploy §۸.۳.
---
</div>
<details>
<summary>OpenDAX upstream README (مرجع)</summary>
![Cryptocurrency Exchange Platform - OpenDAX](https://github.com/openware/meta/raw/main/images/github_opendax.png)
OpenDAX is an open-source cloud-native multi-service platform for building a Blockchain/FinTech exchange.
See upstream: https://github.com/openware/opendax
</details>

15
Rakefile Normal file
View File

@@ -0,0 +1,15 @@
require 'yaml'
require 'base64'
require 'erb'
require_relative 'lib/opendax/config_loader'
CONFIG_PATH = 'config/app.yml'.freeze
UTILS_PATH = 'config/utils.yml'.freeze
@config = Opendax::ConfigLoader.load
@utils = YAML.load_file(UTILS_PATH)
# Add your own tasks in files placed in lib/tasks ending in .rake
Dir.glob('lib/tasks/*.rake').each do |task|
load task
end

1
VERSION Normal file
View File

@@ -0,0 +1 @@
0.1.57

View File

@@ -0,0 +1,18 @@
# frozen_string_literal: true
email = ENV.fetch('EMAIL', 'admin@barong.io')
member = Member.find_by(email: email)
unless member
puts 'STATUS=NO_MEMBER'
exit 1
end
puts "STATUS=OK uid=#{member.uid} id=#{member.id}"
%w[usdt btc cad].each do |currency|
account = member.accounts.find_by(currency_id: currency)
next unless account
puts "ACCOUNT #{currency} balance=#{account.balance} locked=#{account.locked}"
end

4
bin/check_order.rb Normal file
View File

@@ -0,0 +1,4 @@
# frozen_string_literal: true
order = Order.find(ENV.fetch('ORDER_ID', '1'))
puts "ORDER id=#{order.id} state=#{order.state} price=#{order.price} volume=#{order.volume} origin_volume=#{order.origin_volume}"

View File

@@ -0,0 +1,20 @@
# frozen_string_literal: true
puts '--- currencies ---'
%w[irt cad usdt].each do |cid|
c = Currency.find_by(id: cid)
puts "#{cid} visible=#{c&.visible} type=#{c&.type}" if c
end
%w[user@test.com bot@test.com admin@test.com].each do |email|
member = Member.find_by(email: email)
unless member
puts "MISSING #{email}"
next
end
sample = member.accounts.where('balance > 0').limit(3).map { |a| "#{a.currency_id}=#{a.balance}" }.join(', ')
fiat = %w[irt cad].map { |c| a = member.accounts.find_by(currency_id: c); "#{c}=#{a&.balance || 0}" }.join(' ')
total = member.accounts.where('balance > 0').count
puts "#{email} uid=#{member.uid} nonzero=#{total} fiat=[#{fiat}] sample=#{sample}"
end

23
bin/create_admin_user.rb Normal file
View File

@@ -0,0 +1,23 @@
# frozen_string_literal: true
email = ENV.fetch('ADMIN_EMAIL', 'admin@test.com')
password = ENV.fetch('ADMIN_PASSWORD', '123qwe!@#QWE')
user = User.find_or_initialize_by(email: email)
user.password = password
user.role = 'superadmin'
user.state = 'active'
user.level = 3
user.otp = false
if user.save
Level.where(id: 1..Level::LEVEL_ID_BOUNDS[user.level.to_s].to_i).find_each do |level|
user.labels.find_or_create_by!(key: level.key, scope: 'private') do |label|
label.value = level.value
end
end
puts "OK email=#{user.email} uid=#{user.uid} state=#{user.state} level=#{user.level}"
else
puts "ERR #{user.errors.full_messages.join(', ')}"
exit 1
end

56
bin/install.sh Normal file
View File

@@ -0,0 +1,56 @@
#!/bin/bash -x
COMPOSE_VERSION="1.23.2"
COMPOSE_URL="https://github.com/docker/compose/releases/download/$COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)"
# Opendax bootstrap script
install_core() {
sudo bash <<EOS
apt-get update
apt-get install -y -q git tmux gnupg2 dirmngr dbus htop curl libmariadbclient-dev-compat build-essential
EOS
}
log_rotation() {
sudo bash <<EOS
mkdir -p /etc/docker
echo '
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "10"
}
}' > /etc/docker/daemon.json
EOS
}
# Docker installation
install_docker() {
curl -fsSL https://get.docker.com/ | bash
sudo bash <<EOS
usermod -a -G docker $USER
curl -L "$COMPOSE_URL" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
EOS
}
activate_gcloud() {
sudo -u deploy bash <<EOS
gcloud auth configure-docker --quiet
EOS
}
install_ruby() {
sudo -u deploy bash <<EOS
gpg2 --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
curl -sSL https://get.rvm.io | bash -s stable
EOS
}
install_core
log_rotation
install_docker
activate_gcloud
install_ruby

10
bin/install_webhook Normal file
View File

@@ -0,0 +1,10 @@
SECRET=$(ruby -rsecurerandom -e 'puts SecureRandom.hex(20)')
sed s/GENERATED_HMAC_SECRET/${SECRET}/g templates/webhook.service > webhook.service
sed -i s#OPENDAX_DIRECTORY#${PWD}#g webhook.service
echo "Generated Secret: ${SECRET}"
sudo mv ./webhook.service /etc/systemd/system/webhook.service
sudo systemctl daemon-reload
sudo systemctl start webhook

7
bin/quick-test.sh Normal file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
set -e
http --session barong POST http://www.app.local/api/v2/barong/identity/sessions email='iron@man.io' password='0lDHd9ufs9t@'
http --session barong GET http://www.app.local/api/v2/barong/resource/users/me
http --session barong GET http://www.app.local/api/v2/peatio/account/balances

110
bin/seed_test_balances.rb Normal file
View File

@@ -0,0 +1,110 @@
# frozen_string_literal: true
# Credits test user balances in Peatio (Dena).
# Run: bundle exec rails runner lib/seed_test_balances.rb
require 'yaml'
require 'json'
require 'bigdecimal'
def test_seed_enabled?
ENV.fetch('FIBITEX_SEED_TEST_USERS', 'true') != 'false'
end
unless test_seed_enabled?
puts 'SKIP seed_test_balances (FIBITEX_SEED_TEST_USERS=false)'
exit 0
end
config_path = [
ENV['TEST_USERS_CONFIG'],
File.expand_path('../config/test_users.yml', __dir__),
'/opt/peatio/config/test_users.yml'
].compact.find { |p| File.exist?(p) }
unless config_path
puts "ERR missing config: #{config_path}"
exit 1
end
config = YAML.safe_load(File.read(config_path))
fiat_ids = %w[irt cad]
def min_order_amounts_by_currency
mins = {}
Market.find_each do |market|
next unless market.state == 'enabled'
amount = market.min_amount.to_d
next if amount <= 0
cur = market.base_unit
mins[cur] = mins[cur] ? [mins[cur], amount].min : amount
end
mins
end
def ensure_member!(entry, barong_role: 'member')
email = entry['email']
uid = entry['uid']
member = Member.find_or_initialize_by(email: email)
member.uid = uid if uid.present?
member.role = barong_role
member.level = entry['level'] || 0
member.state = 'active'
member.group = entry['peatio_group'] || 'vip-0'
member.save!
member
end
def sync_account_balance!(account, target)
target = target.to_d
current = account.balance.to_d
return if current == target
diff = target - current
if diff > 0
account.plus_funds!(diff)
puts "CREDIT #{account.member.email} #{account.currency_id}=#{target} (added #{diff})"
elsif diff < 0 && account.respond_to?(:sub_funds!) && account.balance.to_d >= -diff
account.sub_funds!(-diff)
puts "DEBIT #{account.member.email} #{account.currency_id}=#{target} (removed #{-diff})"
else
account.update!(balance: target)
puts "SET #{account.member.email} #{account.currency_id}=#{target} (was #{current})"
end
end
min_orders = min_order_amounts_by_currency
(config['users'] || []).each do |entry|
email = entry['email']
member = ensure_member!(entry, barong_role: entry['role'] == 'superadmin' ? 'superadmin' : 'member')
coin_fixed = (entry['coin_fixed'] || {}).transform_keys(&:to_s)
Currency.find_each do |currency|
amount =
if fiat_ids.include?(currency.id)
BigDecimal(entry['fiat_balance'].to_s)
elsif coin_fixed.key?(currency.id)
BigDecimal(coin_fixed[currency.id].to_s)
else
base_min = min_orders[currency.id] || currency.min_deposit_amount.to_d
base_min = BigDecimal('1') if base_min <= 0
base_min * BigDecimal(entry['coin_multiplier'].to_s)
end
account = member.get_account(currency)
sync_account_balance!(account, amount)
end
end
puts 'DONE seed_test_balances'
(config['users'] || []).each do |entry|
member = Member.find_by(email: entry['email'])
next unless member
nonzero = member.accounts.where('balance > 0').count
puts "SUMMARY #{entry['email']} currencies_with_balance=#{nonzero}"
end

99
bin/seed_test_users.rb Normal file
View File

@@ -0,0 +1,99 @@
# frozen_string_literal: true
# Creates / updates Fibitex test users in Barong (Dalan).
# Run: bundle exec rails runner lib/seed_test_users.rb
# Guard: set FIBITEX_SEED_TEST_USERS=false to skip.
require 'yaml'
require 'json'
def test_seed_enabled?
ENV.fetch('FIBITEX_SEED_TEST_USERS', 'true') != 'false'
end
unless test_seed_enabled?
puts 'SKIP seed_test_users (FIBITEX_SEED_TEST_USERS=false)'
exit 0
end
config_path = ENV.fetch(
'TEST_USERS_CONFIG',
File.expand_path('../config/test_users.yml', __dir__)
)
unless File.exist?(config_path)
puts "ERR missing config: #{config_path}"
exit 1
end
config = YAML.safe_load(File.read(config_path))
fiat_ids = %w[irt cad]
def apply_kyc_labels!(user, kyc_mode)
Label.where(user_id: user.id, scope: 'private').delete_all
case kyc_mode.to_s
when 'zero'
bound = Level::LEVEL_ID_BOUNDS['0'].to_i
when 'full'
bound = Level::LEVEL_ID_BOUNDS[user.level.to_s].to_i
else
bound = Level::LEVEL_ID_BOUNDS[user.level.to_s].to_i
end
Level.where(id: 1..bound).find_each do |level|
user.labels.create!(key: level.key, value: level.value, scope: 'private')
end
user.update!(level: Level.what_level(user.kyc_info[:points])) if kyc_mode.to_s == 'full'
end
def sync_user_level!(user, target_level)
return if target_level.nil?
user.update!(level: target_level.to_i)
end
def remove_user!(email)
user = User.find_by(email: email)
return unless user
Label.where(user_id: user.id).delete_all
User.where(id: user.id).delete_all
puts "REMOVED #{email}"
end
(config['remove_emails'] || []).each do |email|
remove_user!(email)
end
(config['users'] || []).each do |entry|
email = entry['email']
user = User.find_or_initialize_by(email: email)
user.uid = entry['uid'] if entry['uid'].present? && user.uid.blank?
user.password = entry['password']
user.role = entry['role']
user.state = entry['state'] || 'active'
user.level = entry['level'] || 0
user.otp = false
if user.save
apply_kyc_labels!(user, entry['kyc'])
sync_user_level!(user, entry['level'])
puts "OK #{email} uid=#{user.uid} role=#{user.role} level=#{user.level} kyc=#{entry['kyc']}"
else
puts "ERR #{email}: #{user.errors.full_messages.join(', ')}"
exit 1
end
end
File.write(
File.join(Dir.tmpdir, 'fibitex_test_user_uids.json'),
JSON.pretty_generate(
(config['users'] || []).map { |u| { 'email' => u['email'], 'uid' => User.find_by!(email: u['email']).uid } }
)
)
puts 'DONE seed_test_users'

3
bin/set-env.sh Normal file
View File

@@ -0,0 +1,3 @@
export UID=$(id -u)
export GID=$(id -g)
alias dc=docker-compose

31
bin/start.sh Normal file
View File

@@ -0,0 +1,31 @@
#!/bin/bash -x
COMPOSE_VERSION="1.23.2"
COMPOSE_URL="https://github.com/docker/compose/releases/download/$COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)"
install_opendax() {
sudo -u deploy bash <<EOS
cd /home/deploy
source /home/deploy/.rvm/scripts/rvm
rvm install --quiet-curl 2.6.1
rvm use --default 2.6.1
gem install bundler
cd opendax
bundle install
rake render:config
rake service:cryptonodes && \
until rake wallet:create['deposit','http://127.0.0.1:8545','changeme']; do sleep 15; done && \
rake wallet:create['hot','http://127.0.0.1:8545','changeme'] && \
rake wallet:create['warm','http://127.0.0.1:8545','changeme'] && \
rake render:config && \
rake service:all && \
rake service:daemons && \
chmod +x bin/install_webhook
./bin/install_webhook
EOS
}
install_opendax

45
bin/sync_peatio_seed.rb Normal file
View File

@@ -0,0 +1,45 @@
# frozen_string_literal: true
# Sync Alvand-P config/peatio/seed into a running Peatio DB (insert missing rows, refresh IRT).
# Usage: bundle exec rails runner ./bin/sync_peatio_seed.rb
require 'yaml'
def seed_file(name)
Rails.root.join('config/seed', name)
end
puts '--- sync currencies ---'
YAML.load_file(seed_file('currencies.yml')).each do |hash|
id = hash.fetch('id')
currency = Currency.find_by(id: id)
if currency
currency.update!(hash.except('id'))
puts " updated currency #{id}"
else
Currency.create!(hash)
puts " created currency #{id}"
end
end
puts '--- sync markets ---'
engine = Engine.find_by!(name: 'peatio-default-engine')
YAML.load_file(seed_file('markets.yml')).map(&:symbolize_keys).each do |hash|
id = hash.fetch(:id)
enabled = hash.delete(:enabled)
hash[:state] ||= enabled ? :enabled : :disabled
hash.delete(:engine_name)
hash[:engine_id] = engine.id
market = Market.find_by(id: id)
if market
market.update!(hash.except(:id))
puts " updated market #{id} (#{hash[:state]})"
else
Market.create!(hash.except(:id).merge(id: id))
puts " created market #{id} (#{hash[:state]})"
end
end
puts '--- done ---'
puts "Markets by quote: #{Market.group(:quote_unit).count}"

33
bin/test_limit_order.rb Normal file
View File

@@ -0,0 +1,33 @@
# frozen_string_literal: true
email = ENV.fetch('EMAIL', 'admin@barong.io')
currency_id = ENV.fetch('CURRENCY', 'usdt')
amount = BigDecimal(ENV.fetch('AMOUNT', '10000'))
member = Member.find_by(email: email)
abort('NO_MEMBER') unless member
account = member.get_account(currency_id)
account.plus_funds!(amount)
puts "CREDITED #{currency_id}=#{amount} new_balance=#{account.balance}"
market = Market.find('btcusdt')
order = OrderBid.new(
state: Order::PENDING,
bid: market.quote_unit,
ask: market.base_unit,
market: market,
price: BigDecimal('50000'),
volume: BigDecimal('0.0001'),
origin_volume: BigDecimal('0.0001'),
member: member,
ord_type: 'limit'
)
begin
order.submit_order
puts "ORDER_OK id=#{order.id} state=#{order.state} price=#{order.price} volume=#{order.volume} locked=#{order.locked}"
rescue StandardError => e
puts "ORDER_FAIL #{e.class}: #{e.message}"
exit 1
end

0
compose/.gitkeep Normal file
View File

5
config.ru Normal file
View File

@@ -0,0 +1,5 @@
#\ -s Puma --host 0.0.0.0 -p 1337 -E production
require_relative 'lib/opendax/webhook'
run Webhook

View File

@@ -0,0 +1,48 @@
---
# Copy to config/app.local.yml and fill in values for local Docker development.
# cp config/app.local.yml.example config/app.local.yml
#
# After editing: rake render:config
#
app:
domain: app.local
subdomain: www
shahoo_subdomain: shahoo
shahoo_subdomain: shahoo
shahoo_subdomain: shahoo
shahoo_subdomain: shahoo
shahoo_subdomain: shahoo
render_protect: false
csrfEnabled: false
serverip:
enabled: false
ip: 127.0.0.1
ssl:
enabled: false
updateVersions: false
captchaLogin: false
captcha:
type: none
images:
peatio: custom/dena:1
barong: custom/dalan:1
frontend: custom/gereh:1
gereh: custom/gereh:1
shahoo: custom/shahoo:1
shahoo_bff: custom/shahoo-bff:1
tower: ya3er/admin_tower:2.2.66
rango: quay.io/openware/rango:2.6.1
vault:
root_token: changeme
peatio_rails_token: changeme
peatio_crypto_token: changeme
peatio_upstream_token: changeme
peatio_matching_token: changeme
barong_token: changeme
database:
password: changeme
BetaCandaTestNetwork: true
parity:
enabled: false
bitcoind:
enabled: false

View File

@@ -0,0 +1,57 @@
---
# Copy to config/app.production.yml on the production server (gitignored).
# Set OPENDAX_ENV=production before rake render:config / rake service:all.
#
# cp config/app.production.yml.example config/app.production.yml
#
app:
domain: tibitex.com
subdomain: www
serverip:
enabled: true
ip: YOUR_SERVER_PUBLIC_IP
ssl:
enabled: true
email: admin@fibitex.com
csrfEnabled: true
captchaLogin: true
captcha:
type: recaptcha
siteKey: YOUR_RECAPTCHA_SITE_KEY
secretKey: YOUR_RECAPTCHA_SECRET_KEY
database:
password: STRONG_DB_PASSWORD
vault:
root_token: changeme
peatio_rails_token: changeme
peatio_crypto_token: changeme
peatio_upstream_token: changeme
peatio_matching_token: changeme
barong_token: changeme
jibit:
key: YOUR_JIBIT_KEY
secret: YOUR_JIBIT_SECRET
kavenegar:
key: YOUR_KAVENEGAR_KEY
sender: YOUR_SENDER
vandar:
mobile: changeme
password: changeme
key: changeme
smtp:
host: mail.fibitex.com
port: 587
user: "no-reply@fibitex.com"
password: "YOUR_SMTP_PASSWORD"
sender_email: "no-reply@fibitex.com"
sender_name: Fibitex
sender_logo: https://beta.fibitex.com/logo-email.png
auth: plain
domain: fibitex.com
starttls_auto: true
openssl_verify_mode: none
BetaCandaTestNetwork: false
parity:
enabled: false
bitcoind:
enabled: false

View File

@@ -0,0 +1,15 @@
---
# Production cutover overlay — Shahoo replaces Gereh on www.* (use after T5.2 QA sign-off).
# Copy to config/app.staging.yml (or app.production.yml) and set OPENDAX_ENV accordingly.
#
# images.frontend: custom/shahoo:1 ← main user-facing SPA
# Gereh service can be removed from compose after validation.
#
app:
domain: tibitex.com
subdomain: www
shahoo_subdomain: shahoo
images:
frontend: custom/shahoo:1
shahoo: custom/shahoo:1
shahoo_bff: custom/shahoo-bff:1

View File

@@ -0,0 +1,83 @@
---
# Staging overlay — Fibitex beta environment (gitignored: app.staging.yml).
#
# Host naming (matches Cloudflare DNS on fibitex.com zone):
# domain: fibitex.com + subdomain: beta → beta.fibitex.com (Gereh)
# shahoo_subdomain: shahoo → shahoo.fibitex.com (Shahoo + BFF)
#
# Do NOT use domain: beta.fibitex.com + subdomain: www (creates www.beta.fibitex.com).
#
# cp config/app.staging.yml.example config/app.staging.yml
# export OPENDAX_ENV=staging
# bundle exec rake render:config
# docker compose up -d --force-recreate proxy frontend shahoo shahoo-bff
#
app:
domain: fibitex.com
subdomain: beta
shahoo_subdomain: shahoo
# optional explicit host (default: shahoo.fibitex.com):
# shahoo_host: shahoo.fibitex.com
serverip:
enabled: true
ip: YOUR_SERVER_PUBLIC_IP
ssl:
enabled: true
email: admin@fibitex.com
csrfEnabled: true
captchaLogin: true
images:
peatio: custom/dena:1
barong: custom/dalan:1
frontend: custom/gereh:1
gereh: custom/gereh:1
shahoo: custom/shahoo:1
shahoo_bff: custom/shahoo-bff:1
database:
password: "STRONG_DB_PASSWORD"
vault:
root_token: "PASTE_FROM_EXISTING_CONFIG"
peatio_rails_token: "PASTE_FROM_EXISTING_CONFIG"
peatio_crypto_token: "PASTE_FROM_EXISTING_CONFIG"
peatio_upstream_token: "PASTE_FROM_EXISTING_CONFIG"
peatio_matching_token: "PASTE_FROM_EXISTING_CONFIG"
barong_token: "PASTE_FROM_EXISTING_CONFIG"
jibit:
key: "YOUR_JIBIT_KEY"
secret: "YOUR_JIBIT_SECRET"
kavenegar:
key: "YOUR_KAVENEGAR_KEY"
sender: "YOUR_SENDER"
vandar:
mobile: "YOUR_VANDAR_MOBILE"
password: "YOUR_VANDAR_PASSWORD"
key: "YOUR_VANDAR_KEY"
captcha:
siteKey: "YOUR_RECAPTCHA_SITE_KEY"
secretKey: "YOUR_RECAPTCHA_SECRET_KEY"
smtp:
host: mail.fibitex.com
port: 587
user: "no-reply@fibitex.com"
password: "YOUR_SMTP_PASSWORD"
sender_email: "no-reply@fibitex.com"
sender_name: Fibitex
# Host logo on your domain (not postimg.cc) — improves Gmail inbox rate
sender_logo: https://beta.fibitex.com/logo-email.png
auth: plain
domain: fibitex.com
starttls_auto: true
openssl_verify_mode: none
BetaCandaTestNetwork: false

147
config/app.yml Normal file
View File

@@ -0,0 +1,147 @@
---
# Shared baseline configuration (safe to commit — no real secrets).
# Local overrides: config/app.local.yml (gitignored)
# Production secrets: config/app.production.yml (gitignored, OPENDAX_ENV=production)
app:
name: Fibitex
domain: tibitex.com
subdomain: www
shahoo_subdomain: shahoo
show_landing: true
render_protect: false
csrfEnabled: true
serverip:
enabled: true
ip: changeme
admin:
user: admin@fibitex.com
pass: changeme
jibit:
url: https://napi.jibit.ir/ide/v1/
key: changeme
secret: changeme
kavenegar:
key: changeme
sender: changeme
vandar:
mobile: changeme
password: changeme
key: changeme
name: developers
ssl:
enabled: true
email: admin@fibitex.com
updateVersions: false
images:
peatio: custom/dena:1
barong: custom/dalan:1
frontend: custom/gereh:1
gereh: custom/gereh:1
shahoo: custom/shahoo:1
shahoo_bff: custom/shahoo-bff:1
tower: ya3er/admin_tower:2.2.66
rango: quay.io/openware/rango:2.6.1
finex:
enabled: false
image: quay.io/openware/finex:2.6.39
license_key: changeme
vendor:
frontend: git@github.com:openware/baseapp.git
kyc:
provider: local
authorization_token: changeme
sandbox_mode: true
api_endpoint: https://api.kycaid.com/
vault:
root_token: changeme
peatio_rails_token: changeme
peatio_crypto_token: changeme
peatio_upstream_token: changeme
peatio_matching_token: changeme
barong_token: changeme
finex_engine_token: changeme
database:
host: db
adapter: mysql
port: 3306
user: root
password: changeme
storage:
provider: local
twilio:
enabled: false
phone_number: "+15005550000"
account_sid: changeme
auth_token: changeme
gaTrackerKey: ''
captchaLogin: true
captcha:
type: recaptcha
siteKey: changeme
secretKey: changeme
smtp:
host: mail.fibitex.com
port: 587
user: changeme
password: changeme
sender_email: changeme
sender_name: Fibitex
sender_logo: https://beta.fibitex.com/logo-email.png
auth: plain
domain: fibitex.com
starttls_auto: true
openssl_verify_mode: none
wallets:
eth:
- kind: deposit
address: changeme
max_balance: 0.0
secret: changeme
- kind: hot
address: changeme
max_balance: 100.0
secret: changeme
- kind: warm
address: changeme
max_balance: 1000.0
secret: changeme
btc:
- kind: deposit
address: changeme
max_balance: 0.0
- kind: hot
address: changeme
max_balance: 100.0
- kind: warm
address: changeme
max_balance: 1000.0
BetaCandaTestNetwork: false
parity:
enabled: false
network: testnet
address: parity
rpcport: 8545
port: 30303
bitcoind:
enabled: false
rpcuser: admin
rpcpassword: changeme
address: bitcoind
network: testnet
rpcport: 18332
port: 18333
litecoind:
rpcuser: admin
rpcpassword: changeme
address: litecoind
network: testnet
rpcport: 19332
port: 19335
terraform:
credentials: "~/safe/opendax.json"
project: example-opendax
region: europe-west4
zone: europe-west4-a
instance_name: opendax-cloud
machine_type: n1-standard-4
image: debian-cloud/debian-9

0
config/applogic/.gitkeep Normal file
View File

0
config/arke/.gitkeep Normal file
View File

View File

@@ -0,0 +1,18 @@
#
# pass for whitelisted (public) routes
# block for blacklisted routes
#
rules:
pass:
- api/v2/dalan/public
- api/v2/dalan/identity
- api/v2/dena/public
- api/v2/dena/coinmarketcap
- api/v2/dena/coingecko
- api/v2/ranger/public
- api/v2/applogic/public
- api/v2/arke/public
- api/v2/finex/public
block:
- api/v2/dalan/management
- api/v2/dena/management

52
config/barong/barong.yml Normal file
View File

@@ -0,0 +1,52 @@
activation_requirements:
email: 'verified'
state_triggers:
banned:
- ban
- fraud
deleted:
- delete
locked:
- suspicious
- lock
document_types:
- Passport
- Identity card
- Driver license
- Utility Bill
- Residental
- Institutional
- Poa
- Selfie
document_categories:
- front_side
- selfie
- back_side
user_storage_titles:
# - personal ## example
# - company ## example
captcha_protected_endpoints: []
# - user_create
# - session_create
# - password_reset
# - email_confirmation
profile_verification_roles:
- superadmin
# - admin
# - kyc_worker
kyc_levels:
1:
2: profile
3: access_phone
4: card
5: iban
2:
6: poa
7: telephone
8: selfie
9: owner_phone
3:
10: vip

382
config/barong/seeds.yml Normal file
View File

@@ -0,0 +1,382 @@
# List of Barong administrators.
#
# Other parameters that you can set here can be found in Account,
# Profile and Phone models (e.g. app/models/account.rb...); all the
# model properties are listed at the very bottom of this models files.
#
# Note: email is the only required field here.
users:
- email: admin@test.com
password: "123qwe!@#QWE"
role: superadmin
state: active
level: 3
- email: user@test.com
password: "123qwe!@#QWE"
role: member
state: active
level: 0
- email: bot@test.com
password: "123qwe!@#QWE"
role: member
state: active
level: 3
levels:
- key: email
id: 1
value: verified
description: "User enter a valid code after registration"
- key: profile
id: 2
value: verified
description: "User personal documents have been verified"
- key: access_phone
id: 3
value: verified
description: "User entered a valid code from sms"
- key: card
id: 4
value: verified
description: "User card number have been verified"
- key: iban
id: 5
value: verified
description: "User iban have been verified"
- key: poa
id: 6
value: verified
description: "User card bank have been verified"
- key: telephone
id: 7
value: verified
description: "User entered a valid code from ring call"
- key: selfie
id: 8
value: verified
description: "User selfie documents have been verified"
- key: owner_phone
id: 9
value: verified
description: "User owner mobile have been verified"
- key: vip
id: 10
value: verified
description: "User Vip have been verified"
restrictions: {}
# - { category: whitelist, scope: country, value: UA, state: disabled }
# - { category: maintenance, scope: all, value: all, state: disabled }
# - { category: blacklist, scope: ip, value: 164.116.47.255, state: disabled, code: 433 }
# - { category: blacklist, scope: ip_subnet, value: 164.116.47.0/24, state: disabled, code: 434 }
# - { category: blacklist, scope: country, value: USA, state: disabled, code: 435 }
# - { category: blacklist, scope: continent, value: SA, state: disabled, code: 436 }
permissions:
# SUPER ADMIN has an access to the whole system without any limits
# so we can just grant him access to /api/v2/*
- { role: superadmin, verb: all, path: api/v2, action: accept }
# Rango(ranger) access
- { role: superadmin, verb: get, path: api/v2/ranger, action: accept }
# we are watching after you 0_0
- { role: superadmin, verb: post, path: api/v2/, action: audit }
- { role: superadmin, verb: put, path: api/v2/, action: audit }
- { role: superadmin, verb: delete, path: api/v2/, action: audit }
# ADMIN
# admin has nearly full access to barong and peatio api, except managing permissions
- { role: admin, verb: all, path: api/v2, action: accept }
# ranger access
- { role: admin, verb: get, path: api/v2/ranger, action: accept }
# Finex upstream access
- { role: admin, verb: get, path: api/v2/open_finance, action: accept }
# admin doesnt have access to manage platform roles and permissions
- { role: admin, verb: all, path: api/v2/dalan/admin/permissions, action: drop }
# admin doesnt have access to manage roles
- { role: admin, verb: all, path: api/v2/dalan/admin/users/role, action: drop }
# admin doesnt have access to admin activities
- { role: admin, verb: all, path: api/v2/dalan/admin/activities/admin, action: drop }
# we are watching after you 0_0
- { role: admin, verb: post, path: api/v2/, action: audit }
- { role: admin, verb: put, path: api/v2/, action: audit }
- { role: admin, verb: delete, path: api/v2/, action: audit }
# ACCOUNTANT
# accountant has a read access to Barong admin
- { role: accountant, verb: get, path: api/v2/dalan/admin, action: accept }
# accountant has a read access to Peatio financial information and creating of adjustments
- { role: accountant, verb: get, path: api/v2/dena/admin/members, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/beneficiaries, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/currencies, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/blockchains, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/wallets, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/trading_fees, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/withdraw_limits, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/orders, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/markets, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/engine, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/trades, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/deposits, action: accept }
- { role: accountant, verb: post, path: api/v2/dena/admin/deposits/new, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/withdraws, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/adjustments, action: accept }
- { role: accountant, verb: post, path: api/v2/dena/admin/adjustments/new, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/assets, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/liabilities, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/revenues, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/expenses, action: accept }
- { role: accountant, verb: get, path: api/v2/dena/admin/internal_transfers, action: accept }
# accountant doesnt have access to see pending documents
- { role: accountant, verb: get, path: api/v2/dalan/admin/users/documents/pending, action: drop }
# accountant doesnt have access to manage platform roles and permissions
- { role: accountant, verb: all, path: api/v2/dalan/admin/users/role, action: drop }
- { role: accountant, verb: all, path: api/v2/dalan/admin/permissions, action: drop }
# accountant doesnt have access to admin activities
- { role: accountant, verb: all, path: api/v2/dalan/admin/activities/admin, action: drop }
# we are watching after you 0_0
- { role: accountant, verb: post, path: api/v2/, action: audit }
- { role: accountant, verb: put, path: api/v2/, action: audit }
- { role: accountant, verb: delete, path: api/v2/, action: audit }
# has standard user permissions to ACCOUNT, MARKET, RESOURCE modules
- { role: accountant, verb: all, path: api/v2/dena/account, action: accept }
- { role: accountant, verb: all, path: api/v2/dena/market, action: accept }
- { role: accountant, verb: all, path: api/v2/finex/market, action: accept }
- { role: accountant, verb: all, path: api/v2/dalan/resource, action: accept }
- { role: accountant, verb: all, path: api/v2/dena/account/internal_transfers, action: accept }
- { role: accountant, verb: all, path: api/v2/dena/swagger, action: accept }
# Drop Peatio order endpoint requests
# ranger access
- { role: accountant, verb: get, path: api/v2/ranger, action: accept }
# applogic access
- { role: accountant, verb: all, path: api/v2/applogic, action: accept }
# get abilities
- { role: accountant, verb: all, path: api/v2/dena/admin/abilities, action: accept }
- { role: accountant, verb: all, path: api/v2/dalan/admin/abilities, action: accept }
# COMPLIANCE
- { role: compliance, verb: get, path: api/v2/dalan/admin, action: accept }
# has an access to CRUD of user-related resources
- { role: compliance, verb: get, path: api/v2/dena/admin/members, action: accept }
- { role: compliance, verb: get, path: api/v2/dena/admin/beneficiaries, action: accept }
- { role: compliance, verb: get, path: api/v2/dena/admin/currencies, action: accept }
- { role: compliance, verb: get, path: api/v2/dena/admin/trades, action: accept }
- { role: compliance, verb: get, path: api/v2/dena/admin/orders, action: accept }
- { role: compliance, verb: all, path: api/v2/dalan/admin/users, action: accept }
# has ability to see deposit, withdraw, operations (partial)
- { role: compliance, verb: get, path: api/v2/dena/admin/deposits, action: accept }
- { role: compliance, verb: get, path: api/v2/dena/admin/withdraws, action: accept }
- { role: compliance, verb: get, path: api/v2/dena/admin/assets, action: accept }
- { role: compliance, verb: get, path: api/v2/dena/admin/liabilities, action: accept }
- { role: compliance, verb: get, path: api/v2/dena/admin/expenses, action: accept }
- { role: compliance, verb: get, path: api/v2/dena/admin/markets, action: accept }
- { role: compliance, verb: get, path: api/v2/dena/admin/engine, action: accept }
# has no ability to see the configurations
- { role: compliance, verb: all, path: api/v2/dena/admin/adjustments, action: drop }
- { role: compliance, verb: all, path: api/v2/dena/admin/revenues, action: drop }
- { role: compliance, verb: all, path: api/v2/dena/admin/blockchains, action: drop }
- { role: compliance, verb: all, path: api/v2/dena/admin/wallets, action: drop }
- { role: compliance, verb: all, path: api/v2/dena/admin/trading_fees, action: drop }
- { role: compliance, verb: all, path: api/v2/dena/admin/withdraw_limits, action: drop }
- { role: compliance, verb: all, path: api/v2/dalan/admin/restrictions, action: drop }
# compliance doesnt have access to change users roles
- { role: compliance, verb: all, path: api/v2/dalan/admin/users/role, action: drop }
# compliance doesnt have access to admin activities
- { role: compliance, verb: all, path: api/v2/dalan/admin/activities/admin, action: drop }
# compliance doesnt have access to manage platform roles and permissions
- { role: compliance, verb: all, path: api/v2/dalan/admin/permissions, action: drop }
# we are watching after you 0_0
- { role: compliance, verb: post, path: api/v2/, action: audit }
- { role: compliance, verb: put, path: api/v2/, action: audit }
- { role: compliance, verb: delete, path: api/v2/, action: audit }
# has standard user permissions to ACCOUNT, MARKET, RESOURCE modules
- { role: compliance, verb: all, path: api/v2/dena/account, action: accept }
- { role: compliance, verb: all, path: api/v2/dena/market, action: accept }
- { role: compliance, verb: all, path: api/v2/finex/market, action: accept }
- { role: compliance, verb: all, path: api/v2/dalan/resource, action: accept }
- { role: compliance, verb: all, path: api/v2/dena/account/internal_transfers, action: accept }
- { role: compliance, verb: all, path: api/v2/dena/swagger, action: accept }
# Drop Peatio order endpoint requests
# ranger access
- { role: compliance, verb: get, path: api/v2/ranger, action: accept }
# applogic access
- { role: compliance, verb: all, path: api/v2/applogic, action: accept }
# get abilities
- { role: compliance, verb: all, path: api/v2/dena/admin/abilities, action: accept }
- { role: compliance, verb: all, path: api/v2/dalan/admin/abilities, action: accept }
# TECHNICAL
# has an access to CRUD of peatio admin functionality on market, blockchain, wallets, currencies
- { role: technical, verb: get, path: api/v2/dalan/admin, action: accept }
- { role: technical, verb: get, path: api/v2/dena/admin, action: accept }
# technical has a configuration access to Peatio admin
- { role: technical, verb: all, path: api/v2/dena/admin/blockchains, action: accept }
- { role: technical, verb: all, path: api/v2/dena/admin/currencies, action: accept }
- { role: technical, verb: all, path: api/v2/dena/admin/markets, action: accept }
- { role: technical, verb: all, path: api/v2/dena/admin/wallets, action: accept }
- { role: technical, verb: all, path: api/v2/dena/admin/trading_fees, action: accept }
- { role: technical, verb: all, path: api/v2/dena/admin/withdraw_limits, action: accept }
- { role: technical, verb: get, path: api/v2/dena/admin/internal_transfers, action: accept }
- { role: technical, verb: all, path: api/v2/dena/admin/engine, action: accept }
# technical has access to delete orders
- { role: technical, verb: delete, path: api/v2/finex/admin/bulk/orders_by_id, action: accept }
- { role: technical, verb: post, path: api/v2/finex/admin/orders/cancel, action: accept }
# technical has an ability to create and update restrictions
- { role: technical, verb: all, path: api/v2/dalan/admin/restrictions, action: accept }
# has no ability to see and update Deposit, Withdraw, Adjustments
- { role: technical, verb: all, path: api/v2/dena/admin/deposits, action: drop }
- { role: technical, verb: all, path: api/v2/dena/admin/withdraws, action: drop }
- { role: technical, verb: all, path: api/v2/dena/admin/adjustments, action: drop }
# Finex upstream access
- { role: technical, verb: get, path: api/v2/open_finance, action: accept }
# technical doesnt have access to see pending documents
- { role: technical, verb: get, path: api/v2/dalan/admin/users/documents/pending, action: drop }
# technical doesnt have access to admin activities
- { role: technical, verb: all, path: api/v2/dalan/admin/activities/admin, action: drop }
# technical doesnt have access to manage platform roles and permissions
- { role: technical, verb: all, path: api/v2/dalan/admin/permissions, action: drop }
# we are watching after you 0_0
- { role: technical, verb: post, path: api/v2/, action: audit }
- { role: technical, verb: put, path: api/v2/, action: audit }
- { role: technical, verb: delete, path: api/v2/, action: audit }
# has standard user permissions to ACCOUNT, MARKET, RESOURCE modules
- { role: technical, verb: all, path: api/v2/dena/account, action: accept }
- { role: technical, verb: all, path: api/v2/dena/market, action: accept }
- { role: technical, verb: all, path: api/v2/finex/market, action: accept }
- { role: technical, verb: all, path: api/v2/dalan/resource, action: accept }
- { role: technical, verb: all, path: api/v2/dena/account/internal_transfers, action: accept }
- { role: technical, verb: all, path: api/v2/dena/swagger, action: accept }
# Drop Peatio order endpoint requests
# ranger access
- { role: technical, verb: get, path: api/v2/ranger, action: accept }
# applogic access
- { role: technical, verb: all, path: api/v2/applogic, action: accept }
# get abilities
- { role: technical, verb: all, path: api/v2/dena/admin/abilities, action: accept }
- { role: technical, verb: all, path: api/v2/dalan/admin/abilities, action: accept }
# SUPPORT
# has read only access to several statistic and user-related endpoints
- { role: support, verb: get, path: api/v2/dalan/admin, action: accept }
- { role: support, verb: get, path: api/v2/dena/admin, action: accept }
# has no ability to see the configurations
- { role: support, verb: all, path: api/v2/dena/admin/adjustments, action: drop }
- { role: support, verb: all, path: api/v2/dena/admin/revenues, action: drop }
- { role: support, verb: all, path: api/v2/dena/admin/blockchains, action: drop }
- { role: support, verb: all, path: api/v2/dena/admin/wallets, action: drop }
- { role: support, verb: all, path: api/v2/dena/admin/trading_fees, action: drop }
- { role: support, verb: all, path: api/v2/dena/admin/withdraw_limits, action: drop }
- { role: support, verb: all, path: api/v2/dalan/admin/restrictions, action: drop }
- { role: support, verb: get, path: api/v2/dena/admin/internal_transfers, action: accept }
- { role: support, verb: get, path: api/v2/dena/admin/engine, action: accept }
# has ability to disable 2FA
- { role: support, verb: post, path: api/v2/dalan/admin/users/update, action: accept }
# support doesnt have access to admin activities
- { role: support, verb: all, path: api/v2/dalan/admin/activities/admin, action: drop }
# support doesnt have access to manage platform roles and permissions
- { role: support, verb: all, path: api/v2/dalan/admin/permissions, action: drop }
- { role: support, verb: all, path: api/v2/dalan/admin/permissions, action: drop }
# we are watching after you 0_0
- { role: support, verb: post, path: api/v2/, action: audit }
- { role: support, verb: put, path: api/v2/, action: audit }
- { role: support, verb: delete, path: api/v2/, action: audit }
# has standard user permissions to ACCOUNT, MARKET, RESOURCE modules
- { role: support, verb: all, path: api/v2/dena/account, action: accept }
- { role: support, verb: all, path: api/v2/dena/market, action: accept }
- { role: support, verb: all, path: api/v2/finex/market, action: accept }
- { role: support, verb: all, path: api/v2/dalan/resource, action: accept }
- { role: support, verb: all, path: api/v2/dena/account/internal_transfers, action: accept }
- { role: support, verb: all, path: api/v2/dena/swagger, action: accept }
# Drop Peatio order endpoint requests
# ranger access
- { role: support, verb: get, path: api/v2/ranger, action: accept }
# applogic access
- { role: support, verb: all, path: api/v2/applogic, action: accept }
# get abilities
- { role: support, verb: all, path: api/v2/dena/admin/abilities, action: accept }
- { role: support, verb: all, path: api/v2/dalan/admin/abilities, action: accept }
# TRADER
# has standard user permissions to ACCOUNT, MARKET, RESOURCE modules
- { role: trader, verb: all, path: api/v2/dena/account, action: accept }
- { role: trader, verb: all, path: api/v2/dena/market, action: accept }
- { role: trader, verb: all, path: api/v2/dalan/resource, action: accept }
- { role: trader, verb: all, path: api/v2/resource, action: accept }
- { role: trader, verb: all, path: api/v2/dena/account/internal_transfers, action: accept }
- { role: trader, verb: all, path: api/v2/dena/swagger, action: accept }
# ranger access
- { role: trader, verb: get, path: api/v2/ranger, action: accept }
# Finex upstream access
- { role: trader, verb: get, path: api/v2/open_finance, action: accept }
# applogic access
- { role: trader, verb: all, path: api/v2/applogic, action: accept }
# MEMBER
# has standard user permissions to ACCOUNT, MARKET, RESOURCE modules
- { role: member, verb: all, path: api/v2/dena/account, action: accept }
- { role: member, verb: all, path: api/v2/dena/market, action: accept }
- { role: member, verb: all, path: api/v2/dalan/resource, action: accept }
- { role: member, verb: all, path: api/v2/resource, action: accept }
- { role: member, verb: all, path: api/v2/dena/account/internal_transfers, action: accept }
- { role: member, verb: all, path: api/v2/dena/swagger, action: accept }
# ranger access
- { role: member, verb: get, path: api/v2/ranger, action: accept }
# Finex upstream access
- { role: member, verb: get, path: api/v2/open_finance, action: accept }
# applogic access
- { role: member, verb: all, path: api/v2/applogic, action: accept }
# BROKER
# has standard user permissions to ACCOUNT, MARKET, RESOURCE modules
- { role: broker, verb: all, path: api/v2/dena/account, action: accept }
- { role: broker, verb: all, path: api/v2/dena/market, action: accept }
- { role: broker, verb: all, path: api/v2/dalan/resource, action: accept }
- { role: broker, verb: all, path: api/v2/resource, action: accept }
- { role: broker, verb: all, path: api/v2/dena/account/internal_transfers, action: accept }
- { role: broker, verb: all, path: api/v2/dena/swagger, action: accept }
# ranger access
- { role: broker, verb: get, path: api/v2/ranger, action: accept }
# Finex upstream access
- { role: broker, verb: get, path: api/v2/open_finance, action: accept }
# applogic access
- { role: broker, verb: all, path: api/v2/applogic, action: accept }
# MAKER
# has standard user permissions to ACCOUNT, MARKET, RESOURCE modules
- { role: maker, verb: all, path: api/v2/dena/account, action: accept }
- { role: maker, verb: all, path: api/v2/dena/market, action: accept }
- { role: maker, verb: all, path: api/v2/dalan/resource, action: accept }
- { role: maker, verb: all, path: api/v2/resource, action: accept }
- { role: maker, verb: all, path: api/v2/dena/account/internal_transfers, action: accept }
- { role: maker, verb: all, path: api/v2/dena/swagger, action: accept }
# ranger access
- { role: maker, verb: get, path: api/v2/ranger, action: accept }
# Finex upstream access
- { role: maker, verb: get, path: api/v2/open_finance, action: accept }
# applogic access
- { role: maker, verb: all, path: api/v2/applogic, action: accept }
# Service Account Maker
# has standard user permissions to ACCOUNT, MARKET, RESOURCE modules
- { role: sa_maker, verb: all, path: api/v2/dena/account, action: accept }
- { role: sa_maker, verb: all, path: api/v2/dena/market, action: accept }
- { role: sa_maker, verb: all, path: api/v2/dalan/resource, action: accept }
- { role: sa_maker, verb: all, path: api/v2/dena/account/internal_transfers, action: accept }
- { role: sa_maker, verb: all, path: api/v2/dena/swagger, action: accept }
# Service Account can not interact with Password, 2FA, KYC, API keys, Beneficiary, Deposit and Withdraw
- { role: sa_maker, verb: all, path: api/v2/dalan/resource/otp, action: drop }
- { role: sa_maker, verb: all, path: api/v2/dalan/resource/phones, action: drop }
- { role: sa_maker, verb: all, path: api/v2/dalan/resource/profiles, action: drop }
- { role: sa_maker, verb: all, path: api/v2/dalan/resource/documents, action: drop }
- { role: sa_maker, verb: all, path: api/v2/dalan/resource/addresses, action: drop }
- { role: sa_maker, verb: all, path: api/v2/applogic/private/tenants, action: drop }
- { role: sa_maker, verb: all, path: api/v2/dalan/resource/api_keys, action: drop }
- { role: sa_maker, verb: all, path: api/v2/dalan/resource/users/password, action: drop }
- { role: sa_maker, verb: all, path: api/v2/dena/account/deposit_address, action: drop }
- { role: sa_maker, verb: all, path: api/v2/dena/account/withdraws, action: drop }
- { role: sa_maker, verb: all, path: api/v2/dena/account/beneficiaries, action: drop }
# Finex upstream access
- { role: sa_maker, verb: get, path: api/v2/open_finance, action: accept }
# ranger access
- { role: sa_maker, verb: get, path: api/v2/ranger, action: accept }
# applogic access
- { role: sa_maker, verb: all, path: api/v2/applogic, action: accept }

0
config/frontend/.gitkeep Normal file
View File

0
config/gateway/.gitkeep Normal file
View File

79
config/influxdb/arke.sql Normal file
View File

@@ -0,0 +1,79 @@
CREATE DATABASE arke_development;
CREATE CONTINUOUS QUERY "trade_to_cq_1m" ON arke_development
RESAMPLE EVERY 5s FOR 10m
BEGIN
SELECT FIRST(price) AS open, max(price) AS high, min(price) AS low, last(price) AS close, sum(amount) AS volume INTO candles_1m FROM trades GROUP BY time(1m), market fill(null)
END;
CREATE CONTINUOUS QUERY "trade_amount_to_cq_1m" ON arke_development
RESAMPLE EVERY 5s FOR 10m
BEGIN
SELECT sum(amount) AS volume INTO candles_1m FROM trades GROUP BY time(1m), market fill(0)
END;
CREATE CONTINUOUS QUERY "cq_5m" ON arke_development
RESAMPLE EVERY 5s FOR 10m
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_5m" FROM "candles_1m" GROUP BY time(5m), market
END;
CREATE CONTINUOUS QUERY "cq_15m" ON arke_development
RESAMPLE EVERY 5s FOR 30m
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_15m" FROM "candles_5m" GROUP BY time(15m), market
END;
CREATE CONTINUOUS QUERY "cq_30m" ON arke_development
RESAMPLE EVERY 5s FOR 1h
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_30m" FROM "candles_15m" GROUP BY time(30m), market
END;
CREATE CONTINUOUS QUERY "cq_1h" ON arke_development
RESAMPLE EVERY 5s FOR 2h
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_1h" FROM "candles_30m" GROUP BY time(1h), market
END;
CREATE CONTINUOUS QUERY "cq_2h" ON arke_development
RESAMPLE EVERY 5s FOR 4h
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_2h" FROM "candles_1h" GROUP BY time(2h), market
END;
CREATE CONTINUOUS QUERY "cq_4h" ON arke_development
RESAMPLE EVERY 5s FOR 8h
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_4h" FROM "candles_2h" GROUP BY time(4h), market
END;
CREATE CONTINUOUS QUERY "cq_6h" ON arke_development
RESAMPLE EVERY 5s FOR 12h
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_6h" FROM "candles_2h" GROUP BY time(6h), market
END;
CREATE CONTINUOUS QUERY "cq_12h" ON arke_development
RESAMPLE EVERY 5s FOR 24h
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_12h" FROM "candles_6h" GROUP BY time(12h), market
END;
CREATE CONTINUOUS QUERY "cq_1d" ON arke_development
RESAMPLE EVERY 5s FOR 2d
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_1d" FROM "candles_6h" GROUP BY time(1d), market
END;
CREATE CONTINUOUS QUERY "cq_3d" ON arke_development
RESAMPLE EVERY 5s FOR 6d
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_3d" FROM "candles_1d" GROUP BY time(3d), market
END;
CREATE CONTINUOUS QUERY "cq_1w" ON arke_development
RESAMPLE EVERY 5s FOR 2w
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_1w" FROM "candles_1d" GROUP BY time(7d), market
END;

View File

@@ -0,0 +1,11 @@
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_5m" FROM "candles_1m" GROUP BY time(5m), market;
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_15m" FROM "candles_5m" GROUP BY time(15m), market;
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_30m" FROM "candles_15m" GROUP BY time(30m), market;
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_1h" FROM "candles_30m" GROUP BY time(1h), market;
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_2h" FROM "candles_1h" GROUP BY time(2h), market;
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_4h" FROM "candles_2h" GROUP BY time(4h), market;
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_6h" FROM "candles_2h" GROUP BY time(6h), market;
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_12h" FROM "candles_6h" GROUP BY time(6h), market;
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_1d" FROM "candles_4h" GROUP BY time(1d), market;
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_3d" FROM "candles_1d" GROUP BY time(3d), market;
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_1w" FROM "candles_1d" GROUP BY time(1w), market;

View File

@@ -0,0 +1,66 @@
CREATE DATABASE peatio_production;
CREATE CONTINUOUS QUERY "trade_to_cq_1m" ON peatio_production
RESAMPLE EVERY 1s FOR 3m
BEGIN
SELECT FIRST(price) AS open, max(price) AS high, min(price) AS low, last(price) AS close, sum(amount) AS volume INTO candles_1m FROM trades GROUP BY time(1m), market
END;
CREATE CONTINUOUS QUERY "candles_1m_to_cq_1m" ON peatio_production
RESAMPLE EVERY 1m FOR 2m
BEGIN
SELECT last(close) AS open, last(close) AS high, last(close) AS low, last(close) AS close, last(volume) * 0 as volume INTO candles_1m FROM candles_1m GROUP BY time(1m), market fill(previous)
END;
CREATE CONTINUOUS QUERY "cq_5m" ON peatio_production
RESAMPLE EVERY 5s FOR 10m
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_5m" FROM "candles_1m" GROUP BY time(5m), market
END;
CREATE CONTINUOUS QUERY "cq_15m" ON peatio_production
RESAMPLE EVERY 5s FOR 30m
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_15m" FROM "candles_5m" GROUP BY time(15m), market
END;
CREATE CONTINUOUS QUERY "cq_30m" ON peatio_production
RESAMPLE EVERY 5s FOR 1h
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_30m" FROM "candles_15m" GROUP BY time(30m), market
END;
CREATE CONTINUOUS QUERY "cq_1h" ON peatio_production
RESAMPLE EVERY 5s FOR 2h
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_1h" FROM "candles_30m" GROUP BY time(1h), market
END;
CREATE CONTINUOUS QUERY "cq_2h" ON peatio_production
RESAMPLE EVERY 5s FOR 4h
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_2h" FROM "candles_1h" GROUP BY time(2h), market
END;
CREATE CONTINUOUS QUERY "cq_4h" ON peatio_production
RESAMPLE EVERY 5s FOR 8h
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_4h" FROM "candles_2h" GROUP BY time(4h), market
END;
CREATE CONTINUOUS QUERY "cq_6h" ON peatio_production
RESAMPLE EVERY 5s FOR 12h
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_6h" FROM "candles_2h" GROUP BY time(6h), market
END;
CREATE CONTINUOUS QUERY "cq_12h" ON peatio_production
RESAMPLE EVERY 5s FOR 24h
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_12h" FROM "candles_6h" GROUP BY time(12h), market
END;
CREATE CONTINUOUS QUERY "cq_1d" ON peatio_production
RESAMPLE EVERY 5s FOR 2d
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_1d" FROM "candles_6h" GROUP BY time(1d), market
END;
CREATE CONTINUOUS QUERY "cq_3d" ON peatio_production
RESAMPLE EVERY 5s FOR 6d
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_3d" FROM "candles_1d" GROUP BY time(3d), market
END;
CREATE CONTINUOUS QUERY "cq_1w" ON peatio_production
RESAMPLE EVERY 5s FOR 2w
BEGIN
SELECT FIRST(open) as open, MAX(high) as high, MIN(low) as low, LAST(close) as close, SUM(volume) as volume INTO "candles_1w" FROM "candles_1d" GROUP BY time(7d), market
END;

View File

@@ -0,0 +1,55 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p>Deposit <b><%= @record.state %></b></p>
<p>
Your deposit #<%= @record.tid %> of <%= @record.amount %> <%= @record.currency %> has been <%= @record.state %>.
</p>
<br /><br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,73 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p style="margin-top: 18px"><b>Hello!</b></p>
<p>
Use this unique link to confirm your email <%= @user.email %>
</p>
<br /><br /><br />
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="left">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<a href="<%= @record.domain %>/accounts/confirmation?confirmation_token=<%= @record.token %>&lang=en">Confirm</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,73 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p style="margin-top: 18px"><b>Здравствуйте!</b></p>
<p>
Используйте эту уникальную ссылку для подтверждения вашей почты <%= @user.email %>
</p>
<br /><br /><br />
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="left">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<a href="<%= @record.domain %>/accounts/confirmation?confirmation_token=<%= @record.token %>&lang=en">Подтвердить</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,97 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p style="margin-top: 18px"><b>Hello!</b></p>
<p>
Use this code to confirm your email <%= @user.email %>
</p>
<br /><br /><br />
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="left">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<span><%= @record.code %></span>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br />
<% if @record.token.present? %>
<p>
Or use this one-time link to confirm your email:
</p>
<br />
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="left">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<a href="<%= @record.domain %>/accounts/confirmation?confirmation_token=<%= @record.token %>&lang=en">Confirm email</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<% end %>
<br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,73 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p style="margin-top: 18px"><b>Hello!</b></p>
<p>
Use this code to disbale 2fa <%= @user.email %>
</p>
<br /><br /><br />
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="left">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<span><%= @record.code %></span>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,73 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p style="margin-top: 18px"><b>Hello!</b></p>
<p>
Use this code to enable your 2fa <%= @user.email %>
</p>
<br /><br /><br />
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="left">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<span><%= @record.code %></span>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,76 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p>Hello!</p>
<p>
<% if @record.value == "verified" %>
Congratulations, your account details was successfully upgraded.
<% end %>
<% if @record.value == "rejected" %>
Unfortunately, your account details was rejected.
<% end %>
Your current account level is <b><%= @record.user.level %></b>
Your account state is <b><%= @record.user.state %></b>
</p>
<p>
<% if @record.key == "profile" %>
Recently your user profile was <%= @record.value %>.
<% end %>
<% if @record.key == "id_document" %>
Recently your main document was <%= @record.value %>.
<% end %>
<% if @record.key == "second_document" %>
Recently your second document was <% @record.value %>.
<% end %>
<% if @record.key == "institutional" %>
Recently your institutional document was <%= @record.value %>.
<% end %>
</p>
<br /><br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,55 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p>New <%= @record.currency %> beneficiary <b><%= @record.name %></b> created!</p>
<p>
Your <b>pin-code</b> for this beneficiary is <%= @record.pin %>.
</p>
<br /><br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,73 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p style="margin-top: 18px"><b>Hello!</b></p>
<p>
email: <%= @user.email %>
</p>
<br /><br /><br />
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="left">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<span><%= @record.code %></span>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,73 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p style="margin-top: 18px"><b>Hello!</b></p>
<p>
Use this code to confirm your password <%= @user.email %>
</p>
<br /><br /><br />
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="left">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<span><%= @record.code %></span>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,97 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p class="title">Hello!</p>
<p class="text">
Use this code or one-time link to reset your password for email <%= @user.email %>
</p>
<br /><br /><br />
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="left">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<span><%= @record.code %></span>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br />
<% if @record.token.present? %>
<p class="text">
Or use this one-time link to reset your password:
</p>
<br />
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="left">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<a href="<%= @record.domain %>/accounts/password_reset?reset_token=<%= @record.token %>&lang=en">Reset password</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<% end %>
<br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,73 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p class="title">Здравствуйте!</p>
<p class="text">
Используйте эту уникальную ссылку для сброса вашего пароля <%= @user.email %>
</p>
<br /><br /><br />
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="left">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<a href="<%= @record.domain %>/accounts/password_reset?reset_token=<%= @record.token %>&lang=en">Сбросить</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,61 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p>Hello!</p>
<p>
We detected a login to your account.
</p>
<p>IP Address: <%= @record.user_ip %></p>
<p>User-agent: <%= @record.user_agent %></p>
<p>If this was you, please disregard this email.</p>
<p>If this wasn't you, please change your passwords immediately, as someone else may be accessing your account.</p>
<br /><br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,61 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p>Hello!</p>
<p>
We detected a failed login to your account.
</p>
<p>IP Address: <%= @record.user_ip %></p>
<p>User-agent: <%= @record.user_agent %></p>
<p>If this was you, please disregard this email.</p>
<p>If this wasn't you, please change your passwords immediately, as someone else may be accessing your account.</p>
<br /><br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,73 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p style="margin-top: 18px"><b>Hello!</b></p>
<p>
Use this code to confirm your withdraw: <%= @user.email %>
</p>
<br /><br /><br />
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="btn btn-primary">
<tbody>
<tr>
<td align="left">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<span><%= @record.code %></span>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

@@ -0,0 +1,55 @@
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
<tr>
<td>&nbsp;</td>
<td class="container">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td style="text-align: center">
<%= image_tag @logo, alt: 'Company Logo', class: 'logo-img' %>
</td>
</tr>
</table>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td class="container">
<div class="content">
<table role="presentation" class="main">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<br />
<p class="text">Withdrawal <b><%= @record.state %></b></p>
<p class="text">
Your withdrawal #<%= @record.tid %> of <%= @record.amount %> <%= @record.currency %> has been <%= @record.state %>.
</p>
<br /><br /><br />
</td>
</tr>
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
</div>
<!-- START FOOTER -->
<div class="footer">
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="content-block">
<span>FIBITEX TECHNOLOGIES INC.</span>
<br><span>Vancouver, Canada</span>
<br><a href="<%= @record.domain %>"><%= @record.domain %></a>
</td>
</tr>
</table>
</div>
<!-- END FOOTER -->
</td>
<td>&nbsp;</td>
</tr>
</table>

View File

View File

View File

View File

8
config/mysql/innodb.cnf Normal file
View File

@@ -0,0 +1,8 @@
[mysqld]
innodb_buffer_pool_size = 2G
innodb_buffer_pool_instances = 2
innodb_log_buffer_size = 128M
innodb_log_file_size = 512M
innodb_flush_log_at_trx_commit = 0
# mysql2 0.5.x (Rails 5.2) — keep native password until Ruby/mysql2 upgrade
default_authentication_plugin=mysql_native_password

22
config/peatio/plugins.yml Normal file
View File

@@ -0,0 +1,22 @@
# Be sure to run "bin/install_plugins" when you modify this file.
#
# This file is used for listing Peatio plugins.
# The plugins must be listed as an array. Each element of array described the plugin using the next variables:
#
# * name
# Mandatory. Specify plugin name. The name must be compatible with filesystem rules.
#
# * git
# Mandatory. Specify Git repository URL.
#
# * commit
# Mandatory. Specify commit hash which Peatio will checkout via "bin/install_plugins".
#
# * require
# Optional. Specify relative path to file from vendor/plugins which should be required by Peatio.
# You may set this value to "false" if you don't want Peatio to require the plugin.
# Example configuration:
#- name: peatio-plugin-example
# git: https://github.com/rubykube/peatio-plugin-example.git
# commit: 11edd2e7c0bef229516f42fde79615a68a008d45

View File

View File

@@ -0,0 +1,411 @@
- id: irt
name: Iranian Toman
type: fiat
precision: 2
base_factor: 1
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 10
min_collection_amount: 10
withdraw_limit_24h: 1000
withdraw_limit_72h: 2000
deposit_fee: 0
withdraw_fee: 0
position: 100
options: {}
- id: cad
name: Canadian Dollar
type: fiat
precision: 2
base_factor: 1
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 10
min_collection_amount: 10
withdraw_limit_24h: 1000
withdraw_limit_72h: 2000
deposit_fee: 0
withdraw_fee: 0
position: 1
options: {}
- id: usdt
name: Tether
blockchain_key: eth-rinkeby
type: coin
precision: 2
base_factor: 1
# IMPORTANT: Don't forget to update this variable according
# to your ERC20-based currency requirements (usually can be found on the official website).
visible: true
deposit_enabled: false
withdrawal_enabled: false
# Deposits with less amount are skipped during blockchain synchronization.
# We advise to set value 10 times bigger than the network fee to prevent losses.
# NOTE: Network fee is paid in ETH but min_deposit_amount is in TRST.
min_deposit_amount: 2
min_collection_amount: 20
withdraw_limit_24h: 1000
withdraw_limit_72h: 3000
deposit_fee: 0
withdraw_fee: 4
position: 2
options:
# ERC20 tx fees configurations.
# Maximum amount of gas you're willing to spend on a particular transaction.
gas_limit: 90_000
# Internal price that is paid for running a contract on the Ethereum network.
gas_price: 1_000_000_000
#
# ERC20 configuration.
erc20_contract_address: '0xdac17f958d2ee523a2206206994597c13d831ec7' # Always wrap this value in quotes!
- id: btc
name: Bitcoin
blockchain_key: btc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 0.00005
min_collection_amount: 0.0001
withdraw_limit_24h: 0.1
withdraw_limit_72h: 0.2
deposit_fee: 0
withdraw_fee: 0.0003
position: 3
options: {}
- id: eth
name: Ethereum
blockchain_key: eth-rinkeby
type: coin
precision: 8
base_factor: 1_000_000_000_000_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 0.00021
min_collection_amount: 0.00021
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 0
position: 4
options:
gas_limit: 21_000
gas_price: 1_000_000_000
- id: etc
name: Ethereum Classic
blockchain_key: btc-testnet
type: coin
precision: 8
base_factor: 1_000_000_000_000_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 0.00021
min_collection_amount: 0.00021
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 0
position: 5
options: {}
- id: shib
name: 1000 Shiba Inu
blockchain_key: btc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 6
options: {}
- id: bch
name: Bitcoin Cash
blockchain_key: btc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 7
options: {}
- id: ltc
name: Litecoin
blockchain_key: btc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 8
options: {}
- id: ada
name: Cardano
blockchain_key: btc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 9
options: {}
- id: bnb
name: BNB
blockchain_key: btc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 10
options: {}
- id: xlm
name: Stellar Lumens
blockchain_key: xlm-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 11
options: {}
- id: xrp
name: Ripple
blockchain_key: bsc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 12
options: {}
- id: trx
name: Tron
blockchain_key: trx-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 13
options: {}
- id: doge
name: Dogecoin
blockchain_key: bsc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 14
options: {}
- id: uni
name: Uniswap
blockchain_key: bsc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 15
options: {}
- id: link
name: Chainlink
blockchain_key: bsc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 16
options: {}
- id: dot
name: Polkadot
blockchain_key: bsc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 17
options: {}
- id: aave
name: AAVE
blockchain_key: bsc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 18
options: {}
- id: matic
name: Polygon
blockchain_key: bsc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 19
options: {}
- id: mkr
name: Maker
blockchain_key: bsc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 20
options: {}
- id: sol
name: Solana
blockchain_key: bsc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: false
withdrawal_enabled: false
min_deposit_amount: 1000
min_collection_amount: 1000
withdraw_limit_24h: 0.2
withdraw_limit_72h: 0.5
deposit_fee: 0
withdraw_fee: 400
position: 21
options: {}

View File

@@ -0,0 +1,752 @@
# IRT Market------------------------------------------
- id: usdtirt
engine_name: peatio-default-engine
base_unit: usdt
quote_unit: irt
amount_precision: 2
price_precision: 2
min_price: 9000
max_price: 9000000
min_amount: 1
position: 40
state: enabled
data: {}
- id: btcirt
engine_name: peatio-default-engine
base_unit: btc
quote_unit: irt
amount_precision: 6
price_precision: 2
min_price: 90000000
max_price: 18000000000
min_amount: 0.0001
position: 41
state: enabled
data: {}
- id: ethirt
engine_name: peatio-default-engine
base_unit: eth
quote_unit: irt
amount_precision: 5
price_precision: 2
min_price: 9000000
max_price: 1800000000
min_amount: 0.0001
position: 42
state: enabled
data: {}
- id: etcirt
engine_name: peatio-default-engine
base_unit: etc
quote_unit: irt
amount_precision: 2
price_precision: 4
min_price: 90000
max_price: 45000000
min_amount: 0.01
position: 43
state: enabled
data: {}
- id: shibirt
engine_name: peatio-default-engine
base_unit: shib
quote_unit: irt
amount_precision: 0
price_precision: 6
min_price: 1
max_price: 900000
min_amount: 1
position: 44
state: enabled
data: {}
- id: bchirt
engine_name: peatio-default-engine
base_unit: bch
quote_unit: irt
amount_precision: 5
price_precision: 2
min_price: 9000
max_price: 450000000
min_amount: 0.001
position: 45
state: enabled
data: {}
- id: ltcirt
engine_name: peatio-default-engine
base_unit: ltc
quote_unit: irt
amount_precision: 6
price_precision: 2
min_price: 9000
max_price: 450000000
min_amount: 0.001
position: 46
state: enabled
data: {}
- id: adairt
engine_name: peatio-default-engine
base_unit: ada
quote_unit: irt
amount_precision: 3
price_precision: 4
min_price: 9
max_price: 9000000
min_amount: 0.1
position: 47
state: enabled
data: {}
- id: bnbirt
engine_name: peatio-default-engine
base_unit: bnb
quote_unit: irt
amount_precision: 4
price_precision: 3
min_price: 90000
max_price: 450000000
min_amount: 0.01
position: 48
state: enabled
data: {}
- id: xlmirt
engine_name: peatio-default-engine
base_unit: xlm
quote_unit: irt
amount_precision: 5
price_precision: 4
min_price: 9
max_price: 9000000
min_amount: 0.1
position: 49
state: enabled
data: {}
- id: xrpirt
engine_name: peatio-default-engine
base_unit: xrp
quote_unit: irt
amount_precision: 5
price_precision: 4
min_price: 9
max_price: 9000000
min_amount: 0.1
position: 50
state: enabled
data: {}
- id: trxirt
engine_name: peatio-default-engine
base_unit: trx
quote_unit: irt
amount_precision: 5
price_precision: 4
min_price: 9
max_price: 9000000
min_amount: 0.1
position: 51
state: enabled
data: {}
- id: dogeirt
engine_name: peatio-default-engine
base_unit: doge
quote_unit: irt
amount_precision: 5
price_precision: 4
min_price: 9
max_price: 9000000
min_amount: 1
position: 52
state: enabled
data: {}
- id: uniirt
engine_name: peatio-default-engine
base_unit: uni
quote_unit: irt
amount_precision: 4
price_precision: 4
min_price: 9
max_price: 9000000
min_amount: 0.001
position: 53
state: enabled
data: {}
- id: linkirt
engine_name: peatio-default-engine
base_unit: link
quote_unit: irt
amount_precision: 4
price_precision: 4
min_price: 9
max_price: 9000000
min_amount: 0.001
position: 54
state: enabled
data: {}
- id: dotirt
engine_name: peatio-default-engine
base_unit: dot
quote_unit: irt
amount_precision: 3
price_precision: 4
min_price: 90
max_price: 9000000
min_amount: 0.1
position: 55
state: enabled
data: {}
- id: aaveirt
engine_name: peatio-default-engine
base_unit: aave
quote_unit: irt
amount_precision: 4
price_precision: 6
min_price: 9000
max_price: 450000000
min_amount: 0.0001
position: 56
state: enabled
data: {}
- id: maticirt
engine_name: peatio-default-engine
base_unit: matic
quote_unit: irt
amount_precision: 3
price_precision: 4
min_price: 90
max_price: 9000000
min_amount: 1
position: 57
state: enabled
data: {}
- id: mkrirt
engine_name: peatio-default-engine
base_unit: mkr
quote_unit: irt
amount_precision: 4
price_precision: 4
min_price: 9000
max_price: 450000000
min_amount: 0.0001
position: 58
state: enabled
data: {}
- id: solirt
engine_name: peatio-default-engine
base_unit: sol
quote_unit: irt
amount_precision: 4
price_precision: 6
min_price: 90
max_price: 9000000
min_amount: 0.001
position: 59
state: enabled
data: {}
# CAD Market------------------------------------------
- id: usdtcad
engine_name: peatio-default-engine
base_unit: usdt
quote_unit: cad
amount_precision: 2
price_precision: 2
min_price: 0.1
max_price: 100
min_amount: 1
position: 1
state: enabled
data: {}
- id: btccad
engine_name: peatio-default-engine
base_unit: btc
quote_unit: cad
amount_precision: 6
price_precision: 2
min_price: 1000
max_price: 200000
min_amount: 0.0001
position: 2
state: enabled
data: {}
- id: ethcad
engine_name: peatio-default-engine
base_unit: eth
quote_unit: cad
amount_precision: 5
price_precision: 2
min_price: 100
max_price: 20000
min_amount: 0.0001
position: 3
state: enabled
data: {}
- id: etccad
engine_name: peatio-default-engine
base_unit: etc
quote_unit: cad
amount_precision: 2
price_precision: 4
min_price: 1
max_price: 500
min_amount: 0.01
position: 4
state: enabled
data: {}
- id: shibcad
engine_name: peatio-default-engine
base_unit: shib
quote_unit: cad
amount_precision: 0
price_precision: 6
min_price: 0.00001
max_price: 10
min_amount: 1
position: 5
state: enabled
data: {}
- id: bchcad
engine_name: peatio-default-engine
base_unit: bch
quote_unit: cad
amount_precision: 5
price_precision: 2
min_price: 0.1
max_price: 5000
min_amount: 0.001
position: 6
state: enabled
data: {}
- id: ltccad
engine_name: peatio-default-engine
base_unit: ltc
quote_unit: cad
amount_precision: 6
price_precision: 2
min_price: 0.1
max_price: 5000
min_amount: 0.001
position: 7
state: enabled
data: {}
- id: adacad
engine_name: peatio-default-engine
base_unit: ada
quote_unit: cad
amount_precision: 3
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 0.1
position: 8
state: enabled
data: {}
- id: bnbcad
engine_name: peatio-default-engine
base_unit: bnb
quote_unit: cad
amount_precision: 4
price_precision: 3
min_price: 1
max_price: 5000
min_amount: 0.01
position: 9
state: enabled
data: {}
- id: xlmcad
engine_name: peatio-default-engine
base_unit: xlm
quote_unit: cad
amount_precision: 5
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 0.1
position: 10
state: enabled
data: {}
- id: xrpcad
engine_name: peatio-default-engine
base_unit: xrp
quote_unit: cad
amount_precision: 5
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 0.1
position: 11
state: enabled
data: {}
- id: trxcad
engine_name: peatio-default-engine
base_unit: trx
quote_unit: cad
amount_precision: 5
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 0.1
position: 12
state: enabled
data: {}
- id: dogecad
engine_name: peatio-default-engine
base_unit: doge
quote_unit: cad
amount_precision: 5
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 1
position: 13
state: enabled
data: {}
- id: unicad
engine_name: peatio-default-engine
base_unit: uni
quote_unit: cad
amount_precision: 4
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 0.001
position: 14
state: enabled
data: {}
- id: linkcad
engine_name: peatio-default-engine
base_unit: link
quote_unit: cad
amount_precision: 4
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 0.001
position: 15
state: enabled
data: {}
- id: dotcad
engine_name: peatio-default-engine
base_unit: dot
quote_unit: cad
amount_precision: 3
price_precision: 4
min_price: 0.001
max_price: 100
min_amount: 0.1
position: 16
state: enabled
data: {}
- id: aavecad
engine_name: peatio-default-engine
base_unit: aave
quote_unit: cad
amount_precision: 4
price_precision: 6
min_price: 0.1
max_price: 5000
min_amount: 0.0001
position: 17
state: enabled
data: {}
- id: maticcad
engine_name: peatio-default-engine
base_unit: matic
quote_unit: cad
amount_precision: 3
price_precision: 4
min_price: 0.001
max_price: 100
min_amount: 1
position: 18
state: enabled
data: {}
- id: mkrcad
engine_name: peatio-default-engine
base_unit: mkr
quote_unit: cad
amount_precision: 4
price_precision: 4
min_price: 0.1
max_price: 5000
min_amount: 0.0001
position: 19
state: enabled
data: {}
- id: solcad
engine_name: peatio-default-engine
base_unit: sol
quote_unit: cad
amount_precision: 4
price_precision: 6
min_price: 0.001
max_price: 100
min_amount: 0.001
position: 20
state: enabled
data: {}
# USDT Market------------------------------------------
- id: btcusdt
engine_name: peatio-default-engine
base_unit: btc
quote_unit: usdt
amount_precision: 6
price_precision: 4
min_price: 1000
max_price: 200000
min_amount: 0.0001
position: 21
state: enabled
data: {}
- id: ethusdt
engine_name: peatio-default-engine
base_unit: eth
quote_unit: usdt
amount_precision: 5
price_precision: 4
min_price: 100
max_price: 20000
min_amount: 0.0001
position: 22
state: enabled
data: {}
- id: etcusdt
engine_name: peatio-default-engine
base_unit: etc
quote_unit: usdt
amount_precision: 4
price_precision: 4
min_price: 1
max_price: 500
min_amount: 0.001
position: 23
state: enabled
data: {}
- id: shibusdt
engine_name: peatio-default-engine
base_unit: shib
quote_unit: usdt
amount_precision: 0
price_precision: 6
min_price: 0.000001
max_price: 10
min_amount: 1
position: 24
state: enabled
data: {}
- id: bchusdt
engine_name: peatio-default-engine
base_unit: bch
quote_unit: usdt
amount_precision: 5
price_precision: 4
min_price: 0.1
max_price: 5000
min_amount: 0.001
position: 25
state: enabled
data: {}
- id: ltcusdt
engine_name: peatio-default-engine
base_unit: ltc
quote_unit: usdt
amount_precision: 6
price_precision: 4
min_price: 0.1
max_price: 5000
min_amount: 0.0001
position: 26
state: enabled
data: {}
- id: adausdt
engine_name: peatio-default-engine
base_unit: ada
quote_unit: usdt
amount_precision: 3
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 0.1
position: 27
state: enabled
data: {}
- id: bnbusdt
engine_name: peatio-default-engine
base_unit: bnb
quote_unit: usdt
amount_precision: 4
price_precision: 3
min_price: 1
max_price: 5000
min_amount: 0.01
position: 28
state: enabled
data: {}
- id: xlmusdt
engine_name: peatio-default-engine
base_unit: xlm
quote_unit: usdt
amount_precision: 5
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 0.1
position: 29
state: enabled
data: {}
- id: xrpusdt
engine_name: peatio-default-engine
base_unit: xrp
quote_unit: usdt
amount_precision: 5
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 0.1
position: 30
state: enabled
data: {}
- id: trxusdt
engine_name: peatio-default-engine
base_unit: trx
quote_unit: usdt
amount_precision: 5
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 0.1
position: 31
state: enabled
data: {}
- id: dogeusdt
engine_name: peatio-default-engine
base_unit: doge
quote_unit: usdt
amount_precision: 5
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 1
position: 32
state: enabled
data: {}
- id: uniusdt
engine_name: peatio-default-engine
base_unit: uni
quote_unit: usdt
amount_precision: 4
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 0.001
position: 33
state: enabled
data: {}
- id: linkusdt
engine_name: peatio-default-engine
base_unit: link
quote_unit: usdt
amount_precision: 4
price_precision: 4
min_price: 0.0001
max_price: 100
min_amount: 0.001
position: 34
state: enabled
data: {}
- id: dotusdt
engine_name: peatio-default-engine
base_unit: dot
quote_unit: usdt
amount_precision: 3
price_precision: 4
min_price: 0.001
max_price: 100
min_amount: 0.1
position: 35
state: enabled
data: {}
- id: aaveusdt
engine_name: peatio-default-engine
base_unit: aave
quote_unit: usdt
amount_precision: 4
price_precision: 6
min_price: 0.1
max_price: 5000
min_amount: 0.0001
position: 36
state: enabled
data: {}
- id: maticusdt
engine_name: peatio-default-engine
base_unit: matic
quote_unit: usdt
amount_precision: 3
price_precision: 4
min_price: 0.001
max_price: 100
min_amount: 1
position: 37
state: enabled
data: {}
- id: mkrusdt
engine_name: peatio-default-engine
base_unit: mkr
quote_unit: usdt
amount_precision: 4
price_precision: 4
min_price: 0.1
max_price: 5000
min_amount: 0.001
position: 38
state: enabled
data: {}
- id: solusdt
engine_name: peatio-default-engine
base_unit: sol
quote_unit: usdt
amount_precision: 4
price_precision: 6
min_price: 0.0001
max_price: 100
min_amount: 0.001
position: 39
state: enabled
data: {}

0
config/secrets/.gitkeep Normal file
View File

43
config/test_users.yml Normal file
View File

@@ -0,0 +1,43 @@
# Test users for local / test environments (see bin/seed_test_users.rb)
# Password for all: 123qwe!@#QWE
remove_emails:
- admin@fibitex.com
- admin@barong.io
- john@barong.io
users:
- email: user@test.com
uid: TST0001USER
password: "123qwe!@#QWE"
role: member
state: active
level: 0
kyc: zero
peatio_group: vip-0
fiat_balance: 20000
coin_multiplier: 2
- email: bot@test.com
uid: TST0002BOT
password: "123qwe!@#QWE"
role: member
state: active
level: 3
kyc: full
peatio_group: bot
fiat_balance: 20000000
coin_multiplier: 1000000
coin_fixed:
usdt: 20000000
- email: admin@test.com
uid: TST0003ADMIN
password: "123qwe!@#QWE"
role: superadmin
state: active
level: 3
kyc: full
peatio_group: vip-0
fiat_balance: 2000
coin_multiplier: 10

178
config/utils.yml Normal file
View File

@@ -0,0 +1,178 @@
images:
applogic: rubykube/applogic:latest
arke: custom/arke:3 #quay.io/openware/arke:2.6.0-bccb72c
superset: amancevice/superset:0.28.1
superset:
email: yaser@fibitex.com
username: yaser
password: changeme
arke:
log_level: WARN # Level of Arke log info
accounts:
#---------------------------{source}-----------------------------------
- id: bitfinex_source # Unique account id of the source
driver: bitfinex # One of supported sources drivers
delay: 1 # Delay of balance information update
key: "" # API key from source (not required for copy strategy)
secret: "" # Secret from API key from source (not required for copy strategy)
#---------------------------{source}-----------------------------------
- id: binance_source # Unique account id of the source
driver: binance # One of supported sources drivers
delay: 1 # Delay of balance information update
key: "" # API key from source (not required for copy strategy)
secret: "" # Secret from API key from source (not required for copy strategy)
#---------------------------{target}-----------------------------------
- id: opendax_target # Unique account id of the target
driver: opendax # Only supported target driver
key: "b1068c9c54fa2035" # API key from the target, required
secret: "6048b9c7668ea7ea0107a62265674540" # Secret from API key from the target, required
host: "https://www.tibitex.com" # Your target URL
ws: "wss://www.tibitex.com" # Your target WebSocet URL
debug: false
verify_ssl: false
finex: false
strategies:
#---------------------------{strategy}-----------------------------------
- id: copy-BTCUSD # Name of a strategy
type: copy # Type of the strategy
debug: true # True to see extra Arke logs
enabled: true # True to run this strategy after Arke (re)startgit
period: 90 # Period of order book refresh
params:
spread_bids: 0.0015 # Percentage difference from the best price on buy side
spread_asks: 0.0015 # Percentage difference from the best price on sell side
limit_asks_base: 0.08 # The amount of base currency that will be placed for sale in the order book, if have enough balance
limit_bids_base: 0.08 # The amount of base currency that will be placed for buy in the order book, if have enough balance in quote currency equivalent
max_amount_per_order: 0.014 # Limit amount of base currency per order (the small amount are, the bigger number of orders at the same price will be created)
levels_size: 1 # Minimum price difference between price points
levels_count: 10 # Maximum amount of price points that may be created
side: both # Side, ask, bid or both to apply the strategy on
target:
account_id: opendax_target # Unique account id, from the account section, that will be used as a target (your exchange)
market_id: btctestusdt # Market pair code in lowercase, from your target exchange
sources:
- account_id: binance_source # Unique account id, from the account section, that will be used as a source
market_id: BTCUSDT # Market pair code in uppercase, from you source exchange
#---------------------------{Microtrades-Market strategy}-----------------------------------
- id: microtrades-BTCUSD # Name of a strategy
type: microtrades-market # Type of the strategy
debug: true # True to see extra Arke logs
enabled: true # True to run this strategy after Arke (re)startgit
period: 10 # Period between micro trades
period_random_delay: 13 # Random delay applied to a period
params:
linked_strategy_id: copy-BTCUSD # Strategy that microtrade links to, to calculate order price
min_amount: 0.000001 # Minimum amount of order
max_amount: 0.00009 # Maximum amount of order
target:
account_id: opendax_target # Unique account id, from the account section, that will be used as a target (your exchange)
market_id: btctestusdt # Market pair code in lowercase, from your target exchange
# log_level: INFO
# accounts:
# - id: 1
# driver: bitfaker
# debug: false
# host: "http://www.app.local"
# ws: "ws://www.app.local"
# key: ""
# secret: ""
# delay: 1
# - id: 2
# driver: bitfaker
# host: "api.binance.com"
# key:
# secret:
# delay: 1
# strategies:
# - id: 1
# type: copy
# debug: true
# enabled: true
# period: 10
# params:
# spread_bids: 0.003
# spread_asks: 0.003
# limit_asks_base: 0.05
# limit_bids_base: 0.05
# levels_size: 0.25
# levels_count: 10
# side: both
# enable_orderback: false
# target:
# account_id: 1
# market:
# id: BTCUSD
# base: btc
# quote: usd
# base_precision: 2
# quote_precision: 2
# min_ask_amount: 1.5
# min_bid_amount: 1.5
# sources:
# - account_id: 2
# market:
# id: BTCUSD
# base: BTC
# quote: USD
# base_precision: 8
# quote_precision: 8
# min_order_back_amount: 1.5
# - id: 2
# type: microtrades
# debug: true
# period: 5
# period_random_delay: 10
# params:
# linked_strategy_id: 1
# min_amount: 0.05
# max_amount: 10
# min_price: 100
# max_price: 1000
# target:
# account_id: 1
# market:
# id: BTCUSD
# base: btc
# quote: usd
# base_precision: 2
# quote_precision: 2
# min_ask_amount: 1.5
# min_bid_amount: 1.5
# strategy:
# type: copy
# volume_ratio: 0.1
# target:
# driver: rubykube
# market: 'FTHUSD'
# host: "http://www.app.local"
# key: ""
# secret: ""
# rate_limit: 1
# sources:
# - driver: bitfaker
# market: 'tETHUSD'
# host: "api.bitfinex.com"
# key: ""
# secret: ""
# rate_limit: 0.2
# - driver: bitfinex
# market: 'tETHUSD'
# host: "api.bitfinex.com"
# key: ""
# secret: ""
# rate_limit: 0.2
# - driver: binance
# market: 'ETHUSDT'
# host: "api.binance.com"
# key: ""
# secret: ""
# rate_limit: 0.2

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

0
data/parity/.gitkeep Normal file
View File

View File

@@ -0,0 +1,94 @@
<div dir="rtl">
# Alvand-P — QA و عیب‌یابی (Fibitex)
چک‌لیست عملیاتی برای staging (`beta.fibitex.com`) و لوکال. جزئیات deploy: [`Docs/Fibitex-staging-deploy.md`](../../Docs/Fibitex-staging-deploy.md).
## قبل از deploy
- [ ] `git pull` روی `Update2026`
- [ ] `bundle install` (در صورت تغییر Gemfile)
- [ ] `rake render:config`**بدون EPERM** روی `config/frontend/shahoo.env.js`
- [ ] Vault unsealed — [`scripts/unseal-vault.ps1`](../../scripts/unseal-vault.ps1) یا `rake vault:setup`
- [ ] `COMPOSE_FILE` درست (همه composeهای لازم)
## render:config / EPERM
| علامت | رفع |
|--------|-----|
| `shahoo.env.js` directory به‌جای فایل | پوشهٔ اشتباه را حذف؛ `rake render:config` دوباره |
| EPERM روی Windows | ترمینال admin یا exclude antivirus روی `config/` |
| تغییر template اعمال نشد | `rake render:config` نه فقط `restart` |
## Vault sealed
<div dir="ltr">
```bash
docker compose exec vault vault status
# Sealed → unseal با keys از ops
```
</div>
لوکال: `.\scripts\unseal-vault.ps1`
## Compose logging — recreate نه restart
`logging:` در compose فقط هنگام **create** کانتینر اعمال می‌شود.
<div dir="ltr">
```bash
export COMPOSE_FILE=compose/app.yaml:compose/backend.yaml:compose/gateway.yaml:compose/proxy.yaml:compose/daemons.yaml:compose/frontend.yaml
docker compose -p fibitex up -d --force-recreate
docker inspect fibitex_peatio_1 --format '{{.HostConfig.LogConfig.Type}} {{.HostConfig.LogConfig.Config}}'
```
</div>
## دو stack Carbon موازی
**هرگز** هم‌زمان `carbon` (legacy path) و `carbon_platform` با `-p carbon` up نکنید — لاگ و دیتا duplicate می‌شود.
فقط: `docker compose -p carbon -f docker-compose.prod.yml -f docker-compose.traefik.yml`
## Smoke tests
<div dir="ltr">
```bash
curl -sS -o /dev/null -w '%{http_code}\n' https://beta.fibitex.com/
curl -sS -o /dev/null -w '%{http_code}\n' https://shahoo.fibitex.com/health
docker compose -p fibitex ps
bash ~/main-code/scripts/check-docker-log-disk.sh
```
</div>
## دیسک / لاگ Docker
| علامت | اقدام |
|--------|--------|
| root >85% | `check-docker-log-disk.sh` exit 1 — `sudo truncate-docker-logs.sh` |
| لاگ یک کانتینر >100MB | truncate (نیاز sudo) یا `--force-recreate` بعد از log rotation |
| cron | `crontab -l` — هر ۶ ساعت → `~/log-disk-check.log` |
ارجاع: [`Docs/Fibitex-staging-deploy.md`](../../Docs/Fibitex-staging-deploy.md) §۸.۳، [`Docs/07-setup-server.md`](../../Docs/07-setup-server.md) §۶.۲
## Shahoo / BFF
- BFF: [`Shahoo-BFF/README.md`](../../Shahoo-BFF/README.md)
- E2E: `.\scripts\test-shahoo-e2e.ps1`
## مستندات مرتبط
| سند | موضوع |
|-----|--------|
| [`Docs/Fibitex-staging-deploy.md`](../../Docs/Fibitex-staging-deploy.md) | Deploy staging |
| [`Docs/07-setup-server.md`](../../Docs/07-setup-server.md) | Production |
| [`Docs/06-setup-local.md`](../../Docs/06-setup-local.md) | لوکال |
| [`Docs/troubleshoot-barong-authz.md`](troubleshoot-barong-authz.md) | Barong authz |
| [`carbon_platform/Docs/QA-troubleshooting.md`](../../carbon_platform/Docs/QA-troubleshooting.md) | Carbon |
</div>

83
docs/aws-install.md Normal file
View File

@@ -0,0 +1,83 @@
# AWS Installation Guide
## Step 1: Prepare the infrastructure
Infrastructural requirements for the installation are:
- An EC2 m5.xlarge **Debian** instance with a 200 GB disk storage
- An Elastic Container Registry repository with the baseapp image
- A DNS record to point to the machine(e.g. `example.domain.com`)
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.
## Step 2: Configure the instance
Connect to the instance over SSH as a `root`/`admin` user and perform the following steps.
### Core dependencies
```bash
apt-get update
apt-get install -y -q git tmux gnupg2 dirmngr dbus htop curl libmariadbclient-dev-compat build-essential
```
### Docker installation
```bash
curl -fsSL https://get.docker.com/ | bash
usermod -a -G docker $USER
COMPOSE_VERSION="1.23.2"
COMPOSE_URL="https://github.com/docker/compose/releases/download/$COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)"
curl -L "$COMPOSE_URL" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
```
### User creation
```bash
groupadd app
useradd --create-home --home /home/app --shell /bin/bash \
--gid app --groups docker,sudo app
```
### Ruby installation
As the `app` user(`sudo su app`), run:
```bash
gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
curl -sSL https://get.rvm.io | bash -s stable
source /home/app/.rvm/scripts/rvm
rvm install --quiet-curl 2.6.1
rvm use --default 2.6.1
gem install bundler
```
## Step 3: Prepare the deployment
Clone the opendax repo to `/home/app`
```bash
git clone git@git.openware.com:opendax
```
`cd` into the `opendax` directory and prepare `config/app.yml` according to the [README](../README.md).
When the configuration is ready, run
```bash
bundle install
rake render:config
rake parity:import && \
until rake wallet:create['deposit','http://0.0.0.0:8545','changeme']; do sleep 15; done && \
rake wallet:create['hot','http://0.0.0.0:8545','changeme'] && \
rake wallet:create['warm','http://0.0.0.0:8545','changeme'] && \
rake render:config && \
rake service:all && \
chmod +x bin/install_webhook
./bin/install_webhook
```
After the deployment process is finished, the frontend would be accessible from the domain provided in the configuration.

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,148 @@
# Troubleshoot barong authorization process and envoy routing
## Architecture overview
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.
![OpenDAX authorization](./images/OpenDAX-authorization.png)
## Enable envoy debug logs
To troubleshoot connection problems with a microservice of the stack, you can enable envoy logs to understand in which step the connection problem appears.
To do so you need to:
1. Edit *templates/compose/gateway.yaml.erb*
2. Change *info* by *debug* in the following lines:
```yaml
command: /usr/local/bin/envoy -l debug -c /etc/envoy/envoy.yaml
```
3. Render the configuration files
```bash
rake render:config
```
4. Restart envoy
```bash
docker-compose up -dV gateway
```
5. Finally you can inspect the envoy logs
```bash
docker-compose logs -f --tail 100 gateway
```
Here are the relevant logs:
1. Initial websocket connection
```log
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):
gateway_1 | ':authority', 'www.app.local'
gateway_1 | ':path', '/api/v2/ranger/private/?stream=global.tickers'
gateway_1 | ':method', 'GET'
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'
gateway_1 | 'accept-encoding', 'gzip, deflate'
gateway_1 | 'accept-language', 'en-US,en;q=0.9,fr;q=0.8'
gateway_1 | 'cache-control', 'no-cache'
gateway_1 | 'connection', 'Upgrade'
gateway_1 | 'cookie', '_barong_session=4cff598ee40d3d2ec38875ddc904fc46'
gateway_1 | 'origin', 'http://www.app.local'
gateway_1 | 'pragma', 'no-cache'
gateway_1 | 'sec-websocket-key', 'b16LunIyXls4CtNZ1lYWsw=='
gateway_1 | 'sec-websocket-extensions', 'permessage-deflate; client_max_window_bits'
gateway_1 | 'sec-websocket-version', '13'
gateway_1 | 'upgrade', 'websocket'
gateway_1 | 'x-forwarded-for', '172.20.0.1'
gateway_1 | 'x-forwarded-host', 'www.app.local'
gateway_1 | 'x-forwarded-port', '80'
gateway_1 | 'x-forwarded-proto', 'ws'
gateway_1 | 'x-forwarded-server', '41e065adb32e'
gateway_1 | 'x-real-ip', '172.20.0.1'
```
2. Request to Barong authz
```log
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'
gateway_1 | [2020-12-02 07:50:30.184][13][debug][router] [source/common/router/router.cc:381] [C0][S3254558628791445120] router decoding headers:
gateway_1 | ':method', 'GET'
gateway_1 | ':path', '/api/v2/auth/api/v2/ranger/private/?stream=global.tickers'
gateway_1 | ':authority', 'www.app.local'
gateway_1 | ':scheme', 'http'
gateway_1 | 'content-length', '0'
gateway_1 | 'x-forwarded-for', '172.20.0.1,172.20.0.8'
gateway_1 | 'cookie', '_barong_session=4cff598ee40d3d2ec38875ddc904fc46'
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'
gateway_1 | 'x-forwarded-host', 'www.app.local'
gateway_1 | 'x-forwarded-proto', 'ws'
gateway_1 | 'x-envoy-internal', 'true'
gateway_1 | 'x-envoy-expected-rq-timeout-ms', '1000'
```
3. Routing the connection to rango
```log
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
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'
gateway_1 | [2020-12-02 07:50:30.220][13][debug][router] [source/common/router/router.cc:381] [C186][S2592169017517480399] router decoding headers:
gateway_1 | ':authority', 'www.app.local'
gateway_1 | ':path', '/api/v2/ranger/private/?stream=global.tickers'
gateway_1 | ':method', 'GET'
gateway_1 | ':scheme', 'http'
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'
gateway_1 | 'accept-encoding', 'gzip, deflate'
gateway_1 | 'accept-language', 'en-US,en;q=0.9,fr;q=0.8'
gateway_1 | 'cache-control', 'no-cache'
gateway_1 | 'connection', 'Upgrade'
gateway_1 | 'cookie', '_barong_session=4cff598ee40d3d2ec38875ddc904fc46'
gateway_1 | 'origin', 'http://www.app.local'
gateway_1 | 'pragma', 'no-cache'
gateway_1 | 'sec-websocket-key', 'tocGzAPK8TACk8zzRX7n3g=='
gateway_1 | 'sec-websocket-extensions', 'permessage-deflate; client_max_window_bits'
gateway_1 | 'sec-websocket-version', '13'
gateway_1 | 'upgrade', 'websocket'
gateway_1 | 'x-forwarded-for', '172.20.0.1'
gateway_1 | 'x-forwarded-host', 'www.app.local'
gateway_1 | 'x-forwarded-port', '80'
gateway_1 | 'x-forwarded-proto', 'ws'
gateway_1 | 'x-forwarded-server', '41e065adb32e'
gateway_1 | 'x-real-ip', '172.20.0.1'
gateway_1 | 'content-length', '0'
gateway_1 | 'x-envoy-internal', 'true'
gateway_1 | 'x-request-id', '5b87e64a-4155-498e-916c-b8b998725a71'
gateway_1 | 'x-envoy-expected-rq-timeout-ms', '15000'
gateway_1 | ':status', '200'
gateway_1 | 'authorization', 'Bearer eyJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE2MDY4OTU0MzAsImV4cCI6MTYwNjg5OTAzMCwic3ViIjoic2Vzc2lvbiIsImlzcyI6ImJhcm9uZyIsImF1ZCI6WyJwZWF0aW8iLCJiYXJvbmciXSwianRpIjoiNTllNGIwNTA3YTgyMGNjMzYzMTIiLCJ1aWQiOiJJRDVGRkE5OERDMjciLCJlbWFpbCI6ImFkbWluQGJhcm9uZy5pbyIsInJvbGUiOiJhZG1pbiIsImxldmVsIjozLCJzdGF0ZSI6ImFjdGl2ZSIsInJlZmVycmFsX2lkIjpudWxsfQ.Br6-yujI5MgU_BktVDYNaEPNtHOMxQZbNS89deQfxNiPPkx6B8ZUDXL9og5DQ6nWBExlHydyPPcCSUvO5BCth_UWiuttY_ldy7TIr_JrXT0td8WN8fq8QadOWFuJ7wvMEklRGVKQmvOrooHNKz_WwcY4xmaSO3SVgQdFSkmt626MOXmo9Wa3nYsL6EafCMe--9PHWop4L-B1w5ndvbGuGLbJaqEktXsudOX0A9Js2sKuHPxSe8QJKN5XwmOFPAWM28-VkaU5cmshMK2CwJaSRhVoL0gIi9VUGpFVVJ1ciD0VHjRfxuFTzph7utRuO_M9N-bweLL8YCCA8RkwlVyuLg'
gateway_1 | 'content-type', 'text/html; charset=utf-8'
gateway_1 | 'cache-control', 'no-cache'
gateway_1 | 'set-cookie', '_barong_session=4cff598ee40d3d2ec38875ddc904fc46; path=/; expires=Thu, 03 Dec 2020 07:50:30 GMT; HttpOnly'
gateway_1 | 'x-request-id', '8ff80928-9091-40b0-b6f0-c0b46f8d72fe'
gateway_1 | 'x-runtime', '0.031033'
gateway_1 | 'vary', 'Origin'
gateway_1 | 'transfer-encoding', 'chunked'
gateway_1 | 'x-envoy-upstream-service-time', '37'
```
## Authz configuration
In case of authorization problem check the following configuration files:
1. *config/barong/authz_rules.yml*
This file contains the default public endpoints and blocked endpoints.
If you have a problem accessing a public endpoint make sure the URL is present in the *rules.pass* section.
2. *templates/config/barong/seeds.yml.erb*
Check the *permissions* section to make sure the role of the user is allowed to access the resource.
Run the following command to apply the changes:
```bash
rake service:setup
```

91
docs/ubuntu-install.md Normal file
View File

@@ -0,0 +1,91 @@
# Install OpenDax in Ubuntu 18.04
## Step 1: Install Docker
To install Docker you will need to do those steps with `sudo` or login as root user with `sudo -i`
Create a Unix user for holding your application
```
groupadd app
useradd -d /home/app -s `which bash` -g app -m app
```
### Installing from apt-get
First, update your existing list of packages:
```
apt update
```
Next, install a few prerequisite packages which let apt use packages over HTTPS:
```
apt install apt-transport-https ca-certificates curl software-properties-common
```
Then add the GPG key for the official Docker repository to your system:
```
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
```
Add the Docker repository to APT sources:
```
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"
```
Next, update the package database with the Docker packages from the newly added repo:
```
apt update
```
Make sure you are about to install from the Docker repo instead of the default Ubuntu repo:
Finally, install Docker:
```
apt install docker-ce
```
Docker should now be installed, the daemon started, and the process enabled to start on boot. Check that it's running:
```
systemctl status docker
```
Add your app user into the docker group
```
usermod -aG docker app
```
## Step 2: Install Docker Compose
Run this command to download the latest version of Docker Compose:
```
curl -L "https://github.com/docker/compose/releases/download/1.23.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
```
## Step 3: Clone OpenDax
Login to your app user:
```
su - app
```
Clone opendax repository
```
cd $HOME
git clone https://github.com/rubykube/opendax.git
cd opendax
```
## Step 4: Clone your frontend
Edit config file `config/app.yml`

View File

@@ -0,0 +1,71 @@
# frozen_string_literal: true
require 'yaml'
module Opendax
# Loads config/app.yml and deep-merges an environment overlay when present.
#
# Overlay resolution (first match wins):
# 1. OPENDAX_ENV=local|staging|production → config/app.{env}.yml
# 2. If OPENDAX_ENV unset and config/app.local.yml exists → use local overlay
#
# Never commit real secrets to config/app.yml — use app.local.yml or app.production.yml.
module ConfigLoader
BASE_PATH = 'config/app.yml'
module_function
def load
base = load_yaml_hash!(BASE_PATH, 'base config')
overlay_path = resolve_overlay_path
return base unless overlay_path && File.exist?(overlay_path)
overlay = load_yaml_hash!(overlay_path, 'overlay config')
deep_merge(base, overlay)
end
def load_yaml_hash!(path, label)
data = YAML.load_file(path)
return data if data.is_a?(Hash)
raise TypeError,
"#{label} #{path} must be a YAML mapping (Hash), got #{data.class}. " \
'Check syntax — quote values that contain colons (e.g. database passwords).'
end
def resolve_overlay_path
env = ENV['OPENDAX_ENV'].to_s.strip
if env.empty?
return 'config/app.local.yml' if File.exist?('config/app.local.yml')
return nil
end
"config/app.#{env}.yml"
end
def active_overlay
path = resolve_overlay_path
path if path && File.exist?(path)
end
def deep_merge(base, overlay)
unless base.is_a?(Hash) && overlay.is_a?(Hash)
raise TypeError,
"deep_merge expects Hash + Hash, got #{base.class} + #{overlay.class}"
end
base.merge(overlay) do |key, old_val, new_val|
if old_val.is_a?(Hash) && new_val.is_a?(Hash)
deep_merge(old_val, new_val)
elsif old_val.is_a?(Hash) && !new_val.is_a?(Hash)
raise TypeError,
"Config type mismatch at #{key}: base has Hash but overlay has " \
"#{new_val.class}. Quote scalar values in app.staging.yml (passwords with ':' need quotes)."
else
new_val
end
end
end
end
end

46
lib/opendax/payload.rb Normal file
View File

@@ -0,0 +1,46 @@
require 'jwt'
module Opendax
class Error < StandardError
end
class Payload
def initialize(params)
@secret = params[:secret]
@expire = params[:expire] || 600
raise Opendax::Error.new unless @secret
raise Opendax::Error.new unless @expire > 0
end
def generate!(params)
raise Opendax::Error.new unless params[:service]
raise Opendax::Error.new unless params[:image]
token = params.merge({
'iat': Time.now.to_i,
'exp': (Time.now + @expire).to_i
})
JWT.encode token, @secret, 'HS256'
end
def decode!(token)
JWT.decode(token, @secret, true, {
algorithm: 'HS256'
}).first
end
def safe_decode(token)
begin
decode!(token)
rescue JWT::ExpiredSignature
rescue JWT::ImmatureSignature
rescue JWT::VerificationError
rescue JWT::DecodeError
nil
end
end
end
end

79
lib/opendax/renderer.rb Normal file
View File

@@ -0,0 +1,79 @@
# frozen_string_literal: true
require 'openssl'
require 'sshkey'
require 'pathname'
require 'yaml'
require 'base64'
require 'fileutils'
module Opendax
# Renderer is class for rendering Opendax templates.
class Renderer
TEMPLATE_PATH = Pathname.new('./templates')
BARONG_KEY = 'config/secrets/barong.key'
APPLOGIC_KEY = 'config/secrets/applogic.key'
SSH_KEY = 'config/secrets/app.key'
def render
@config ||= config
@utils ||= utils
@name ||= @config['app']['name'].downcase
@barong_key ||= OpenSSL::PKey::RSA.new(File.read(BARONG_KEY), '')
@applogic_key ||= OpenSSL::PKey::RSA.new(File.read(APPLOGIC_KEY), '')
@barong_private_key ||= Base64.urlsafe_encode64(@barong_key.to_pem)
@barong_public_key ||= Base64.urlsafe_encode64(@barong_key.public_key.to_pem)
@applogic_private_key ||= Base64.urlsafe_encode64(@applogic_key.to_pem)
@applogic_public_key ||= Base64.urlsafe_encode64(@applogic_key.public_key.to_pem)
Dir.glob("#{TEMPLATE_PATH}/**/*.erb", File::FNM_DOTMATCH).each do |file|
output_file = template_name(file)
FileUtils.chmod 0o644, output_file if File.exist?(output_file)
render_file(file, output_file)
FileUtils.chmod 0o444, output_file if @config['render_protect']
end
end
def render_file(file, out_file)
puts "Rendering #{out_file}"
result = ERB.new(File.read(file), trim_mode: '-').result(binding)
dir = File.dirname(out_file)
FileUtils.mkdir(dir) unless Dir.exist?(dir)
File.write(out_file, result)
end
def ssl_helper(arg)
@config['ssl']['enabled'] ? arg << 's' : arg
end
def template_name(file)
path = Pathname.new(file)
out_path = path.relative_path_from(TEMPLATE_PATH).sub('.erb', '')
File.join('.', out_path)
end
def render_keys
generate_key(BARONG_KEY)
generate_key(APPLOGIC_KEY)
generate_key(SSH_KEY, public: true)
end
def generate_key(filename, public: false)
return if File.file?(filename)
key = SSHKey.generate(type: 'RSA', bits: 2048)
File.write(filename, key.private_key)
File.write("#{filename}.pub", key.ssh_public_key) if public
end
def config
Opendax::ConfigLoader.load
end
def utils
YAML.load_file('./config/utils.yml')
end
end
end

81
lib/opendax/vault.rb Normal file
View File

@@ -0,0 +1,81 @@
# frozen_string_literal: true
module Opendax
class Vault
POLICIES_NAMES = ["barong", "finex_engine", "peatio_rails", "peatio_crypto", "peatio_upstream", "peatio_matching"]
def vault_secrets_path
'config/vault-secrets.yml'
end
def vault_exec(command)
`docker-compose exec -T vault sh -c '#{command}'`
end
def secrets(command, endpoints, options = '')
endpoints.each { |endpoint| vault_exec("vault secrets #{command} #{options} #{endpoint}") }
end
def setup
puts '----- Checking Vault status -----'
vault_status = YAML.safe_load(vault_exec('vault status -format yaml'))
return if vault_status.nil?
if vault_status['initialized']
puts '----- Vault is initialized -----'
begin
vault_secrets = YAML.safe_load(File.read(vault_secrets_path))
rescue SystemCallError => e
puts 'Vault keys are missing'
return
end
vault_root_token = vault_secrets['root_token']
unseal_keys = vault_secrets['unseal_keys_b64'][0, 3]
else
puts '----- Initializing Vault -----'
vault_init_output = YAML.safe_load(vault_exec('vault operator init -format yaml --recovery-shares=3 --recovery-threshold=2'))
File.write(vault_secrets_path, YAML.dump(vault_init_output))
vault_root_token = vault_init_output['root_token']
unseal_keys = vault_init_output['unseal_keys_b64'][0, 3]
end
if vault_status['sealed']
puts '----- Unsealing Vault -----'
unseal_keys.each { |key| vault_exec("vault operator unseal #{key}") }
else
puts '----- Vault is unsealed -----'
end
return vault_root_token if vault_status['initialized']
puts '----- Vault login -----'
vault_exec("vault login #{vault_root_token}")
puts '----- Configuring the endpoints -----'
secrets('enable', %w[totp transit])
secrets('disable', ['secret'])
secrets('enable', ['kv'], '-path=secret -version=1')
vault_root_token
end
def load_policies(deployment_name, vault_root_token)
puts '----- Vault login -----'
vault_exec("vault login #{vault_root_token}")
tokens = {}
POLICIES_NAMES.each do |policy|
name = "#{deployment_name.downcase}_#{policy}"
puts "Loading #{name} policy..."
vault_exec("vault policy write #{name} /tmp/policies/#{policy}.hcl")
puts "Creating the #{name} token..."
vault_token_create_output = YAML.safe_load(vault_exec("vault token create -policy=#{name} -renewable=true -ttl=240h -period=240h -format=yaml"))
tokens["#{policy}_token"] = vault_token_create_output["auth"]["client_token"]
end
tokens
end
end
end

74
lib/opendax/webhook.rb Normal file
View File

@@ -0,0 +1,74 @@
require 'sinatra/base'
require 'json'
require 'yaml'
require_relative 'payload'
require_relative 'renderer'
class Webhook < Sinatra::Base
CONFIG_PATH = 'config/app.yml'.freeze
set :show_exceptions, false
def initialize
super
@services = %w[barong peatio frontend AdminTower applogic finex-engine finex-api]
secret = ENV['WEBHOOK_JWT_SECRET']
raise 'WEBHOOK_JWT_SECRET is not set' if secret.to_s.empty?
@decoder = Opendax::Payload.new(secret: secret)
end
def update_config(service, image)
config = YAML.load_file(CONFIG_PATH)
config["images"][service] = image
File.open(CONFIG_PATH, 'w') {|f| f.write config.to_yaml }
end
before do
content_type 'application/json'
end
get '/deploy/ping' do
'pong'
end
get '/deploy/:token' do |token|
decoded = @decoder.safe_decode(token)
return answer(400, 'invalid token') unless decoded
service = decoded['service']
image = decoded['image']
return answer(400, 'service is not specified') unless service
return answer(400, 'image is not specified') unless image
return answer(404, 'unknown service') unless @services.include? service
return answer(400, 'invalid image') if (%r(^(([-_\w\.]){,20}(\/|:))+([-\w\.]{,20})$) =~ image) == nil
system "docker image pull #{image}"
unless $?.success?
system("docker image inspect #{image} > /dev/null")
return answer(404, 'invalid image') unless $?.success?
end
if $?.success?
update_config(service, image)
renderer = Opendax::Renderer.new
renderer.render
system "docker-compose up -Vd #{service}"
end
return answer(500, 'could not restart container') unless $?.success?
return answer(200, "service #{service} updated with image #{image}")
end
def answer(response_status, message)
status response_status
{
message: message
}.to_json
end
end

22
lib/tasks/audit.rake Normal file
View File

@@ -0,0 +1,22 @@
namespace :audit do
desc 'Print CVE audit commands (run via Docker on this machine)'
task :help do
puts <<~HELP
Fibitex dependency CVE audit see Docs/10-cve-audit.md
Ruby (Dena):
docker run --rm -v "#{Dir.pwd}/../Dena:/app" -w /app ruby:2.6.6 bash -c "gem install bundler:2.1.4 bundler-audit --no-document && bundle audit check --update"
Ruby (Dalan):
docker run --rm -v "#{Dir.pwd}/../Dalan:/app" -w /app ruby:2.6.6 bash -c "gem install bundler:2.1.4 bundler-audit --no-document && bundle audit check --update"
OSV (summary):
docker run --rm -v "#{Dir.pwd}/../Dena:/src" ghcr.io/google/osv-scanner:latest -L /src/Gemfile.lock
docker run --rm -v "#{Dir.pwd}/../Dalan:/src" ghcr.io/google/osv-scanner:latest -L /src/Gemfile.lock
docker run --rm -v "#{Dir.pwd}/../Gereh:/src" ghcr.io/google/osv-scanner:latest -L /src/yarn.lock
Config secrets check:
bundle exec rake config:check
HELP
end
end

47
lib/tasks/config.rake Normal file
View File

@@ -0,0 +1,47 @@
namespace :config do
desc 'Verify config/app.yml contains no real secrets (safe for git)'
task :check do
require_relative '../opendax/config_loader'
raw = YAML.load_file('config/app.yml')
leaks = []
check_value = lambda do |path, value|
return if value.nil?
return unless value.is_a?(String)
str = value.strip
return if str.empty? || str == 'changeme'
if str.match?(/\As\.[A-Za-z0-9]{20,}\z/)
leaks << "#{path}: looks like a Vault token"
elsif path.include?('password') && str != 'changeme'
leaks << "#{path}: non-placeholder password"
end
end
walk = lambda do |node, prefix|
case node
when Hash
node.each { |k, v| walk.call(v, prefix.empty? ? k.to_s : "#{prefix}.#{k}") }
when Array
node.each_with_index { |v, i| walk.call(v, "#{prefix}[#{i}]") }
else
check_value.call(prefix, node)
end
end
walk.call(raw, '')
if leaks.any?
puts 'FAIL: config/app.yml may contain secrets:'
leaks.each { |l| puts " - #{l}" }
puts 'Move sensitive values to config/app.local.yml or config/app.production.yml'
exit 1
end
overlay = Opendax::ConfigLoader.active_overlay
puts 'OK: config/app.yml looks safe for git'
puts "Active overlay: #{overlay || 'none'}"
end
end

32
lib/tasks/db.rake Normal file
View File

@@ -0,0 +1,32 @@
namespace :db do
def mysql_cli
return "mysql -u root -h db -P 3306 -pchangeme"
end
desc 'Create database'
task :create do
sh 'docker-compose run --rm peatio bundle exec rake db:create'
sh 'docker-compose run --rm barong bundle exec rake db:create'
end
desc 'Load database dump'
task :load => :create do
sh %Q{cat data/mysql/peatio_production.sql | docker-compose run --rm db #{mysql_cli} peatio_production}
sh %Q{cat data/mysql/barong_production.sql | docker-compose run --rm db #{mysql_cli} barong_production}
sh 'docker-compose run --rm peatio bundle exec rake db:migrate'
sh 'docker-compose run --rm barong bundle exec rake db:migrate'
end
desc 'Drop all databases'
task :drop do
sh %q(docker-compose run --rm db /bin/sh -c "mysql -u root -h db -P 3306 -pchangeme -e 'DROP DATABASE peatio_production'")
sh %q(docker-compose run --rm db /bin/sh -c "mysql -u root -h db -P 3306 -pchangeme -e 'DROP DATABASE barong_production'")
sh %q(docker-compose run --rm db /bin/sh -c "mysql -u root -h db -P 3306 -pchangeme -e 'DROP DATABASE superset'")
end
desc 'Database Console'
task :console do
sh "docker-compose run --rm db #{mysql_cli}"
end
end

11
lib/tasks/docker.rake Normal file
View File

@@ -0,0 +1,11 @@
namespace :docker do
desc 'Stop all runnning docker contrainers'
task :down do
sh 'docker-compose down'
end
desc 'Clean up all docker volumes'
task :clean do
sh 'docker volume prune -f'
end
end

18
lib/tasks/payload.rake Normal file
View File

@@ -0,0 +1,18 @@
require_relative '../opendax/payload'
require 'faraday'
namespace :payload do
desc 'Generate JWT'
task :send, [:service, :image, :url] do |_, args|
secret = ENV['WEBHOOK_JWT_SECRET']
abort 'WEBHOOK_JWT_SECRET not set' if secret.to_s.empty?
coder = Opendax::Payload.new(secret: secret)
jwt = coder.generate!(service: args.service, image: args.image)
url = "#{args.url}/deploy/#{jwt}"
response = Faraday::Connection.new.get(url) do |request|
request.options.timeout = 300
end
pp response.body
fail unless response.status == 200
end
end

17
lib/tasks/render.rake Normal file
View File

@@ -0,0 +1,17 @@
require_relative '../opendax/renderer'
namespace :render do
desc 'Render configuration and compose files and keys'
task :config do
if (overlay = Opendax::ConfigLoader.active_overlay)
puts "Using config overlay: #{overlay}"
else
puts 'Using config/app.yml only (no overlay)'
end
renderer = Opendax::Renderer.new
renderer.render_keys
renderer.render
end
end

347
lib/tasks/service.rake Normal file
View File

@@ -0,0 +1,347 @@
namespace :service do
ENV['APP_DOMAIN'] = @config['app']['domain']
@switch = Proc.new do |args, start, stop|
case args.command
when 'start'
start.call
when 'stop'
stop.call
when 'restart'
stop.call
start.call
else
puts "unknown command #{args.command}"
end
end
desc 'Run Traefik (reverse-proxy)'
task :proxy, [:command] do |task, args|
args.with_defaults(:command => 'start')
def start
puts '----- Starting the proxy -----'
File.new('config/acme.json', File::CREAT, 0600) unless File.exist? 'config/acme.json'
sh 'docker-compose up -d proxy'
end
def stop
puts '----- Stopping the proxy -----'
sh 'docker-compose rm -fs proxy'
end
@switch.call(args, method(:start), method(:stop))
end
desc 'Run backend (vault db redis rabbitmq)'
task :backend, [:command] do |task, args|
args.with_defaults(:command => 'start')
def start
puts '----- Starting dependencies -----'
sh 'docker-compose up -d vault db redis rabbitmq'
sleep 7 # time for db to start, we can get connection refused without sleeping
end
def stop
puts '----- Stopping dependencies -----'
sh 'docker-compose rm -fs vault db redis rabbitmq'
end
@switch.call(args, method(:start), method(:stop))
end
desc 'Run influxdb'
task :influxdb, [:command] do |task, args|
args.with_defaults(:command => 'start')
def start
puts '----- Starting influxdb -----'
sh 'docker-compose up -d influxdb'
puts 'Wait 5 second for influx'
sleep(5)
sh 'docker-compose exec influxdb bash -c "cat peatio.sql | influx"'
end
def stop
puts '----- Stopping influxdb -----'
sh 'docker-compose rm -fs influxdb'
end
@switch.call(args, method(:start), method(:stop))
end
desc '[Optional] Run arke-maker'
task :arke_maker, [:command] do |task, args|
args.with_defaults(:command => 'start')
def start
puts '----- Starting arke -----'
sh 'docker-compose up -d arke-maker'
end
def stop
puts '----- Stopping arke -----'
sh 'docker-compose rm -fs arke-maker'
end
@switch.call(args, method(:start), method(:stop))
end
desc '[Optional] Run daemons (rango, peatio daemons, barong sidekiq)'
task :daemons, [:command] do |_task, args|
@daemons = %w[rango blockchain cron_job upstream deposit deposit_coin_address withdraw_coin influx_writer barong_sidekiq]
if @config['finex']['enabled']
@daemons |= %w[finex-engine finex-api]
else
@daemons |= %w[matching order_processor trade_executor]
end
args.with_defaults(:command => 'start')
def start
puts '----- Starting daemons -----'
sh "docker-compose up -d #{@daemons.join(' ')}"
end
def stop
puts '----- Stopping daemons -----'
sh "docker-compose rm -fs #{@daemons.join(' ')}"
end
@switch.call(args, method(:start), method(:stop))
end
desc '[Optional] Run cryptonodes'
task :cryptonodes, [:command] do |task, args|
args.with_defaults(:command => 'start')
def start
puts '----- Starting cryptonodes -----'
sh 'docker-compose up -d parity'
if @config['bitcoind']['enabled']
sh 'docker-compose up -d bitcoind'
end
end
def stop
puts '----- Stopping cryptonodes -----'
sh 'docker-compose rm -fs parity'
if @config['bitcoind']['enabled']
sh 'docker-compose rm -fs bitcoind'
end
end
@switch.call(args, method(:start), method(:stop))
end
desc 'Run setup hooks for peatio, barong'
task :setup, [:command] => ['vault:setup', 'vault:load_policies'] do |task, args|
if args.command != 'stop'
Rake::Task["render:config"].execute
puts '----- Running hooks -----'
sh 'docker-compose run --rm peatio bash -c "./bin/link_config && bundle exec rake db:create db:migrate"'
sh 'docker-compose run --rm peatio bash -c "./bin/link_config && bundle exec rake db:seed"'
sh 'docker-compose run --rm barong bash -c "./bin/init_config && bundle exec rake db:create db:migrate"'
sh 'docker-compose run --rm barong bash -c "./bin/link_config && bundle exec rake db:seed"'
if ENV.fetch('FIBITEX_SEED_TEST_USERS', 'true') != 'false'
puts '----- Seeding test users and balances -----'
sh 'docker-compose run --rm barong bash -c "bundle exec rails runner ./lib/seed_test_users.rb"'
sh 'docker-compose run --rm peatio bash -c "ruby ./bin/link_config && bundle exec rails runner ./lib/seed_test_balances.rb"'
end
end
end
desc 'Run mikro app (barong, peatio)'
task :app, [:command] => [:backend, :setup] do |task, args|
args.with_defaults(:command => 'start')
def start
puts '----- Starting app -----'
sh 'docker-compose up -d peatio barong gateway'
end
def stop
puts '----- Stopping app -----'
sh 'docker-compose rm -fs peatio barong gateway'
end
@switch.call(args, method(:start), method(:stop))
end
desc 'Run the frontend application'
task :frontend, [:command] do |task, args|
args.with_defaults(:command => 'start')
def start
puts '----- Starting the frontend -----'
sh 'docker-compose up -d frontend'
end
def stop
puts '----- Stopping the frontend -----'
sh 'docker-compose rm -fs frontend'
end
@switch.call(args, method(:start), method(:stop))
end
desc 'Run the tower application'
task :AdminTower, [:command] do |task, args|
args.with_defaults(:command => 'start')
def start
puts '----- Starting the AdminTower -----'
sh 'docker-compose up -d AdminTower'
end
def stop
puts '----- Stopping the AdminTower -----'
sh 'docker-compose rm -fs AdminTower'
end
@switch.call(args, method(:start), method(:stop))
end
desc 'Run Mailer'
task :mailer, [:command] do |task, args|
args.with_defaults(:command => 'start')
def start
puts '----- Starting Mailer -----'
sh 'docker-compose up -d mailer'
end
def stop
puts '----- Stopping Mailer -----'
sh 'docker-compose rm -fs mailer'
end
@switch.call(args, method(:start), method(:stop))
end
desc '[Optional] Run monitoring'
task :monitoring, [:command] do |task, args|
args.with_defaults(:command => 'start')
def start
puts '----- Starting monitoring -----'
sh 'docker-compose up -d prometheus'
sh 'docker-compose up -d grafana'
sh 'docker-compose up -d alertmanager'
sh 'docker-compose up -d loki'
sh 'docker-compose up -d promtail'
sh 'docker-compose up -d scope'
sh 'docker-compose up -d node-exporter'
sh 'docker-compose up -d cadvisor'
end
def stop
puts '----- Stopping monitoring -----'
sh 'docker-compose rm -fs prometheus'
sh 'docker-compose rm -fs grafana'
sh 'docker-compose rm -fs alertmanager'
sh 'docker-compose rm -fs loki'
sh 'docker-compose rm -fs promtail'
sh 'docker-compose rm -fs scope'
sh 'docker-compose rm -fs node-exporter'
sh 'docker-compose rm -fs cadvisor'
end
@switch.call(args, method(:start), method(:stop))
end
desc '[Optional] Run superset'
task :superset, [:command] do |task, args|
args.with_defaults(:command => 'start')
def start
conf = @utils['superset']
init_params = [
'--app', 'superset',
'--firstname', 'Admin',
'--lastname', 'Superset',
'--username', conf['username'],
'--email', conf['email'],
'--password', conf['password']
].join(' ')
puts '----- Initializing Superset -----'
sh [
'docker-compose run --rm superset',
'sh -c "',
"fabmanager create-admin #{init_params}",
'&& superset db upgrade',
# '&& superset load_examples',
'&& superset init"'
].join(' ')
puts '----- Starting Superset -----'
sh 'docker-compose up -d superset'
end
def stop
puts '----- Stopping Superset -----'
sh 'docker-compose rm -fs superset'
end
@switch.call(args, method(:start), method(:stop))
end
desc '[Optional] Run Blog'
task :blog, [:command] do |task, args|
args.with_defaults(:command => 'start')
def start
puts '----- Starting Blog_db -----'
sh 'docker-compose up -d blog_db'
puts '----- Starting Blog -----'
sh 'docker-compose up -d blog'
end
def stop
puts '----- Stopping Blog -----'
sh 'docker-compose rm -fs blog'
puts '----- Stopping Blog_db -----'
sh 'docker-compose rm -fs blog_db'
end
@switch.call(args, method(:start), method(:stop))
end
desc 'Set up and start all services with dependencies (does not run optional ones)'
task :all, [:command] => ['versions:update', 'render:config'] do |task, args|
args.with_defaults(:command => 'start')
def start
Rake::Task["service:proxy"].invoke('start')
Rake::Task["service:backend"].invoke('start')
Rake::Task["service:influxdb"].invoke('start')
puts 'Wait 5 second for backend'
sleep(5)
Rake::Task["service:setup"].invoke('start')
Rake::Task["service:app"].invoke('start')
Rake::Task["service:frontend"].invoke('start')
Rake::Task["service:AdminTower"].invoke('start')
Rake::Task["service:mailer"].invoke('start')
Rake::Task["service:daemons"].invoke('start')
end
def stop
Rake::Task["service:proxy"].invoke('stop')
Rake::Task["service:backend"].invoke('stop')
Rake::Task["service:influxdb"].invoke('stop')
Rake::Task["service:setup"].invoke('stop')
Rake::Task["service:app"].invoke('stop')
Rake::Task["service:frontend"].invoke('stop')
Rake::Task["service:AdminTower"].invoke('stop')
Rake::Task["service:mailer"].invoke('stop')
Rake::Task["service:daemons"].invoke('stop')
end
@switch.call(args, method(:start), method(:stop))
end
end

16
lib/tasks/terraform.rake Normal file
View File

@@ -0,0 +1,16 @@
namespace :terraform do
desc 'Initialize the Terraform configuration'
task :init do
Dir.chdir('terraform') { sh 'terraform init' }
end
desc 'Apply the Terraform configuration'
task :apply => ['render:config', :init] do
Dir.chdir('terraform') { sh 'terraform apply' }
end
desc 'Destroy the Terraform infrastructure'
task :destroy do
Dir.chdir('terraform') { sh 'terraform destroy' }
end
end

15
lib/tasks/test_seed.rake Normal file
View File

@@ -0,0 +1,15 @@
namespace :test do
desc 'Seed test users (Barong + Peatio balances) for local/test environments'
task seed: :environment do
if ENV.fetch('FIBITEX_SEED_TEST_USERS', 'true') == 'false'
puts 'SKIP test:seed (FIBITEX_SEED_TEST_USERS=false)'
next
end
puts '----- Seeding test users (Barong) -----'
sh 'docker-compose run --rm barong bash -c "bundle exec rails runner ./lib/seed_test_users.rb"'
puts '----- Seeding test balances (Peatio) -----'
sh 'docker-compose run --rm peatio bash -c "ruby ./bin/link_config && bundle exec rails runner ./lib/seed_test_balances.rb"'
end
end

12
lib/tasks/toolbox.rake Normal file
View File

@@ -0,0 +1,12 @@
namespace :toolbox do
desc 'Run the toolbox'
task :run do
run_cmd = %w[docker-compose run --rm toolbox run]
YAML.safe_load(File.read('config/toolbox.yaml'))
.transform_keys { |k| '--' << k }
.each_pair { |k, v| run_cmd << k << v.to_s }
sh *run_cmd
end
end

25
lib/tasks/vault.rake Normal file
View File

@@ -0,0 +1,25 @@
require_relative '../opendax/vault'
namespace :vault do
desc 'Initialize, unseal and set secrets for Vault'
task :setup do
vault = Opendax::Vault.new
vault_root_token = vault.setup
unless vault_root_token.nil?
@config["vault"]["root_token"] = vault_root_token
File.open(CONFIG_PATH, 'w') { |f| YAML.dump(@config, f) }
end
end
task :load_policies do
vault = Opendax::Vault.new
vault_tokens = vault.load_policies(@config["app"]["name"], @config["vault"]["root_token"])
unless vault_tokens.empty?
vault_tokens.each do |k, v|
@config["vault"][k] = v
File.open(CONFIG_PATH, 'w') { |f| YAML.dump(@config, f) }
end
end
end
end

Some files were not shown because too many files have changed in this diff Show More