Initial commit

This commit is contained in:
Yaser
2026-08-13 19:50:53 +03:30
commit 38084458fe
879 changed files with 95198 additions and 0 deletions

193
config/abilities.yml Normal file
View File

@@ -0,0 +1,193 @@
roles:
- superadmin
- admin
- technical
- accountant
- compliance
- support
- member
- broker
- trader
- maker
- sa_maker
admin_permissions:
superadmin:
manage:
- Operations::Account
- Operations::Asset
- Operations::Expense
- Operations::Liability
- Operations::Revenue
- Member
- Account
- Beneficiary
- PaymentAddress
- Deposit
- Withdraw
- WithdrawLimit
- Blockchain
- Currency
- Engine
- Market
- TradingFee
- Wallet
- Adjustment
- InternalTransfer
- WhitelistedSmartContract
read:
- Trade
- Order
create:
- Deposits::Fiat
update:
- Order
admin:
manage:
- Operations::Account
- Operations::Asset
- Operations::Expense
- Operations::Liability
- Operations::Revenue
- Beneficiary
- Deposit
- Withdraw
- WithdrawLimit
- DepositLimit
- Engine
- Market
- TradingFee
- Wallet
- Adjustment
- InternalTransfer
- WhitelistedSmartContract
- Currency
- Blockchain
read:
- Trade
- Order
- Account
- PaymentAddress
- Member
create:
- Deposits::Fiat
update:
- Order
- Member
technical:
read:
- Operations::Account
- Operations::Asset
- Operations::Expense
- Operations::Liability
- Trade
- Order
- Member
- InternalTransfer
manage:
- WithdrawLimit
- DepositLimit
- Blockchain
- Currency
- Engine
- Market
- TradingFee
- Wallet
- WhitelistedSmartContract
update:
- Order
accountant:
read:
- Operations::Account
- Operations::Asset
- Operations::Expense
- Operations::Liability
- Operations::Revenue
- Member
- Account
- Beneficiary
- PaymentAddress
- Deposit
- Withdraw
- WithdrawLimit
- DepositLimit
- Blockchain
- Currency
- Engine
- Market
- TradingFee
- Wallet
- Trade
- Order
- Adjustment
- InternalTransfer
create:
- Deposits::Fiat
- Adjustment
compliance:
read:
- Operations::Account
- Operations::Asset
- Operations::Expense
- Operations::Liability
- Member
- Account
- Beneficiary
- PaymentAddress
- Deposit
- Withdraw
- Currency
- Engine
- Market
- Trade
- Order
support:
read:
- Operations::Account
- Operations::Asset
- Operations::Expense
- Operations::Liability
- Member
- Account
- Beneficiary
- PaymentAddress
- Deposit
- Withdraw
- Currency
- Engine
- Market
- Trade
- Order
- InternalTransfer
user_permissions:
superadmin:
manage: all
admin:
manage: all
technical:
manage: all
accountant:
manage: all
compliance:
manage: all
support:
manage: all
member:
manage: all
broker:
manage: all
trader:
manage: all
maker:
manage: all
sa_maker:
read:
- Operations::Account
- Order
- Trade
- StatsMemberPnl
create:
- Order
update:
- Order

111
config/amqp.yml Normal file
View File

@@ -0,0 +1,111 @@
connect:
host: <%= ENV.fetch('RABBITMQ_HOST', 'localhost') %>
port: <%= ENV.fetch('RABBITMQ_PORT', '5672') %>
username: <%= ENV.fetch('RABBITMQ_USER', 'guest') %>
password: <%= ENV.fetch('RABBITMQ_PASSWORD', 'guest') %>
exchange:
trade:
name: peatio.trade
type: headers
notification:
name: peatio.notification
type: direct
orderbook:
name: peatio.orderbook
type: fanout
events:
name: peatio.events
type: direct
matching:
name: peatio.matching
type: direct
finex-spot:
name: finex.orderapi
type: direct
opendax:
name: finex.orderapi
type: direct
queue:
matching:
name: peatio.matching
durable: true
# You can set queue maximum length (see https://www.rabbitmq.com/maxlength.html).
# For order matching queue it is recommended to set limit about to 10000 per market.
# So in case you have 10 markets you would set 1000000. But this value is relative and depends on your business (market load).
#
# max_length: 10000
#
# Alternatively you can pass custom arguments here (for example in case your use RabbitMQ plugins):
#
# arguments:
# x-max-length: 10000
#
# When you change any parameter of queue definition it is required to drop it in RabbitMQ admin panel.
# In case you want this to be done transparently and automatically I recommend to set auto_delete to true.
#
# auto_delete: true
#
# In such case queue will be deleted automatically once all workers are disconnected. This should ensure queue
# is created from scratch with new configuration at next redeployment.
new_trade:
name: peatio.trade.new
durable: true
order_processor:
name: peatio.order.processor
durable: true
market_ticker:
name: peatio.trade.market_ticker
pusher_market:
name: peatio.pusher.market
pusher_member:
name: peatio.pusher.member
withdraw_coin:
name: peatio.withdraw.coin
deposit_collection_fees:
name: peatio.deposit.collection_fees
deposit_collection:
name: peatio.deposit.collection
deposit_coin_address:
name: peatio.deposit.coin.address
durable: true
influx_writer:
name: peatio.trade.writer
trade_error:
name: peatio.trades.errors
# Queue which used by third-party trading engine for updating balances and
# order submit consuming.
events_processor:
name: peatio.events.processor
binding:
matching:
queue: matching
clean_start: true
exchange: matching
trade_executor:
queue: new_trade
exchange: matching
order_processor:
queue: order_processor
exchange: matching
withdraw_coin:
queue: withdraw_coin
deposit_coin_address:
queue: deposit_coin_address
influx_writer:
queue: influx_writer
exchange: trade
trade_error:
queue: trade_error
exchange: matching
events_processor:
queue: events_processor
exchange: events
channel:
trade_executor:
prefetch: 5
order_processor:
prefetch: 5

58
config/application.rb Normal file
View File

@@ -0,0 +1,58 @@
# encoding: UTF-8
# frozen_string_literal: true
require_relative 'boot'
require 'rails'
%w( active_record action_controller action_view active_job ).each { |framework| require "#{framework}/railtie" }
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module Peatio
class Application < Rails::Application
# Eager loading app dir.
config.eager_load_paths += Dir[Rails.root.join('app')]
# Eager load constants from lib/peatio
# There is a lot of constants used over the whole application.
# lib/peatio/aasm/locking.rb => AASM::Locking
config.eager_load_paths += Dir[Rails.root.join('lib/peatio')]
# Configure Sentry as early as possible.
if ENV['SENTRY_DSN_BACKEND'].present?
require 'sentry-raven'
Raven.configure { |config| config.dsn = ENV['SENTRY_DSN_BACKEND'] }
end
# Require Scout.
require 'scout_apm' if Rails.env.in?(ENV['SCOUT_ENV'].to_s.split(',').map(&:squish))
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
config.time_zone = ENV.fetch('TIMEZONE')
# Configure relative url root by setting URL_ROOT_PATH environment variable.
# Used by microkube with API Gateway.
config.relative_url_root = ENV.fetch('URL_ROOT_PATH', '/')
# Remove cookies and cookies session.
config.middleware.delete ActionDispatch::Cookies
config.middleware.delete ActionDispatch::Session::CookieStore
# Disable CSRF.
config.action_controller.allow_forgery_protection = false
config.middleware.use ActionDispatch::Flash
env_file = File.join(Rails.root, 'peatio.env')
Dotenv.load(env_file) if File.exists?(env_file)
end
end

90
config/backend.yml Normal file
View File

@@ -0,0 +1,90 @@
version: '3'
services:
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
ports:
- "3306:3306"
influxdb:
image: influxdb:1.7.8
container_name: influxdb
ports:
- "8083:8083"
- "8086:8086"
volumes:
- ../db/influxdb.sql:/influxdb.sql
- influx_data:/var/lib/influxdb
environment:
INFLUXDB_ADMIN_ENABLED: "true"
redis:
image: redis:4.0
volumes:
- redis_data:/data
ports:
- "6379:6379"
rabbitmq:
image: rabbitmq:3.7.6-management
volumes:
- rabbitmq_data:/var/lib/rabbitmq
ports:
- "5672:5672"
- "15672:15672"
auth:
image: quay.io/openware/authz-dummy:0.1.1
ports:
- "8005:8005"
environment:
DUMMY_USER_EMAIL: "admin@barong.io"
DUMMY_USER_UID: "U123456789"
DUMMY_USER_ROLE: "superadmin"
DUMMY_USER_LEVEL: 3
DUMMY_USER_STATE: "active"
DUMMY_JWT_PRIVKEY_FILE: "/secrets/rsa-key"
DUMMY_JWT_TTL: 86400
volumes:
- ./secrets:/secrets:ro
gateway:
image: quay.io/datawire/ambassador:0.50.0-rc3
ports:
- "8080:80"
depends_on:
- auth
volumes:
- ./gateway:/ambassador/ambassador-config/:ro
entrypoint:
- sh
- -exc
- |
# Allow accessing host's 0.0.0.0 so we can connect to a local peatio
# from the gateway container
ip -4 route list match 0/0 | awk '{print $$3" peatio.local"}' >> /etc/hosts
ip -4 route list match 0/0 | awk '{print $$3" ws.local"}' >> /etc/hosts
# Continue with the default entrypoint
./entrypoint.sh
vault:
image: vault:1.0.1
ports:
- "8200:8200"
environment:
SKIP_SETCAP: 1
VAULT_TOKEN: ${VAULT_TOKEN}
VAULT_DEV_ROOT_TOKEN_ID: changeme
VAULT_ADDR: http://vault:8200
volumes:
influx_data:
db_data:
rabbitmq_data:
redis_data:

1
config/bench/usd-eur.csv Normal file

File diff suppressed because one or more lines are too long

7
config/boot.rb Normal file
View File

@@ -0,0 +1,7 @@
# encoding: UTF-8
# frozen_string_literal: true
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require 'bundler/setup' # Set up gems listed in the Gemfile.
require 'bootsnap/setup' # Speed up boot time by caching expensive operations.

19
config/cryptonodes.yml Normal file
View File

@@ -0,0 +1,19 @@
version: '2'
services:
parity:
image: parity/parity:stable
restart: always
command:
--chain=kovan
--jsonrpc-interface=all
--jsonrpc-hosts=all
ports:
- 8180:8180
- 8545:8545
volumes:
- parity:/root/.local/share/io.parity.ethereum/
user: root
volumes:
parity: {}

7
config/daemons.yml Normal file
View File

@@ -0,0 +1,7 @@
dir_mode: script
dir: ../../log
multiple: false
backtrace: true
monitor: false
ontop: false
log_output: true

30
config/database.yml Normal file
View File

@@ -0,0 +1,30 @@
default: &default
adapter: <%= ENV.fetch('DATABASE_ADAPTER', 'mysql2') %>
encoding: utf8
support_json: <%= ENV.fetch('DATABASE_SUPPORT_JSON', 'true') %>
collation: <%= ENV.fetch('DATABASE_COLLATION', 'utf8_general_ci') %>
pool: <%= ENV.fetch("RAILS_MAX_THREADS", 8).to_i * ENV.fetch("WEB_CONCURRENCY", 1).to_i %>
host: <%= ENV.fetch('DATABASE_HOST', '127.0.0.1') %>
port: <%= ENV.fetch('DATABASE_PORT', 3306) %>
username: <%= ENV.fetch('DATABASE_USER', 'root') %>
password: <%= ENV.fetch('DATABASE_PASS', 'changeme') %>
development:
<<: *default
database: peatio_development
test:
<<: *default
database: peatio_test
production:
<<: *default
database: <%= ENV.fetch('DATABASE_NAME', 'peatio_production') %>
archive_db:
<<: *default
url: <%= ENV['ARCHIVE_DATABASE_URL'] %>
database: <%= ENV.fetch('ARCHIVE_DATABASE_NAME', 'peatio_archive_db') %>
username: <%= ENV.fetch('ARCHIVE_DATABASE_USER', 'root') %>
password: <%= ENV['ARCHIVE_DATABASE_PASS'] %>
host: <%= ENV.fetch('ARCHIVE_DATABASE_HOST', '127.0.0.1') %>

7
config/environment.rb Normal file
View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
# Load the Rails application.
require_relative 'application'
# Initialize the Rails application.
Rails.application.initialize!

View File

@@ -0,0 +1,54 @@
# encoding: UTF-8
# frozen_string_literal: true
require File.expand_path('../shared', __FILE__)
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = false
# Do not eager load code on boot.
config.eager_load = false
# Show full error reports.
config.consider_all_requests_local = true
# Enable/disable caching. By default caching is disabled.
if Rails.root.join('tmp', 'caching-dev.txt').exist?
config.action_controller.perform_caching = true
config.cache_store = :memory_store
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{2.days.to_i}"
}
else
config.action_controller.perform_caching = false
config.cache_store = :redis_cache_store, { driver: :hiredis, url: ENV.fetch('REDIS_URL', 'redis://localhost:6379/1') }
end
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = true
# Use an evented file watcher to asynchronously detect changes in source code,
# routes, locales, etc. This feature depends on the listen gem.
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
# Bullet gem config.
config.after_initialize do
Bullet.enable = true if ENV['BULLET'] == 'true'
Bullet.bullet_logger = true
Bullet.add_footer = true
end
end

View File

@@ -0,0 +1,70 @@
# encoding: UTF-8
# frozen_string_literal: true
require File.expand_path('../shared', __FILE__)
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Attempt to read encrypted secrets from `config/secrets.yml.enc`.
# Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or
# `config/secrets.yml.key`.
# config.read_encrypted_secrets = true
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.public_file_server.enabled = true
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = ENV['FORCE_SECURE_CONNECTION'] == 'true'
# Prepend all log lines with the following tags.
config.log_tags = [ :request_id ]
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::JSONLogFormatter.new
# Use a different logger for distributed setups.
# require 'syslog/logger'
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
config.logger.formatter = config.log_formatter
# Disable colorize logging in production
config.colorize_logging = false
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
end

View File

@@ -0,0 +1,4 @@
# encoding: UTF-8
# frozen_string_literal: true
Dir[Rails.root.join('config/environments/shared/**/*.rb')].each { |p| require p }

View File

@@ -0,0 +1,10 @@
# encoding: UTF-8
# frozen_string_literal: true
Rails.application.configure do
if ENV.true?("REDIS_CLUSTER")
config.cache_store = :redis_cache_store, { driver: :hiredis, cluster: [ENV.fetch('REDIS_URL')], password: ENV.fetch('REDIS_PASSWORD') }
else
config.cache_store = :redis_cache_store, { driver: :hiredis, url: ENV.fetch('REDIS_URL') }
end
end

View File

@@ -0,0 +1,29 @@
# encoding: UTF-8
# frozen_string_literal: true
Rails.application.configure do
# Available levels (verbosity goes from high to less): debug, info, warn, error, fatal.
# Default level for production is warn, otherwise debug.
log_level = ENV['LOG_LEVEL'].presence || (Rails.env.production? ? :info : :debug)
config.log_formatter = Logger::Formatter.new
# In non-test environments logging always goes to STDOUT since this is the most appropriate way
# to get logs in Docker environment.
unless Rails.env.test?
config.logger = ActiveSupport::Logger.new STDERR, level: log_level
config.logger.formatter = config.log_formatter
end
# Prepend all log lines with the following tags.
# config.log_tags = [ :subdomain, :uuid ]
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# The configuration variables below will be used in case config.logger hasn't been set yet.
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = log_level
end

View File

@@ -0,0 +1,52 @@
# encoding: UTF-8
# frozen_string_literal: true
require File.expand_path('../shared', __FILE__)
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
config.eager_load = false
# Configure public file server for tests with Cache-Control for performance.
config.public_file_server.enabled = true
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{1.hour.to_i}"
}
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
routes.default_url_options = { host: 'test.host' }
# Randomize the order test cases are executed.
config.active_support.test_order = :random
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
# Bullet gem config.
config.after_initialize do
Bullet.enable = true if ENV['BULLET'] == 'true'
Bullet.bullet_logger = true
end
end

View File

@@ -0,0 +1,4 @@
apiVersion: ambassador/v1
kind: Module
name: ambassador
config: {}

11
config/gateway/auth.yaml Normal file
View File

@@ -0,0 +1,11 @@
---
apiVersion: ambassador/v1
kind: AuthService
name: authentication
auth_service: auth:8005
path_prefix: /auth
proto: http
allowed_authorization_headers:
- "Authorization"
allowed_request_headers:
- "Authorization"

View File

@@ -0,0 +1,27 @@
---
apiVersion: ambassador/v1
kind: Mapping
name: peatio_api_mapping
host: www.app.local:8080
prefix: /api/peatio/v2/
rewrite: /api/v2/
service: peatio.local:3000
---
apiVersion: ambassador/v1
kind: Mapping
name: peatio_app_mapping
host: peatio.app.local:8080
prefix: /
rewrite: /
service: peatio.local:3000
---
apiVersion: ambassador/v1
kind: Mapping
name: ranger_api_mapping
host: ws.app.local:8080
use_websocket: true
prefix: /api/ranger/v2/
rewrite: /
service: ws.local:8081

17
config/influxdb.yml Normal file
View File

@@ -0,0 +1,17 @@
default: &default
host: <%= ENV.fetch("INFLUXDB_HOST", "127.0.0.1").split(',') %>
port: <%= ENV.fetch("INFLUXDB_PORT", 8086) %>
username: <%= ENV.fetch("INFLUXDB_USER", "root") %>
password: <%= ENV.fetch("INFLUXDB_PASS", "root") %>
development:
<<: *default
database: peatio_development
test:
<<: *default
database: peatio_test
production:
<<: *default
database: <%= ENV.fetch('INFLUXDB_DATABASE_NAME', "peatio_production") %>

View File

@@ -0,0 +1,18 @@
# frozen_string_literal: true
module ActiveRecord
class Base
def self.inherited(child)
super
unless child == ActiveRecord::SchemaMigration
validates_lengths_from_database
end
end
end
end
Rails.configuration.database_support_json = \
ActiveRecord::Base.configurations[Rails.env]['support_json']
Rails.configuration.database_adapter = \
ActiveRecord::Base.configurations[Rails.env]['adapter']

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
require 'peatio/aml'
begin
if ENV['AML_BACKEND'].present?
require ENV['AML_BACKEND']
Peatio::AML.adapter = "#{ENV.fetch('AML_BACKEND').capitalize}".constantize.new
end
rescue StandardError, LoadError => e
Rails.logger.error { e.message }
end

View File

@@ -0,0 +1,8 @@
# Be sure to restart your server when you modify this file.
# ActiveSupport::Reloader.to_prepare do
# ApplicationController.renderer.defaults.merge!(
# http_host: 'example.org',
# https: false
# )
# end

View File

@@ -0,0 +1,10 @@
# encoding: UTF-8
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!

View File

@@ -0,0 +1,8 @@
# encoding: UTF-8
# frozen_string_literal: true
class NilClass
def to_d
BigDecimal(0)
end
end

View File

@@ -0,0 +1,3 @@
Peatio::Blockchain.registry[:bitcoin] = Bitcoin::Blockchain
Peatio::Blockchain.registry[:geth] = Ethereum::Blockchain
Peatio::Blockchain.registry[:parity] = Ethereum::Blockchain

View File

@@ -0,0 +1,9 @@
# frozen_string_literal: true
require 'peatio/app'
Peatio::App.define do |config|
config.set(:deposit_funds_locked, 'false', type: :bool)
config.set(:app_name, 'Dena')
config.set(:domain, 'Zagros.com')
end

View File

@@ -0,0 +1,25 @@
# Be sure to restart your server when you modify this file.
# Define an application-wide content security policy
# For further information see the following documentation
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
# Rails.application.config.content_security_policy do |policy|
# policy.default_src :self, :https
# policy.font_src :self, :https, :data
# policy.img_src :self, :https, :data
# policy.object_src :none
# policy.script_src :self, :https
# policy.style_src :self, :https
# # Specify URI for violation reports
# # policy.report_uri "/csp-violation-report-endpoint"
# end
# If you are using UJS then enable automatic nonce generation
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
# Report CSP violations to a specified URI
# For further information see the following documentation:
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
# Rails.application.config.content_security_policy_report_only = true

View File

@@ -0,0 +1,8 @@
# encoding: UTF-8
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Specify a serializer for the signed and encrypted cookie jars.
# Valid options are :json, :marshal, and :hybrid.
Rails.application.config.action_dispatch.cookies_serializer = :json

View File

@@ -0,0 +1,5 @@
# encoding: UTF-8
# frozen_string_literal: true
Date::DATE_FORMATS[:short] = '%m-%d'
Time::DATE_FORMATS[:default] = "%Y-%m-%d %H:%M:%S"

View File

@@ -0,0 +1,9 @@
# encoding: UTF-8
# frozen_string_literal: true
# Specifications are available in docs/specs/event_api.md.
require 'active_support/concern'
require 'active_support/lazy_load_hooks'
require 'amqp/event_api'
ActiveSupport.on_load(:active_record) { ActiveRecord::Base.include EventAPI::ActiveRecord::Extension }

View File

@@ -0,0 +1,39 @@
# encoding: UTF-8
# frozen_string_literal: true
def catch_and_report_exception(options = {})
begin
yield
nil
rescue options.fetch(:class) { StandardError } => e
report_exception(e)
e
end
end
# report_api_error sample output.
# With default Rails formatter:
# I, [2019-09-18T12:52:59.077389 #157366] INFO -- : {:message=>"Account balance is insufficient", :path=>"/api/v2/account/withdraws", :params=>{"uid"=>"ID20DA7496BB", "currency"=>"usd", "amount"=>0.1e3, "beneficiary_id"=>1, "otp"=>123456}}
#
# With JSONLogFormatter:
# {"message":"Account balance is insufficient","path":"/api/v2/account/withdraws","params":{"uid":"ID5DE7A981C4","currency":"usd","amount":"100.0","beneficiary_id":1,"otp":123456},"level":"INFO","time":"2019-09-18 12:54:36"}
def report_api_error(exception, request)
Rails.logger.info message: exception.message, path: request.path, params: request.params
end
def report_exception(exception, report_to_ets = true)
report_exception_to_screen(exception)
report_exception_to_ets(exception) if report_to_ets
end
def report_exception_to_screen(exception)
Rails.logger.error(exception.inspect)
Rails.logger.error(exception.backtrace.join("\n")) if exception.respond_to?(:backtrace)
end
def report_exception_to_ets(exception)
Raven.capture_exception(exception) if defined?(Raven)
rescue => ets_exception
report_exception(ets_exception, false)
end

View File

@@ -0,0 +1,7 @@
# encoding: UTF-8
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += [:otp]

View File

@@ -0,0 +1,22 @@
# encoding: UTF-8
# frozen_string_literal: true
# Make Grape support lambdas in «description» field.
require 'grape-swagger/doc_methods/parse_params'
require 'grape_entity/exposure/delegator_exposure'
class Grape::Entity::Exposure::Base
def documentation
@documentation.respond_to?(:call) ? @documentation.call : @documentation
end
end
class << GrapeSwagger::DocMethods::ParseParams
def document_description(settings)
description = settings[:desc].presence || settings[:description].presence
description = description.respond_to?(:call) ? description.call : description
description = '' unless description.kind_of?(String) && description.present?
@parsed_param[:description] = description
end
end

View File

@@ -0,0 +1,33 @@
# encoding: UTF-8
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Add new inflection rules using the following format. Inflections
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.acronym 'RESTful'
# end
ActiveSupport::Inflector.inflections do |inflect|
inflect.acronym 'AML'
inflect.acronym 'API'
inflect.acronym 'AMQP'
inflect.acronym 'MQ'
inflect.acronym 'CORS'
inflect.acronym 'UI'
inflect.acronym 'UUID'
inflect.acronym 'CRUD'
inflect.acronym 'TID'
inflect.acronym 'OWHDWallet'
inflect.irregular 'cash', 'cash'
end

View File

@@ -0,0 +1,65 @@
# encoding: UTF-8
# frozen_string_literal: true
Rails.configuration.x.jwt_public_key =
if ENV['JWT_PUBLIC_KEY'].present?
key = OpenSSL::PKey.read(Base64.urlsafe_decode64(ENV['JWT_PUBLIC_KEY']))
raise ArgumentError, 'JWT_PUBLIC_KEY was set to private key, however it should be public.' if key.private?
key
end
::Rails.configuration.x.jwt_options = {
algorithm: ENV.fetch('JWT_ALGORITHM', 'RS256'),
verify_expiration: true,
verify_not_before: true,
iss: ENV['JWT_ISSUER'],
verify_iss: ENV['JWT_ISSUER'].present?,
verify_iat: true,
verify_jti: true,
aud: ENV['JWT_AUDIENCE'].to_s.split(',').reject(&:blank?),
verify_aud: ENV['JWT_AUDIENCE'].present?,
sub: 'session',
verify_sub: true,
}.compact.tap do |jwt_options|
leeway_options = {
leeway: ENV['JWT_DEFAULT_LEEWAY'],
iat_leeway: ENV['JWT_ISSUED_AT_LEEWAY'],
exp_leeway: ENV['JWT_EXPIRATION_LEEWAY'],
nbf_leeway: ENV['JWT_NOT_BEFORE_LEEWAY'],
}.compact.transform_values!(&:to_i)
jwt_options.merge!(leeway_options)
# Set algorithm to 'none' if public key was not provided.
# Since rack-jwt requires public_key for all algorithms except 'none'
# Also using empty public key doesn't make sense unless you use 'none' algorithm.
jwt_options[:algorithm] = 'none' if ::Rails.configuration.x.jwt_public_key.blank?
end
require 'yaml'
require 'openssl'
(YAML.load_file('config/management_api_v1.yml') || {}).deep_symbolize_keys.tap do |x|
x.fetch(:keychain).each do |id, key|
key = OpenSSL::PKey.read(Base64.urlsafe_decode64(key.fetch(:value)))
if key.private?
raise ArgumentError, 'keychain.' + id.to_s + ' was set to private key, ' \
'however it should be public (in config/management_api_v1.yml).'
end
x[:keychain][id][:value] = key
end
x.fetch(:scopes).values.each do |scope|
%i[permitted_signers mandatory_signers].each do |list|
scope[list] = scope.fetch(list, []).map(&:to_sym)
scope[list] = scope.fetch(list, []).map(&:to_sym)
if list == :mandatory_signers && scope[list].empty?
raise ArgumentError, 'scopes.' + scope.to_s + '.' + list.to_s + ' is empty, ' \
'however it should contain at least one value (in config/management_api_v1.yml).'
end
end
end
Rails.configuration.x.security_configuration = x
end

View File

@@ -0,0 +1,27 @@
# encoding: UTF-8
# frozen_string_literal: true
# Require JWT initializer to configure JWT key & options.
require_relative 'jwt'
require 'jwt/rack'
on_error = lambda do |_error|
message = 'jwt.decode_and_verify'
body = { errors: [message] }.to_json
headers = { 'Content-Type' => 'application/json', 'Content-Length' => body.bytesize.to_s }
[401, headers, [body]]
end
# TODO: Fixme in jwt-rack handle api/v2// as api/v2.
auth_args = {
secret: Rails.configuration.x.jwt_public_key,
options: Rails.configuration.x.jwt_options,
verify: Rails.configuration.x.jwt_public_key.present?,
exclude: %w(/api/v2/public /api/v2//public /api/v2/management /api/v2//management
/api/v2/swagger /api/v2//swagger /api/v2/admin/swagger /api/v2//admin/swagger
/api/v2/coinmarketcap /api/v2//coinmarketcap /api/v2/coingecko /api/v2//coingecko),
on_error: on_error
}
Rails.application.config.middleware.use JWT::Rack::Auth, auth_args

View File

@@ -0,0 +1,28 @@
# encoding: UTF-8
# frozen_string_literal: true
Kaminari.configure do |config|
config.default_per_page = 10
config.max_per_page = 1000
# config.window = 4
# config.outer_window = 0
# config.left = 0
# config.right = 0
# config.page_method_name = :page
# config.param_name = :page
end
module KaminariCustomRoute
def page_url_for(page)
params = params_for(page).symbolize_keys
route = params.delete(:route)
if route
@template.send("#{route}_url", params)
else
@template.url_for(params)
end
end
end
Kaminari::Helpers::Tag.prepend KaminariCustomRoute

View File

@@ -0,0 +1,12 @@
# encoding: UTF-8
# frozen_string_literal: true
case ENV.fetch('MATCHING_ENGINE', 'peatio')
when 'finex'
Rails.logger.info { 'Use finex as third-party matching engine' }
Order::TYPES << 'post_only'
when 'peatio'
Rails.logger.info { 'Use default matching engine' }
end
Order::TYPES.freeze
Order.enumerize :ord_type, in: Order::TYPES, scope: true

View File

@@ -0,0 +1,21 @@
# encoding: UTF-8
# frozen_string_literal: true
%w[ deposit withdraw trading ].each do |ability|
var = "MINIMUM_MEMBER_LEVEL_FOR_#{ability.upcase}"
n = ENV[var]
if n.blank?
raise ArgumentError, "The variable #{var} is not set."
end
begin
Integer(n)
rescue ArgumentError
raise ArgumentError, "The value of #{var} (#{n.inspect}) is not a valid number."
end
if n.to_i < 0 || n.to_i > 99
raise ArgumentError, "The value of #{var} (#{n.inspect}) must be in range of [0, 99]."
end
end

View File

@@ -0,0 +1,7 @@
# encoding: UTF-8
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf

View File

@@ -0,0 +1,4 @@
# encoding: UTF-8
# frozen_string_literal: true
Mysql2::Client.default_query_options[:connect_flags] |= Mysql2::Client::MULTI_STATEMENTS

View File

@@ -0,0 +1,61 @@
# Be sure to restart your server when you modify this file.
#
# This file contains migration options to ease your Rails 5.0, 5.1, 5.2 upgrade.
#
# Once upgraded flip defaults one by one to migrate to the new default.
#
# Read the Rails 5.0, 5.1, 5.2 release notes for more info on each option.
# Enable per-form CSRF tokens. Previous versions had false.
Rails.application.config.action_controller.per_form_csrf_tokens = false
# Enable origin-checking CSRF mitigation. Previous versions had false.
Rails.application.config.action_controller.forgery_protection_origin_check = false
# Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`.
# Previous versions had false.
ActiveSupport.to_time_preserves_timezone = false
# Require `belongs_to` associations by default. Previous versions had false.
Rails.application.config.active_record.belongs_to_required_by_default = false
# Do not halt callback chains when a callback returns false. Previous versions had true.
# ActiveSupport.halt_callback_chains_on_return_false = true
# Make `form_with` generate non-remote forms.
Rails.application.config.action_view.form_with_generates_remote_forms = false
# Unknown asset fallback will return the path passed in when the given
# asset is not present in the asset pipeline.
# Rails.application.config.assets.unknown_asset_fallback = false
# Make Active Record use stable #cache_key alongside new #cache_version method.
# This is needed for recyclable cache keys.
# Rails.application.config.active_record.cache_versioning = true
# Use AES-256-GCM authenticated encryption for encrypted cookies.
# Also, embed cookie expiry in signed or encrypted cookies for increased security.
#
# This option is not backwards compatible with earlier Rails versions.
# It's best enabled when your entire app is migrated and stable on 5.2.
#
# Existing cookies will be converted on read then written with the new scheme.
# Rails.application.config.action_dispatch.use_authenticated_cookie_encryption = true
# Use AES-256-GCM authenticated encryption as default cipher for encrypting messages
# instead of AES-256-CBC, when use_authenticated_message_encryption is set to true.
# Rails.application.config.active_support.use_authenticated_message_encryption = true
# Add default protection from forgery to ActionController::Base instead of in
# ApplicationController.
# Rails.application.config.action_controller.default_protect_from_forgery = true
# Store boolean values are in sqlite3 databases as 1 and 0 instead of 't' and
# 'f' after migrating old data.
# Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
# Use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header.
# Rails.application.config.active_support.use_sha1_digests = true
# Make `form_with` generate id attributes for any generated HTML tags.
# Rails.application.config.action_view.form_with_generates_ids = true

View File

@@ -0,0 +1,9 @@
# encoding: UTF-8
# frozen_string_literal: true
class Hash
def fetch!(key)
raise RuntimeError, "Required key #{key.inspect} is missing or is blank!" unless self[key].present?
self[key]
end
end

View File

@@ -0,0 +1,23 @@
# encoding: UTF-8
# frozen_string_literal: true
class Rack::Session::Redis
def set_session(env, session_id, new_session, options)
with_lock env, false do
with do |c|
new_options = if env['api_v2.session_lifetime']
x = ActionDispatch::Request::Session::Options.new \
options.instance_variable_get(:@by),
options.instance_variable_get(:@env),
options.instance_variable_get(:@delegate)
x[:expire_after] = env['api_v2.session_lifetime']
x
else
options
end
c.set(session_id, new_session, new_options)
end
session_id
end
end
end

View File

@@ -0,0 +1,3 @@
# Be sure to restart your server when you modify this file.
Rails.application.config.session_store :disabled

View File

@@ -0,0 +1,12 @@
# encoding: UTF-8
# frozen_string_literal: true
class String
# Similar to how ActiveRecord does. See lib/active_record/type/decimal.rb
def to_d
str_decimal = delete_suffix('.')
return BigDecimal(0) if str_decimal.blank?
BigDecimal(str_decimal)
end
end

View File

@@ -0,0 +1,26 @@
# encoding: UTF-8
# frozen_string_literal: true
module Enumerize
class Attribute
def value_options(options = {})
values = if options.empty?
@values
else
raise ArgumentError, 'Options cannot have both :only and :except' if options[:only] && options[:except]
only = Array(options[:only]).map(&:to_s)
except = Array(options[:except]).map(&:to_s)
@values.reject do |value|
if options[:only]
!only.include?(value)
elsif options[:except]
except.include?(value)
end
end
end
values.map { |v| [v.text, v.value] }
end
end
end

View File

@@ -0,0 +1,12 @@
# frozen_string_literal: true
begin
types = YAML.load_file("#{Rails.root}/config/transfer_types.yml").symbolize_keys
deposit_types = Deposit::TRANSFER_TYPES.merge(types[:deposit])
withdraw_types = Withdraw::TRANSFER_TYPES.merge(types[:withdraw])
Deposit.enumerize :transfer_type, in: deposit_types
Withdraw.enumerize :transfer_type, in: withdraw_types
rescue StandardError => e
Deposit.enumerize :transfer_type, in: Deposit::TRANSFER_TYPES
Withdraw.enumerize :transfer_type, in: Withdraw::TRANSFER_TYPES
Rails.logger.error { e.message }
end

View File

@@ -0,0 +1 @@
ActiveRecord::Type.register(:uuid, UUID::Type)

View File

@@ -0,0 +1,3 @@
require 'peatio/upstream/opendax'
Peatio::Upstream.registry[:opendax] = Peatio::Upstream::Opendax

View File

@@ -0,0 +1,44 @@
# encoding: UTF-8
# frozen_string_literal: true
require 'vault/totp'
require 'vault/rails'
Vault::Rails.configure do |config|
config.enabled = Rails.env.production?
config.address = ENV.fetch('VAULT_ADDR', 'http://127.0.0.1:8200')
config.token = ENV['VAULT_TOKEN']
config.ssl_verify = false
config.timeout = 60
config.application = ENV.fetch('VAULT_APP_NAME', 'peatio')
config.in_memory_warnings_enabled = false
end
if ENV['VAULT_TOKEN'].to_s != ''
def renew_process
token = Vault.auth_token.lookup(Vault.token)
time = token.data[:ttl] * (1 + rand) * 0.1
Rails.logger.debug '[VAULT] Token will renew in %.0f sec' % time
sleep(time)
Vault.auth_token.renew(token.data[:id])
Rails.logger.info '[VAULT] Token renewed'
end
token = Vault.auth_token.lookup(Vault.token)
if token.data[:renewable]
Rails.logger.info '[VAULT] Starting token renew thread'
Thread.new do
loop do
renew_process
rescue StandardError => e
report_exception(e)
sleep 60
end
end
else
Rails.logger.info '[VAULT] Token is not renewable'
end
else
Rails.logger.warn 'Environment variable VAULT_TOKEN is missing'
end

View File

@@ -0,0 +1,13 @@
# encoding: UTF-8
# frozen_string_literal: true
# This file is auto-generated from the current state of VCS.
# Instead of editing this file, please use bin/gendocs.
module Peatio
class Application
GIT_TAG = '2.6.0'
GIT_SHA = '66aceba'
BUILD_DATE = '2019-11-07 11:43:58+00:00'
VERSION = GIT_TAG
end
end

View File

@@ -0,0 +1,7 @@
Peatio::Wallet.registry[:bitcoind] = Bitcoin::Wallet
Peatio::Wallet.registry[:geth] = Ethereum::Wallet
Peatio::Wallet.registry[:parity] = Ethereum::Wallet
Peatio::Wallet.registry[:gnosis] = Gnosis::Wallet
Peatio::Wallet.registry[:ow_hdwallet] = OWHDWallet::Wallet
Peatio::Wallet.registry[:opendax] = OWHDWallet::Wallet
Peatio::Wallet.registry[:opendax_cloud] = OpendaxCloud::Wallet

View File

@@ -0,0 +1,17 @@
# encoding: UTF-8
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# This file contains settings for ActionController::ParamsWrapper which
# is enabled by default.
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json]
end
# To enable root element in JSON for ActiveRecord objects.
# ActiveSupport.on_load(:active_record) do
# self.include_root_in_json = true
# end

22
config/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

38
config/puma.rb Normal file
View File

@@ -0,0 +1,38 @@
# frozen_string_literal: true
# Puma can serve each request in a thread from an internal thread pool.
# The `threads` method setting takes two numbers: a minimum and maximum.
# Any libraries that use thread pools should be configured to match
# the maximum value specified for Puma. Default is set to 5 threads for minimum
# and maximum; this matches the default thread size of Active Record.
#
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { 2 }
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 8 }
threads min_threads_count, max_threads_count
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
#
port ENV.fetch("PORT") { 3000 }
# Specifies the `environment` that Puma will run in.
#
environment ENV.fetch("RAILS_ENV") { "development" }
# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked webserver processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
#
# workers ENV.fetch("WEB_CONCURRENCY") { 4 }
# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
#
preload_app!
# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restart

8
config/routes.rb Normal file
View File

@@ -0,0 +1,8 @@
# frozen_string_literal: true
Peatio::Application.routes.draw do
get '/swagger', to: 'swagger#index'
mount API::Mount => API::Mount::PREFIX
end

31
config/scout_apm.yml Normal file
View File

@@ -0,0 +1,31 @@
# This configuration file is used for Scout APM.
# Environment variables can also be used to configure Scout.
# See our help docs at http://help.apm.scoutapp.com#environment-variables for more information.
# See http://help.apm.scoutapp.com/#ruby-configuration-options
common: &defaults
# key: Your organization key for Scout APM. Found on the settings screen.
# - Default: none
key: <%= ENV['SCOUT_KEY'] %>
# Verboseness of logs.
# - Default: 'info'
# - Valid Options: debug, info, warn, error
log_level: <%= ENV.fetch('SCOUT_LOG_LEVEL', 'info') %>
log_file_path: stdout
# Application name in APM Web UI.
name: <%= ENV['SCOUT_APP_NAME'].presence || "#{ENV.fetch('URL_HOST')} (#{Rails.env})" %>
# Enable Scout APM or not.
monitor: <%= Rails.env.in?(ENV['SCOUT_ENV'].to_s.split(',').map(&:squish)) %>
production:
<<: *defaults
development:
<<: *defaults
test:
<<: *defaults

22
config/secrets.yml Normal file
View File

@@ -0,0 +1,22 @@
# Be sure to restart your server when you modify this file.
# Your secret key is used for verifying the integrity of signed cookies.
# If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks.
# You can use `rails secret` to generate a secure secret key.
# Make sure the secrets in this file are kept private
# if you're sharing your code publicly.
development:
secret_key_base: ec7ffa7f1e53b586f2ad072518776a153b14f40ea77e5aa17b9b3ab5145ac29f018c2da13c626102b2d7c749b60f8fc81798579a7e820b96821d431b5fc144c3 # guardrails-disable-line
test:
secret_key_base: 2c3cdc3e0bc14d5260250570be0961de2f974c4f3e15b6004734d9e587ce9f47da248f20dc1707a5bb555d879a5494641f4b1a01ca6066df2b783943914ebcd7 # guardrails-disable-line
# Do not keep production secrets in the repository,
# instead read values from the environment.
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

6
config/spring.rb Normal file
View File

@@ -0,0 +1,6 @@
%w(
.ruby-version
.rbenv-vars
tmp/restart.txt
tmp/caching-dev.txt
).each { |path| Spring.watch(path) }

View File

@@ -0,0 +1,149 @@
defaults: &defaults
TIMEZONE: 'Tehran'
# Configure Redis URL, for a TCP connection:
# `redis://:[password]@[hostname]:[port]/[db]`
# (password, port and database are optional).
REDIS_URL: redis://localhost:6379
REDIS_PASSWORD: ~
REDIS_CLUSTER: false
# Application URL configuration variables.
URL_HOST: peatio.tech
URL_ROOT_PATH: '/'
URL_SCHEME: http
FORCE_SECURE_CONNECTION: 'false' # Set to "true" to disable access via unsecured HTTP, send HSTS headers and use secure cookies.
# Configuration variables for logger.
LOG_LEVEL: ~ # Default level for production is warn, otherwise debug.
# Configuration variables for API CORS.
#
# Set list of allowed origins using the variable below.
# By default it allows access to API from all origins.
# See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
API_CORS_ORIGINS: '*'
# Access-Control-Allow-Credentials response header is not supported
# if the CORS header Access-Control-Allow-Origin is *.
API_CORS_ALLOW_CREDENTIALS: 'false'
# The Access-Control-Max-Age response header indicates how long
# the results of a preflight request can be cached.
# Default value 3600.
API_CORS_MAX_AGE: ~
# Configuration variables for Sentry.
SENTRY_DSN_BACKEND: ~ # Specify Sentry DSN used for Rails application.
# Customize page metadata like title, description & keywords for landing, cabinet & admin modules.
METADATA_TITLE: Peatio Exchange
METADATA_DESCRIPTION: The Opensource Cryptocurrency Exchange
METADATA_KEYWORDS: Peatio,Opensource,Exchange,Cryptocurrency
# Configuration variables for JWT verification.
# Get explanation at https://en.wikipedia.org/wiki/JSON_Web_Token.
#
# JWT_PUBLIC_KEY
#
# JWT provider uses private key for encoding JSON Web Tokens
# while public key is used for decoding by resources.
#
# For example, Barong is JWT provider, Peatio is resource accepting JWT.
# Barong must have private key installed, Peatio must have public key installed.
#
# You can generate keypair by running:
#
# ruby -e "require 'openssl'; require 'base64'; OpenSSL::PKey::RSA.generate(2048).tap { |p| puts '', 'PRIVATE RSA KEY (URL-safe Base64 encoded, PEM):', '', Base64.urlsafe_encode64(p.to_pem), '', 'PUBLIC RSA KEY (URL-safe Base64 encoded, PEM):', '', Base64.urlsafe_encode64(p.public_key.to_pem) }"
#
# Copy the generated private key and put it's value to appropriate variable at JWT provider (for example, at Barong it will be JWT_SHARED_SECRET_KEY).
# Copy the generated public key and put it's value to variable JWT_PUBLIC_KEY (at Peatio).
#
# Peatio and JWT provider should have the same keypair installed, or they would not understand each other.
#
# You may want to adjust key length or cipher.
#
# Development and test environments already don't include sample keys.
#
# You can generate valid JWT by running:
#
# JWT.encode(payload, OpenSSL::PKey.read(Base64.urlsafe_decode64(ENCODED_PRIVATE_KEY)), ENV.fetch('JWT_ALGORITHM'))
#
# Replace ENCODED_PRIVATE_KEY with private key printed by previous command.
#
# You can decode JWT by running:
#
# JWT.decode(token, OpenSSL::PKey.read(Base64.urlsafe_decode64(ENCODED_PUBLIC_KEY)), true, algorithms: [ENV.fetch('JWT_ALGORITHM')])
#
# To authenticate using JWT send it's value in "Authorization" header:
#
# curl -H "Authorization: Bearer TOKEN" http://localhost:3000/api/v2/account/balances
#
JWT_PUBLIC_KEY: ~
JWT_ALGORITHM: RS256 # JWT signing algorithm (mandatory).
JWT_ISSUER: ~ # JWT issuer name (optional).
JWT_AUDIENCE: peatio # Could be comma-separated value (optional).
JWT_DEFAULT_LEEWAY: ~ # Seconds (optional).
JWT_ISSUED_AT_LEEWAY: '180' # Seconds (optional).
JWT_EXPIRATION_LEEWAY: ~ # Seconds (optional).
JWT_NOT_BEFORE_LEEWAY: ~ # Seconds (optional).
PEATIO_JWT_PRIVATE_KEY: ~
# Scout APM configuration variables.
SCOUT_KEY: ~ # Your organization key for Scout APM. Found on the settings screen.
SCOUT_APP_NAME: ~ # Application name in APM Web UI.
SCOUT_LOG_LEVEL: warn # Verboseness of logs (debug, info, warn, error)
SCOUT_ENV: production # List of Rails environments for which Scout should be enabled.
# Configuration variables for dynamic Barong levels (1.8+).
MINIMUM_MEMBER_LEVEL_FOR_DEPOSIT: '0'
MINIMUM_MEMBER_LEVEL_FOR_WITHDRAW: '0'
MINIMUM_MEMBER_LEVEL_FOR_TRADING: '0'
# Event API configuration.
# JWT configuration.
# You can generate keypair using:
#
# ruby -e "require 'openssl'; require 'base64'; OpenSSL::PKey::RSA.generate(2048).tap { |p| puts '', 'PRIVATE RSA KEY (URL-safe Base64 encoded, PEM):', '', Base64.urlsafe_encode64(p.to_pem), '', 'PUBLIC RSA KEY (URL-safe Base64 encoded, PEM):', '', Base64.urlsafe_encode64(p.public_key.to_pem) }"
#
EVENT_API_JWT_PRIVATE_KEY: ~ # Private key. Must be URL-safe Base64 encoded in PEM format.
EVENT_API_JWT_ALGORITHM: RS256
# RabbitMQ configuration.
# You can use just «EVENT_API_RABBITMQ_URL» or specify configuration per separate variable.
EVENT_API_RABBITMQ_URL: ~
EVENT_API_RABBITMQ_HOST: localhost
EVENT_API_RABBITMQ_PORT: "5672"
EVENT_API_RABBITMQ_USERNAME: guest
EVENT_API_RABBITMQ_PASSWORD: guest
RANGER_HOST: '0.0.0.0'
RANGER_PORT: '8081'
RANGER_CONNECT_SECURE: 'false'
BULLET: 'false'
# Configuration to allow Withdraw via API i.e (POST api/v2/account/withdraws)
ENABLE_ACCOUNT_WITHDRAWAL_API: 'true'
# Configure Vault to verify OTP for Withdraw API
#VAULT_ADDR: http://127.0.0.1:8200
#VAULT_TOKEN: ""
# Configure to limit currencies and markets on the platform.
MAX_CURRENCIES: ~
MAX_MARKETS: ~
development:
<<: *defaults
# Development configuration variables for Event API JWT.
# TODO i think below line must be comment
# EVENT_API_JWT_PRIVATE_KEY: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBb3VLVHh2SFVJVDJENmdXaWJRcS9kbW9BUUwyeWJ6SGFiUXRlc1AyL2o1VjkvUExaCmhHNWtLVkpPWjcxVVdMQ3BjZTQxeHZzQ0lKd0Q5MnVDNW5Lak5wblRDTWpwTUJNMGg0aFF4a2VOeHdNeU41N1gKM1QzbWFCVmZzUTNCblErSm84L0tzdUxhODlvY0dDeDgvYlUyOGNld2FxRk8ydUVMWWJiaUZadGFCenFJd0ZCdQpTM3hGQmt6NE16MGgvWEIxTjl5ZDg5d25OMm1oWVBsU0xrTGVUdFoyeWswK2krZHhZd2V4MEozOXJDS0hnRWRKCko1NTZHNmdtZWpJZ3dtcHNVeHJpdkVJRU5jR09POHdmQVBUVy92SFZmc2ROTExHejRtZE9CWmxsa2orcFFQODYKTnFSUjRKSnFDdEg3dHYyaXVBSGI4NnB5anVlZkVGU3ljMmxZRXdJREFRQUJBb0lCQUJrUlViamVZczB5MEdobApzWmVpZmREVmczQnpRVkRIbFZ3TzBlWGZSMm5ya2RZcDhidmwyVmhhcUdKaXl1WlRXZUNFenBYdTcyYmhXK0xxCkV0MHdhMW50MW9LVm1QMmpGd1I4d0NHanhYZ0pUK01yZVFFOWs0WVZOQUxsb1JSdzNiZnVOTDNQRis5TGMrTnMKaFZmdVdhUmdIUkJyL3R6RW9hSEtLWVUxd1djM0poSitNRklNVkZBT0RvaGp6bXNlV2lzTDNnbzVrUC9KYUpVZwprNm13Wnd0QzRvQ3pPQ3FoRGF0WVI3cktJbXMyS1lCNVBwaTRDTThkRzJGTzBwWGxXUU9XT0t2N01TUjlVeEtzCmd4YWFRRlhjajBQM2lSRFVQMDRkSWtqblNtemZmR0F2L3lBTHovZjk0V1lIK3gvd01DWms4ejJ4bnRJclllM3UKN0NOd045RUNnWUVBMEplcThCaXlKczF6YlBpcTlWWnR5L3R0M1dhaXJDbUl4cXRwU2syVU9UNmh2TldiMTUxVwpBMGRWYWEvSVBhdDV4ZkNWdGhkNlB3UGpJbWVPVXQ4Mlhib2JYeE8zREJUcmVzTlRNWUhiMGVUK09sSG04SU5uCnVwOGFxZWpWejc1ME5VYUxGWWpxWk1wVVR1Z2FVREIzNWZ1bXg0SXliNm5LRGMvSStrN25qUlVDZ1lFQXgrZVAKcE4vR1dqYjJUOU1CUm1xdkVtSGxKOXBZSEZpWGZlWnJHdzg3Q2E5WjVDYVp1VzBrSVAwSlhWSDZOOThqL2RvbApDTHZPdE5oZVFoaGUrTU91VXJMT0ttaytpckM5SEk2cW9aT3Nkc0lCc0pXSHdPanB1UW00OWNvdXc0K2ZKOWRxCjN2cTE2bG5EQlNoRU5HTEFhdVBzWDhLRUlYVzhRRnBDM3ppbXFvY0NnWUI2bTh2VVdRL09reEQzeXFyaWpxejMKSzVFR2hKKzF4cXdvNnZSMndtY1B4dXJXemxCT1NxTVdSa1hFVzVpOTl4OGE1REY3MlF6NElWYlBFRU91SHBvYwpPWnFCSmx0LzlJUDlvdll4c1h6K1FUWFdIZkk3Q1dKZFpjd01kMW5HUk5LVnhpTld3eVhUbk1JMXAyUmdJajAzCnA5WCtpMThPRjZVMnZSNExVM256aVFLQmdBVVZzOGFxMW4zRzloN3pyQTJoZXhDSm91MlBsVHdyV0xjZ0hFdFUKNk5pSE9FOGdXRHFxTndnTHg2Z3pCSjFWTkxJcFVWWFdpUng2Z0hOSDhXcDhkN3VzeHFlM2c1cTlnaUh1MHhKSApFbFQyL0ZvRWc2NTVmakJ4dWQydXBkL2RrRnZRRSt6V0RiaUhUZm1jbTVlRmg0VndoTHV1MC9PUjdoYm85TmgrCnRXYVRBb0dCQUwxVjFUTWZZRFhwYjFwaFBaV2pQL29iV1NqK2VyUXlYdit3TTIxVzRYWFI4YTBkV2hOVXdVeDAKdU9WZ2s1ZlN1OExtNG0zWGNYZ09wV0VJVkZJTzFodDFNN0xxZ0VGNGhFOHl6Y0Vldy9HWXR4VkpCTWEyODVpVQpaVUtkeCt6QWd5VFlnYk50VkVseTVobGRuT2orVmNzanVEL3krWEhXWVl5OVpLa2pNdDhECi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
# Event API JWT public key value is.
# EVENT_API_JWT_PUBLIC_KEY: LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFvdUtUeHZIVUlUMkQ2Z1dpYlFxLwpkbW9BUUwyeWJ6SGFiUXRlc1AyL2o1VjkvUExaaEc1a0tWSk9aNzFVV0xDcGNlNDF4dnNDSUp3RDkydUM1bktqCk5wblRDTWpwTUJNMGg0aFF4a2VOeHdNeU41N1gzVDNtYUJWZnNRM0JuUStKbzgvS3N1TGE4OW9jR0N4OC9iVTIKOGNld2FxRk8ydUVMWWJiaUZadGFCenFJd0ZCdVMzeEZCa3o0TXowaC9YQjFOOXlkODl3bk4ybWhZUGxTTGtMZQpUdFoyeWswK2krZHhZd2V4MEozOXJDS0hnRWRKSjU1Nkc2Z21laklnd21wc1V4cml2RUlFTmNHT084d2ZBUFRXCi92SFZmc2ROTExHejRtZE9CWmxsa2orcFFQODZOcVJSNEpKcUN0SDd0djJpdUFIYjg2cHlqdWVmRUZTeWMybFkKRXdJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==
test:
<<: *defaults
production:
<<: *defaults

View File

@@ -0,0 +1,5 @@
order_count: 500
base_url: 'http://localhost:3000'
threads: 10
market: 'btcusd'
server_token: 'Bearer '

View File

@@ -0,0 +1,36 @@
- currencies: btc,usd # List of fiat currencies for creating deposits.
traders: 25 # Number of members who will trade.
threads: 50 # Number of simultaneous threads which will publish messages to RabbitMQ.
report_path: bench/reports # Path for saving benchmark report.
log_path: bench/log # Path for logging benchmark status.
orders:
#
# Generic config.
injector: dummy # Order injector name.
number: 100000 # Number of orders to be created and published to RabbitMQ (at least 100_000).
step: 10000 # Step for writing sql transactions.
markets: btcusd # Markets for performing trading.
#
# Dummy injector specific config.
min_volume: 0.1 # Order min volume (default 0.1).
max_volume: 1.0 # Order max volume (default 1.0).
min_price: 0.5 # Order min price (default 0.5).
max_price: 2.0 # Order max price (default 2.0).
- currencies: btc,usd # List of fiat currencies for creating deposits.
traders: 25 # Number of members who will trade.
threads: 50 # Number of simultaneous threads which will publish messages to RabbitMQ.
report_path: bench/reports # Path for saving benchmark report.
log_path: bench/log # Path for logging benchmark status.
orders:
#
# Generic config.
injector: bitfinex # Order injector name.
number: 100000 # Number of orders to be created and published to RabbitMQ (at least 100_000).
step: 10000 # Step for writing sql transactions.
markets: btcusd # Markets for performing trading.
#
# Bitfinex injector specific config.
# Path to bitfinex order history file.
# TODO: Add example how to generate this file.
data_load_path: config/bench/data/usd-eur.csv

View File

@@ -0,0 +1,36 @@
- currencies: btc,usd # List of fiat currencies for creating deposits.
traders: 25 # Number of members who will trade.
threads: 50 # Number of simultaneous threads which will publish messages to RabbitMQ.
report_path: bench/reports # Path for saving benchmark report.
log_path: bench/log # Path for logging benchmark status.
orders:
#
# Generic config.
injector: dummy # Order injector name.
number: 10000 # Number of orders to be created and published to RabbitMQ (at least 2000).
step: 10000
markets: btcusd # Markets for performing trading.
#
# Dummy injector specific config.
min_volume: 0.1 # Order min volume (default 0.1).
max_volume: 1.0 # Order max volume (default 1.0).
min_price: 0.5 # Order min price (default 0.5).
max_price: 2.0 # Order max price (default 2.0).
- currencies: btc,usd # List of fiat currencies for creating deposits.
traders: 25 # Number of members who will trade.
threads: 50 # Number of simultaneous threads which will publish messages to RabbitMQ.
report_path: bench/reports # Path for saving benchmark report.
log_path: bench/log # Path for logging benchmark status.
orders:
#
# Generic config.
injector: bitfinex # Order injector name.
number: 10000 # Number of orders to be created and published to RabbitMQ (at least 2000).
step: 10000 # Step for writing sql transactions.
markets: btcusd # Markets for performing trading.
#
# Bitfinex injector specific config.
# Path to bitfinex order history file.
# TODO: Add example how to generate this file.
data_load_path: config/bench/data/usd-eur.csv

View File

@@ -0,0 +1,36 @@
- currencies: btc,usd # List of fiat currencies for creating deposits.
traders: 25 # Number of members who will trade.
threads: 50 # Number of simultaneous threads which will publish messages to RabbitMQ.
report_path: bench/reports # Path for saving benchmark report.
log_path: bench/log # Path for logging benchmark status.
orders:
#
# Generic config.
injector: dummy # Order injector name.
number: 20000 # Number of orders to be created and published to RabbitMQ (at least 2000).
step: 10000 # Step for writing sql transactions.
markets: btcusd # Markets for performing trading.
#
# Dummy injector specific config.
min_volume: 0.1 # Order min volume (default 0.1).
max_volume: 1.0 # Order max volume (default 1.0).
min_price: 0.5 # Order min price (default 0.5).
max_price: 2.0 # Order max price (default 2.0).
- currencies: btc,usd # List of fiat currencies for creating deposits.
traders: 25 # Number of members who will trade.
threads: 50 # Number of simultaneous threads which will publish messages to RabbitMQ.
report_path: bench/reports # Path for saving benchmark report.
log_path: bench/log # Path for logging benchmark status.
orders:
#
# Generic config.
injector: bitfinex # Order injector name.
number: 20000 # Number of orders to be created and published to RabbitMQ (at least 4000).
step: 10000 # Step for writing sql transactions.
markets: btcusd # Markets for performing trading.
#
# Bitfinex injector specific config.
# Path to bitfinex order history file.
# TODO: Add example how to generate this file.
data_load_path: config/bench/data/usd-eur.csv

View File

@@ -0,0 +1,73 @@
<% if ENV['MANAGEMENT_API_V1_CONFIG'] %>
<%= File.read(ENV['MANAGEMENT_API_V1_CONFIG']) %>
<% else %>
# Be sure to restart your server when you modify this file.
#
# This file keeps all the security configuration variables for «Management API v1».
#
# Keeps all the public keys used to validate signatures.
# All values must be presented in PEM format and be URL-safe Base64 encoded.
#
# Example:
#
# keychain:
# backend-1.mycompany.example:
# algorithm: RS256
# value: LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF3UjNPT1RQbzZvZE8wM3hXVDRNawp6TXJuM2pQS2pVdW0rVkc5dUZWODZNejVnMm1ueXdSRDc4MEY4aXVaZm41SGtROFpTUlFHYlRHNnB1dlVWWDFCClA0MWIrUW52VHFtWFhHcE9aSklzV3V2cHA4dHpZenFOejUvcTRRdUZQWDlrczdtaVV2dkNzbmo5S21Wb08yMU4KUVgyOWZUNkRJYldkUnJvWU1IOHloVmRrSjRVQnhYeHlSWmZ4VnN4UFVwckNodEgxN1JwNnQvYVRTR0VZNndQNwpKbEVCZi9Gb0djQk15OU5BOWhqZFMyMWxGcmVYeXdaUzZYdmhrN3dydGJWT2didU5EajdVeWhjS0RCaHA4c2VjCkV4TlB6d2p4ckhGTzhZaitFejBCMmZKQ1FDWW9SVG1kTzVEQS9kRTFHQmtqeXRCZjhDdGVIdExXcmZIU2g5em0KNlFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==
# backend-2.mycompany.example:
# algorithm: HS384
# value: LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUFyZm53OXpGMDRCaFlZTk5mblVKawppK2YwWUE2RitDdlZtMGozOEV1c2E2ZHdkRnBaMEFhK0dzRjlEWGpuOXgzTjdpZzlxNnFmbTN5TzdJbmxqZmdZCmp4eU12MmdXcTNTZmhySmZpUWd3dmh2NHJiMzJiTmc3ckxPTVJmenVDeUQ2aFBQU2FueTM3ZnhSNmxKR3E5SUcKUTRJa3JPNmZIOGozUllQVDBGUVlJcXg1a2pNbU9wczFlV2xTR1RYbDZWSDNtVWxxTWVMSjJjL1NMZ3Y3dUxDagpmMVpDTXFELzB4VERWZ0ZxbzJSSlRucEcvUzlXRHdpZ3U0aTdyY1VkeDcrQUMvK2lNSGpNL1VZekRtWHJDQkpaCjBnSUVPV1ZwM2dMMzNocmRZci9uNU11SFRiMXpJUHdJQW1ySHpmWFpwOEQxNVVUdGtENktXU1FINWQ5SnAvVncKN3dJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==
# backend-3.mycompany.example:
# algorithm: RS512
# value: LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUEzL2VIUUd1V2NFUHhwY2pxaVN5SQpLYmFlTFhnNHhrTFcwMU12eHlPVENMeHNrbVk5T0ViVTBQa2ptaFk1bWhiOXpmVjJqMVBmbXdXQmp5bXJ2alJJCmlWMDdxczA1OUx3UGhyL0JZc0lnYk13bWVEZUp5VHlxTmFvckNkVklhamxMVHhGSklNOGtXTUg1TUcrR2U0b2wKc1VWblEwRDNZdURvNCtPSzJiSDBOY3M5ZEFTWGx4T0lsenpZTlFkUTNCSUxZbFE3MW9CRDNmTWRyaXQwSktVYwphb25jTXJ0RlB2WlRuZjZROUhVM2VpR3NxTHhWczVZRTBGUlVsd0Z4TjZzbnZNQW9rNEpRT3A5cUExUi96WHMwCnRWdUVpeEJ1Sm5jSjZSYlp5UVp5YWg3YzAxd1NLcks1UTRudVh3VlhXUkhvd0gxOTZHMU9TODhoYmVZNHNneTkKdForZ3NsdlZIYWJmK1JqK0JtZmNOYmx2T1lQWlI4K3dVQ2pOWW43L1BWRjQ0NDRzUCtTZkEyejdvaU1OVStrVwpGVHM5dVdRNGxzQ0RIQnd6ZXNFMDc0dmZLMHF4c0NNN0hWeHhVc2gvNGx3aGppZTgrTFNqdzliWTlrcjJxWWFmClRMRnpoVWl2clJMaEpWdnZkQmRRYlBIUFVybnJ2TnFqblRYOWtFcWR4bktrbWluWmhtbU1pakpKa1dGREgwbmgKNmR4ZlZwZ2puYXUzWmoyZkNSNFV6aXNXK25MaExUc1Fadzd0b0NaVUo2aWV6N0psOEpJYWdBVWJ5OW8ycUN4ZgpWcTBwK3pwRlZKUFZzelVQNkZMTzh3Tjd5aThVT3l4T3VmdmEvOHgySmRJTzJ4emlPc2ZLVnhIZTFZRkZtWVdtCnZKaWZ1ZGUrdCtBbS9EM1FMSjlpK2JNQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=
#
#
keychain: {}
#
# Keeps all the JWT verification options.
# The documentation is available at https://github.com/jwt/ruby-jwt#support-for-reserved-claim-names.
# Check lib/jwt/default_options.rb for the default options.
#
jwt: {}
#
# Keep all the API security scopes.
#
# The API security scope consists of scope name, list of permitted and mandatory signers.
# The scope name is associated with API actions. For example, write_deposits is associated with
# ability to create deposits and accept them. The scopes which have «write» in the name are supposed
# to be dangerous so they must require more signatures then read-only scopes
#
# Each scope must include list of permitted and mandatory signers.
# Peatio validates JWT signatures against permitted keys and doesn't trust
# JWTs which don't include signatures from all mandatory signers.
#
# Example:
# scopes:
# read_deposits:
# permitted_signers: ['backend-1.mycompany.example', 'backend-2.mycompany.example']
# mandatory_signers: ['backend-1.mycompany.example']
# write_deposits:
# permitted_signers: ['backend-1.mycompany.example', 'backend-2.mycompany.example']
# mandatory_signers: ['backend-1.mycompany.example', 'backend-2.mycompany.example']
#
# The available scopes include:
# read_deposits
# write_deposits
# read_withdraws
# write_withdraws
# read_operations
# write_operations
# read_transfers
# write_transfers
# write_members
# read_currencies
# write_currencies
# read_markets
# write_markets
# tools
#
scopes: {}
<% end %>

View File

@@ -0,0 +1,73 @@
<% if ENV['ACCOUNTS_CONFIG'] %>
<%= File.read(ENV['ACCOUNTS_CONFIG']) %>
<% else %>
- code: 101
type: asset
kind: main
currency_type: fiat
description: Main Fiat Assets Account
scope: platform
- code: 102
type: asset
kind: main
currency_type: coin
description: Main Crypto Assets Account
scope: platform
- code: 201
type: liability
kind: main
currency_type: fiat
description: Main Fiat Liabilities Account
scope: member
- code: 202
type: liability
kind: main
currency_type: coin
description: Main Crypto Liabilities Account
scope: member
- code: 211
type: liability
kind: locked
currency_type: fiat
description: Locked Fiat Liabilities Account
scope: member
- code: 212
type: liability
kind: locked
currency_type: coin
description: Locked Crypto Liabilities Account
scope: member
- code: 301
type: revenue
kind: main
currency_type: fiat
description: Main Fiat Revenues Account
scope: platform
- code: 302
type: revenue
kind: main
currency_type: coin
description: Main Crypto Revenues Account
scope: platform
- code: 401
type: expense
kind: main
currency_type: fiat
description: Main Fiat Expenses Account
scope: platform
- code: 402
type: expense
kind: main
currency_type: coin
description: Main Crypto Expenses Account
scope: platform
<% end %>

View File

@@ -0,0 +1,47 @@
<% if ENV['BLOCKCHAINS_CONFIG'] %>
<%= File.read(ENV['BLOCKCHAINS_CONFIG']) %>
<% else %>
- key: prt-kovan
name: Ethereum Kovan
client: parity # API client name.
server: http://127.0.0.1:8545 # Public Ethereum node endpoint. IMPORTANT: full syncmode.
height: 2500000 # Initial block number from which sync will be started.
min_confirmations: 6 # Minimal confirmations needed for withdraw and deposit confirmation.
explorer:
address: https://kovan.etherscan.io/address/#{address}
transaction: https://kovan.etherscan.io/tx/#{txid}
status: disabled
- key: eth-rinkeby
name: Ethereum Rinkeby
client: geth # API client name.
server: http://127.0.0.1:8545 # Public Ethereum node endpoint. IMPORTANT: full syncmode.
height: 4000000 # Initial block number from which sync will be started.
min_confirmations: 6 # Minimal confirmations needed for withdraw and deposit confirmation.
explorer:
address: https://rinkeby.etherscan.io/address/#{address}
transaction: https://rinkeby.etherscan.io/tx/#{txid}
status: active
- key: eth-mainet
name: Ethereum Mainet
client: geth # API client name.
server: http://127.0.0.1:8545 # Public Ethereum node endpoint. IMPORTANT: full syncmode.
height: 7500000 # Initial block number from which sync will be started.
min_confirmations: 6 # Minimal confirmations needed for withdraw and deposit confirmation.
explorer:
address: https://etherscan.io/address/#{address}
transaction: https://etherscan.io/tx/#{txid}
status: disabled
- key: btc-testnet
name: Bitcoin Testnet
client: bitcoin # API client name.
server: http://user:password@127.0.0.1:18332 # Public Bitcoin node endpoint.
height: 1500000 # Initial block number from which sync will be started.
min_confirmations: 6 # Minimal confirmations needed for withdraw and deposit confirmation.
explorer:
address: https://testnet.blockchain.info/address/#{address}
transaction: https://testnet.blockchain.info/tx/#{txid}
status: active
<% end %>

View File

@@ -0,0 +1,99 @@
<% if ENV['CURRENCIES_CONFIG'] %>
<%= File.read(ENV['CURRENCIES_CONFIG']) %>
<% else %>
- id: usd
name: US Dollar
type: fiat
precision: 2
base_factor: 1
visible: true
deposit_enabled: true
withdrawal_enabled: true
min_deposit_amount: 0
min_collection_amount: 0
withdraw_limit_24h: 100
withdraw_limit_72h: 200
deposit_fee: 0
withdraw_fee: 0
position: 1
options: {}
- id: btc
name: Bitcoin
blockchain_key: btc-testnet
type: coin
precision: 8
base_factor: 100_000_000
visible: true
deposit_enabled: true
withdrawal_enabled: true
# Deposits with less amount are skipped during blockchain synchronization.
# We advise to set value 10 times bigger than the network fee to prevent losses.
min_deposit_amount: 0.0000356
min_collection_amount: 0.0000356
withdraw_limit_24h: 0.1
withdraw_limit_72h: 0.2
deposit_fee: 0
withdraw_fee: 0
position: 2
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: true
withdrawal_enabled: true
# Deposits with less amount are skipped during blockchain synchronization.
# We advise to set value 10 times bigger than the network fee to prevent losses.
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: 3
options:
# ETH tx fees configurations.
#
# Maximum amount of gas you're willing to spend on a particular transaction.
gas_limit: 21_000
# Internal price that is paid for running a transaction on the Ethereum network.
gas_price: 1_000_000_000
- id: trst
name: WeTrust
blockchain_key: eth-rinkeby
parent_id: eth
type: coin
precision: 8
base_factor: 1_000_000 # 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: true
withdrawal_enabled: true
# 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: 2
withdraw_limit_24h: 300
withdraw_limit_72h: 600
deposit_fee: 0
withdraw_fee: 0
position: 4
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: '0x0000000000000000000000000000000000000000' # Always wrap this value in quotes!
<% end %>

View File

@@ -0,0 +1,4 @@
- id: 1
kind: 'fiat'
kyc_level: 1
limit_24_hour: 500000000

View File

@@ -0,0 +1,28 @@
<% if ENV['ENGINES_CONFIG'] %>
<%= File.read(ENV['ENGINES_CONFIG']) %>
<% else %>
- name: peatio-default-engine
driver: peatio
state: online
- name: local-finex-spot-engine
driver: finex-spot
state: online
- name: opendax-finex-spote-engine
driver: opendax
uid: U123456789
url: https://www.opendax.io/api/v2/finex
key: ""
secret: ""
data: {}
# The data field for store some special engines metadata
# Can be used in upstream worker
# Example for upstream:
# {
# "rest"=>"https://url",
# "websocket"=>"wss://url",
# "trade_proxy"=>true,
# "orderbook_proxy"=>"true"
# }
# }
state: online
<% end %>

View File

@@ -0,0 +1,81 @@
<% if ENV['MARKETS_CONFIG'] %>
<%= File.read(ENV['MARKETS_CONFIG']) %>
<% else %>
- id: btcusd
base_unit: btc
quote_unit: usd
engine_name: peatio-default-engine
amount_precision: 4
price_precision: 4
min_price: 0.0001
max_price: 0.0
min_amount: 0.0001
position: 100
state: enabled
data: {}
- id: ethusd
base_unit: eth
quote_unit: usd
engine_name: peatio-default-engine
amount_precision: 4
price_precision: 4
min_price: 0.0001
max_price: 0.0
min_amount: 0.0001
position: 101
state: enabled
data: {}
- id: trstusd
base_unit: trst
quote_unit: usd
engine_name: peatio-default-engine
amount_precision: 4
price_precision: 4
min_price: 0.0001
max_price: 0.0
min_amount: 0.0001
position: 102
state: enabled
data: {}
- id: ethbtc
base_unit: eth
quote_unit: btc
engine_name: peatio-default-engine
amount_precision: 4
price_precision: 4
min_price: 0.0001
max_price: 0.0
min_amount: 0.0001
position: 103
state: enabled
data: {}
- id: trstbtc
base_unit: trst
quote_unit: btc
engine_name: peatio-default-engine
amount_precision: 4
price_precision: 4
min_price: 0.0001
max_price: 0.0
min_amount: 0.0001
position: 104
state: enabled
data: {}
- id: trsteth
base_unit: trst
quote_unit: eth
engine_name: peatio-default-engine
amount_precision: 4
price_precision: 4
min_price: 0.0001
max_price: 0.0
min_amount: 0.0001
position: 105
state: enabled
data: {}
<% end %>

View File

@@ -0,0 +1,28 @@
- id: 1
uid: '1'
email: 'test1@test.com'
level: 2
role: 'admin'
group: 'vip-3'
state: 'active'
- id: 2
uid: '2'
email: 'test2@test.com'
level: 2
role: 'admin'
group: 'vip-3'
state: 'active'
- id: 3
uid: '3'
email: 'test3@test.com'
level: 2
role: 'admin'
group: 'vip-3'
state: 'active'

View File

@@ -0,0 +1,29 @@
<% if ENV['TRADING_FEES_CONFIG'] %>
<%= File.read(ENV['TRADING_FEES_CONFIG']) %>
<% else %>
- market_id: any
group: any
maker: 0.002
taker: 0.002
- market_id: any
group: vip-0
maker: 0.001
taker: 0.002
- market_id: any
group: vip-1
maker: 0.0008
taker: 0.0018
- market_id: any
group: vip-2
maker: 0.0006
taker: 0.0016
- market_id: any
group: vip-3
maker: 0.0
taker: 0.0014
<% end %>

View File

@@ -0,0 +1,108 @@
<% if ENV['WALLETS_CONFIG'] %>
<%= File.read(ENV['WALLETS_CONFIG']) %>
<% else %>
- name: Ethereum Deposit Wallet
blockchain_key: eth-rinkeby
currency_ids: eth,trst
# Address where deposits will be collected to.
address: '0x2b9fBC10EbAeEc28a8Fc10069C0BC29E45eBEB9C' # IMPORTANT: Always wrap this value in quotes!
kind: deposit # Wallet kind (deposit, hot, warm, cold or fee).
max_balance: 0.0
status: active
gateway: geth # Gateway client name.
settings:
#
# Geth gateway client settings.
uri: http://127.0.0.1:8545
secret: 'changeme'
- name: Ethereum Hot Wallet
blockchain_key: eth-rinkeby
currency_ids: eth,trst
# Address where deposits will be collected to.
address: '0x270704935783087a01c7a28d8f2d8f01670c8050' # IMPORTANT: Always wrap this value in quotes!
kind: hot # Wallet kind (deposit, hot, warm, cold or fee).
max_balance: 100.0
status: active
gateway: geth # Gateway client name.
settings:
#
# Geth gateway client settings.
uri: http://127.0.0.1:8545
secret: 'test'
- name: Ethereum Warm Wallet
blockchain_key: eth-rinkeby
currency_ids: eth,trst
# Address where deposits will be collected to.
address: '0x2b9fBC10EbAeEc28a8Fc10069C0BC29E45eBEB9C' # IMPORTANT: Always wrap this value in quotes!
kind: warm # Wallet kind (deposit, hot, warm, cold or fee).
max_balance: 1000.0
status: active
gateway: geth # Gateway client name.
settings:
#
# Geth gateway client settings.
uri: http://127.0.0.1:8545
secret: 'test'
- name: Ethereum Wallet for paying ERC20 fees
blockchain_key: eth-rinkeby
currency_ids: eth
# Address where deposits will be collected to.
address: '0x270704935783087a01c7a28d8f2d8f01670c8050' # IMPORTANT: Always wrap this value in quotes!
kind: fee # Wallet kind (deposit, hot, warm, cold or fee).
max_balance: 100.0
status: active
gateway: geth # Gateway client name.
settings:
#
# Geth gateway client settings.
uri: http://127.0.0.1:8545
secret: 'test'
- name: Bitcoin Deposit Wallet
blockchain_key: btc-testnet
currency_ids: btc
# Address where deposits will be collected to.
address: '2N4qYjye5yENLEkz4UkLFxzPaxJatF3kRwf' # IMPORTANT: Always wrap this value in quotes!
kind: deposit # Wallet kind (deposit, hot, warm, cold or fee).
max_balance: 0.0
status: active
gateway: bitcoind # Gateway client name.
settings:
#
# Bitcoind gateway client settings.
uri: http://user:password@127.0.0.1:18332
- name: Bitcoin Hot Wallet
blockchain_key: btc-testnet
currency_ids: btc
# Address where deposits will be collected to.
address: '2N4qYjye5yENLEkz4UkLFxzPaxJatF3kRwf' # IMPORTANT: Always wrap this value in quotes!
kind: hot # Wallet kind (deposit, hot, warm, cold or fee).
max_balance: 0.0
status: active
gateway: bitcoind # Gateway client name.
settings:
#
# Bitcoind gateway client settings.
uri: http://user:password@127.0.0.1:18332
# skip_deposit_collection - defines if deposit will be collected to
# this wallet. Supported values: true | false. By default `false`.
skip_deposit_collection: true
- name: Bitcoin Warm Wallet
blockchain_key: btc-testnet
currency_ids: btc
# Address where deposits will be collected to.
address: '2N4qYjye5yENLEkz4UkLFxzPaxJatF3kRwf' # IMPORTANT: Always wrap this value in quotes!
kind: warm # Wallet kind (deposit, hot, warm, cold or fee).
max_balance: 0.0
status: active
gateway: bitcoind # Gateway client name.
settings:
#
# Bitcoind gateway client settings.
uri: http://user:password@127.0.0.1:18332
<% end %>

View File

@@ -0,0 +1,21 @@
<% if ENV['WHITELISTED_CONTRACTS'] %>
<%= File.read(ENV['WHITELISTED_CONTRACTS']) %>
<% else %>
- blockchain_key: eth-mainet
address: '0x6c0b51971650d28821ce30b15b02b9826a20b129'
state: active
- blockchain_key: eth-mainet
address: '0x1522900b6dafac587d499a862861c0869be6e428'
state: active
- blockchain_key: eth-rinkeby
address: '0xbbd602bb278edff65cbc967b9b62095ad5be23a3'
state: active
- blockchain_key: eth-rinkeby
address: '0xe3cb6897d83691a8eb8458140a1941ce1d6e6dac'
state: active
<% end %>

View File

@@ -0,0 +1,9 @@
<% if ENV['WITHDRAW_LIMITS_CONFIG'] %>
<%= File.read(ENV['WITHDRAW_LIMITS_CONFIG']) %>
<% else %>
- kyc_level: any
group: any
# limits in USD
limit_24_hour: 100
limit_1_month: 1000
<% end %>

10
config/transfer_types.yml Normal file
View File

@@ -0,0 +1,10 @@
deposit:
card: 101
wire: 102
swift: 103
sepa: 104
withdraw:
card: 101
wire: 102
swift: 103
sepa: 104