Initial commit
This commit is contained in:
60
app/api/v2/public/currencies.rb
Normal file
60
app/api/v2/public/currencies.rb
Normal file
@@ -0,0 +1,60 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Public
|
||||
class Currencies < Grape::API
|
||||
|
||||
helpers ::API::V2::ParamHelpers
|
||||
|
||||
desc 'Get a currency' do
|
||||
success Entities::Currency
|
||||
end
|
||||
params do
|
||||
requires :id,
|
||||
type: String,
|
||||
values: { value: -> { Currency.visible.codes(bothcase: true) }, message: 'public.currency.doesnt_exist'},
|
||||
desc: -> { API::V2::Entities::Currency.documentation[:id][:desc] }
|
||||
end
|
||||
get '/currencies/:id', requirements: { id: /[\w\.\-]+/ } do
|
||||
present Currency.find(params[:id]), with: API::V2::Entities::Currency
|
||||
end
|
||||
|
||||
desc 'Get list of currencies',
|
||||
is_array: true,
|
||||
success: Entities::Currency
|
||||
params do
|
||||
use :pagination
|
||||
optional :type,
|
||||
type: String,
|
||||
values: { value: %w[fiat coin], message: 'public.currency.invalid_type' },
|
||||
desc: -> { API::V2::Entities::Currency.documentation[:type][:desc] }
|
||||
optional :search, type: JSON, default: {} do
|
||||
optional :code,
|
||||
type: String,
|
||||
desc: 'Search by currency code using SQL LIKE'
|
||||
optional :name,
|
||||
type: String,
|
||||
desc: 'Search by currency name using SQL LIKE'
|
||||
end
|
||||
end
|
||||
get '/currencies' do
|
||||
search_attrs = { m: 'or',
|
||||
code_cont: params.dig(:search, :code),
|
||||
name_cont: params.dig(:search, :name) }
|
||||
|
||||
|
||||
present paginate(Rails.cache.fetch("currencies_#{params}", expires_in: 600) do
|
||||
currencies = Currency.visible.ordered
|
||||
currencies = currencies.where(type: params[:type]).includes(:blockchain) if params[:type] == 'coin'
|
||||
currencies = currencies.where(type: params[:type]) if params[:type] == 'fiat'
|
||||
|
||||
search = currencies.ransack(search_attrs)
|
||||
search.result.load.to_a
|
||||
end), with: API::V2::Entities::Currency
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
36
app/api/v2/public/deposit_limits.rb
Normal file
36
app/api/v2/public/deposit_limits.rb
Normal file
@@ -0,0 +1,36 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Public
|
||||
class DepositLimits < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
desc 'Returns deposit limits table as paginated collection',
|
||||
is_array: true,
|
||||
success: API::V2::Entities::DepositLimit
|
||||
params do
|
||||
optional :group,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:group][:desc] },
|
||||
coerce_with: ->(c) { c.strip.downcase }
|
||||
optional :kyc_level,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::DepositLimit.documentation[:kyc_level][:desc] }
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/deposit_limits' do
|
||||
ransack_params = API::V2::Admin::Helpers::RansackBuilder.new(params)
|
||||
.eq(:group, :kyc_level)
|
||||
.build
|
||||
|
||||
search = DepositLimit.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
present paginate(Rails.cache.fetch("deposit_limits_#{params}", expires_in: 600) { search.result.load.to_a }), with: API::V2::Entities::DepositLimit
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
197
app/api/v2/public/markets.rb
Normal file
197
app/api/v2/public/markets.rb
Normal file
@@ -0,0 +1,197 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Public
|
||||
class Markets < Grape::API
|
||||
helpers ::API::V2::OrderHelpers
|
||||
helpers ::API::V2::ParamHelpers
|
||||
|
||||
class OrderBook < Struct.new(:asks, :bids); end
|
||||
|
||||
resource :markets do
|
||||
desc 'Get all available markets.',
|
||||
is_array: true,
|
||||
success: API::V2::Entities::Market
|
||||
params do
|
||||
use :pagination
|
||||
optional :ordering,
|
||||
values: { value: %w(asc desc), message: 'public.markets.invalid_ordering' },
|
||||
default: 'asc',
|
||||
desc: 'If set, returned values will be sorted in specific order, defaults to \'asc\'.'
|
||||
optional :order_by,
|
||||
values: { value: %w(id position), message: 'public.markets.invalid_order_by' },
|
||||
default: 'position',
|
||||
desc: 'Name of the field, which result will be ordered by.'
|
||||
optional :base_unit,
|
||||
type: String,
|
||||
values: { value: -> (v){ ::Currency.exists?(v) },
|
||||
message: 'public.markets.base_unit_doesnt_exist' },
|
||||
desc: 'Strict filter for base unit'
|
||||
optional :quote_unit,
|
||||
type: String,
|
||||
values: { value: -> (v){ ::Currency.exists?(v) },
|
||||
message: 'public.markets.quote_unit_doesnt_exist' },
|
||||
desc: 'Strict filter for quote unit'
|
||||
optional :search, type: JSON, default: {} do
|
||||
optional :base_code,
|
||||
type: String,
|
||||
desc: 'Search base currency code using LIKE'
|
||||
optional :quote_code,
|
||||
type: String,
|
||||
desc: 'Search qoute currency code using LIKE'
|
||||
optional :base_name,
|
||||
type: String,
|
||||
desc: 'Search base currency name using LIKE'
|
||||
optional :quote_name,
|
||||
type: String,
|
||||
desc: 'Search quote currency name using LIKE'
|
||||
end
|
||||
end
|
||||
get "/" do
|
||||
search_params = params[:search]
|
||||
.slice(:base_code, :quote_code, :base_name, :quote_name)
|
||||
.transform_keys {|k| "#{k}_cont"}
|
||||
.merge(m: 'or')
|
||||
|
||||
search = ::Market.active
|
||||
.where(params.slice(:base_unit, :quote_unit))
|
||||
.ransack(search_params)
|
||||
|
||||
# Add default ordering (position asc) for cases markets where unit position is same.
|
||||
search.sorts = ["#{params[:order_by]} #{params[:ordering]}", "position asc"]
|
||||
|
||||
present paginate(Rails.cache.fetch("markets_#{params}", expires_in: 600) { search.result.load.to_a }),
|
||||
with: API::V2::Entities::Market,
|
||||
extended: !!params[:extended]
|
||||
end
|
||||
|
||||
desc 'Get the order book of specified market.',
|
||||
is_array: true,
|
||||
success: API::V2::Entities::OrderBook
|
||||
params do
|
||||
requires :market,
|
||||
type: String,
|
||||
values: { value: -> { ::Market.active.ids }, message: 'public.market.doesnt_exist' },
|
||||
desc: -> { V2::Entities::Market.documentation[:id] }
|
||||
optional :asks_limit,
|
||||
type: { value: Integer, message: 'public.order_book.non_integer_ask_limit' },
|
||||
values: { value: 1..200, message: 'public.order_book.invalid_ask_limit' },
|
||||
default: 20,
|
||||
desc: 'Limit the number of returned sell orders. Default to 20.'
|
||||
optional :bids_limit,
|
||||
type: { value: Integer, message: 'public.order_book.non_integer_bid_limit' },
|
||||
values: { value: 1..200, message: 'public.order_book.invalid_bid_limit' },
|
||||
default: 20,
|
||||
desc: 'Limit the number of returned buy orders. Default to 20.'
|
||||
end
|
||||
get ":market/order-book", requirements: { market: /[\w\.\-]+/ } do
|
||||
asks = OrderAsk.active.with_market(params[:market]).matching_rule.limit(params[:asks_limit])
|
||||
bids = OrderBid.active.with_market(params[:market]).matching_rule.limit(params[:bids_limit])
|
||||
book = OrderBook.new asks, bids
|
||||
present book, with: API::V2::Entities::OrderBook
|
||||
end
|
||||
|
||||
desc 'Get recent trades on market, each trade is included only once. Trades are sorted in reverse creation order.',
|
||||
is_array: true,
|
||||
success: API::V2::Entities::Trade
|
||||
params do
|
||||
requires :market,
|
||||
type: String,
|
||||
values: { value: -> { ::Market.active.ids }, message: 'public.market.doesnt_exist' },
|
||||
desc: -> { V2::Entities::Market.documentation[:id] }
|
||||
optional :limit,
|
||||
type: { value: Integer, message: 'public.trade.non_integer_limit' },
|
||||
values: { value: 1..1000, message: 'public.trade.invalid_limit' },
|
||||
default: 100,
|
||||
desc: 'Limit the number of returned trades. Default to 100.'
|
||||
optional :timestamp,
|
||||
type: { value: Integer, message: 'public.trade.non_integer_timestamp' },
|
||||
desc: "An integer represents the seconds elapsed since Unix epoch."\
|
||||
"If set, only trades executed before the time will be returned."
|
||||
optional :order_by,
|
||||
type: String,
|
||||
values: { value: %w(asc desc), message: 'public.trade.invalid_order_by' },
|
||||
default: 'desc',
|
||||
desc: "If set, returned trades will be sorted in specific order, default to 'desc'."
|
||||
end
|
||||
get ":market/trades", requirements: { market: /[\w\.\-]+/ } do
|
||||
present Trade.public_from_influx(params[:market], params[:limit]), with: API::V2::Entities::PublicTrade
|
||||
end
|
||||
|
||||
desc 'Get depth or specified market. Both asks and bids are sorted from highest price to lowest.'
|
||||
params do
|
||||
requires :market,
|
||||
type: String,
|
||||
values: { value: -> { ::Market.active.ids }, message: 'public.market.doesnt_exist' },
|
||||
desc: -> { V2::Entities::Market.documentation[:id] }
|
||||
optional :limit,
|
||||
type: { value: Integer, message: 'public.market_depth.non_integer_limit' },
|
||||
values: { value: 1..1000, message: 'public.market_depth.invalid_limit' },
|
||||
default: 300,
|
||||
desc: 'Limit the number of returned price levels. Default to 300.'
|
||||
end
|
||||
get ":market/depth", requirements: { market: /[\w\.\-]+/ } do
|
||||
asks = OrderAsk.get_depth(params[:market])[0, params[:limit]]
|
||||
bids = OrderBid.get_depth(params[:market])[0, params[:limit]]
|
||||
{ timestamp: Time.now.to_i, asks: asks, bids: bids }
|
||||
end
|
||||
|
||||
desc 'Get OHLC(k line) of specific market.'
|
||||
params do
|
||||
requires :market,
|
||||
type: String,
|
||||
values: { value: -> { ::Market.active.ids }, message: 'public.market.doesnt_exist' },
|
||||
desc: -> { V2::Entities::Market.documentation[:id] }
|
||||
optional :period,
|
||||
type: { value: Integer, message: 'public.k_line.non_integer_period' },
|
||||
values: { value: KLineService::AVAILABLE_POINT_PERIODS, message: 'public.k_line.invalid_period' },
|
||||
default: 1,
|
||||
desc: "Time period of K line, default to 1. You can choose between #{KLineService::AVAILABLE_POINT_PERIODS.join(', ')}"
|
||||
optional :time_from,
|
||||
type: { value: Integer, message: 'public.k_line.non_integer_time_from' },
|
||||
allow_blank: { value: false, c_name: 'k_line' },
|
||||
desc: "An integer represents the seconds elapsed since Unix epoch. If set, only k-line data after that time will be returned."
|
||||
optional :time_to,
|
||||
type: { value: Integer, message: 'public.k_line.non_integer_time_to' },
|
||||
allow_blank: { value: false, c_name: 'k_line' },
|
||||
desc: "An integer represents the seconds elapsed since Unix epoch. If set, only k-line data till that time will be returned."
|
||||
optional :limit,
|
||||
type: { value: Integer, message: 'public.k_line.non_integer_limit' },
|
||||
values: { value: KLineService::AVAILABLE_POINT_LIMITS, message: 'public.k_line.invalid_limit' },
|
||||
default: 30,
|
||||
desc: "Limit the number of returned data points default to 30. Ignored if time_from and time_to are given."
|
||||
end
|
||||
get ":market/k-line", requirements: { market: /[\w\.\-]+/ } do
|
||||
KLineService[params[:market], params[:period]]
|
||||
.get_ohlc(params.slice(:limit, :time_from, :time_to).merge(offset: true))
|
||||
end
|
||||
|
||||
desc 'Get ticker of all markets (For response doc see /:market/tickers/ response).'
|
||||
get "/tickers" do
|
||||
Rails.cache.fetch(:markets_tickers, expires_in: 60) do
|
||||
::Market.active.ordered.inject({}) do |h, m|
|
||||
h[m.id] = format_ticker TickersService[m].ticker
|
||||
h
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Get ticker of specific market.',
|
||||
success: API::V2::Entities::Ticker
|
||||
params do
|
||||
requires :market,
|
||||
type: String,
|
||||
values: { value: -> { ::Market.active.ids }, message: 'public.market.doesnt_exist' },
|
||||
desc: -> { V2::Entities::Market.documentation[:id] }
|
||||
end
|
||||
get "/:market/tickers/", requirements: { market: /[\w\.\-]+/ } do
|
||||
present format_ticker(TickersService[params[:market]].ticker),
|
||||
with: API::V2::Entities::Ticker
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
17
app/api/v2/public/member_levels.rb
Normal file
17
app/api/v2/public/member_levels.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Public
|
||||
class MemberLevels < Grape::API
|
||||
desc 'Returns hash of minimum levels and the privileges they provide.'
|
||||
get '/member-levels' do
|
||||
{ deposit: { minimum_level: ENV.fetch('MINIMUM_MEMBER_LEVEL_FOR_DEPOSIT').to_i },
|
||||
withdraw: { minimum_level: ENV.fetch('MINIMUM_MEMBER_LEVEL_FOR_WITHDRAW').to_i },
|
||||
trading: { minimum_level: ENV.fetch('MINIMUM_MEMBER_LEVEL_FOR_TRADING').to_i } }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
21
app/api/v2/public/mount.rb
Normal file
21
app/api/v2/public/mount.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Public
|
||||
class Mount < Grape::API
|
||||
|
||||
before { set_ets_context! }
|
||||
|
||||
mount Public::Currencies
|
||||
mount Public::Markets
|
||||
mount Public::MemberLevels
|
||||
mount Public::Tools
|
||||
mount Public::TradingFees
|
||||
mount Public::Webhooks
|
||||
mount Public::WithdrawLimits
|
||||
mount Public::DepositLimits
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
39
app/api/v2/public/tools.rb
Normal file
39
app/api/v2/public/tools.rb
Normal file
@@ -0,0 +1,39 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Public
|
||||
class Tools < Grape::API
|
||||
desc 'Get server current time, in seconds since Unix epoch.'
|
||||
get "/timestamp" do
|
||||
::Time.now.iso8601
|
||||
end
|
||||
|
||||
desc 'Get running Dena version and build details.'
|
||||
get "/version" do
|
||||
{
|
||||
git_tag: Peatio::Application::GIT_TAG,
|
||||
git_sha: Peatio::Application::GIT_SHA,
|
||||
build_date: Peatio::Application::BUILD_DATE,
|
||||
version: Peatio::Application::VERSION
|
||||
}.tap do |v|
|
||||
present OpenStruct.new(v), with: Entities::Version
|
||||
end
|
||||
end
|
||||
|
||||
resource :health do
|
||||
desc 'Get application liveness status'
|
||||
get "/alive" do
|
||||
status Services::HealthChecker.alive? ? 200 : 503
|
||||
end
|
||||
|
||||
desc 'Get application readiness status'
|
||||
get "/ready" do
|
||||
status Services::HealthChecker.ready? ? 200 : 503
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
39
app/api/v2/public/trading_fees.rb
Normal file
39
app/api/v2/public/trading_fees.rb
Normal file
@@ -0,0 +1,39 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Public
|
||||
class TradingFees < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
desc 'Returns trading_fees table as paginated collection',
|
||||
is_array: true,
|
||||
success: API::V2::Entities::TradingFee
|
||||
params do
|
||||
optional :group,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:group][:desc] },
|
||||
coerce_with: ->(c) { c.strip.downcase }
|
||||
optional :market_id,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::TradingFee.documentation[:market_id][:desc] },
|
||||
values: { value: -> { ::Market.ids.append(::TradingFee::ANY) },
|
||||
message: 'public.trading_fee.market_doesnt_exist' }
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/trading_fees' do
|
||||
ransack_params = API::V2::Admin::Helpers::RansackBuilder.new(params)
|
||||
.eq(:group, :market_id)
|
||||
.build
|
||||
|
||||
search = TradingFee.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
present paginate(Rails.cache.fetch("trading_fees_#{params}", expires_in: 600) { search.result.load.to_a }), with: API::V2::Entities::TradingFee
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
55
app/api/v2/public/webhooks.rb
Normal file
55
app/api/v2/public/webhooks.rb
Normal file
@@ -0,0 +1,55 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Public
|
||||
class Webhooks < Grape::API
|
||||
helpers ::API::V2::WebhooksHelpers
|
||||
|
||||
desc 'Bitgo Webhook'
|
||||
params do
|
||||
requires :event,
|
||||
type: String,
|
||||
desc: 'Name of event can be deposit or withdraw',
|
||||
values: { value: -> { %w[deposit withdraw] }, message: 'public.webhook.invalid_event' }
|
||||
requires :type,
|
||||
type: String,
|
||||
desc: 'Type of event.'
|
||||
given type: ->(val) { val == 'transfer' } do
|
||||
requires :hash,
|
||||
type: String,
|
||||
desc: 'Transfer txid.'
|
||||
requires :transfer,
|
||||
type: String,
|
||||
desc: 'Transfer id.'
|
||||
requires :coin,
|
||||
type: String,
|
||||
desc: 'Currency code.'
|
||||
requires :wallet,
|
||||
type: String,
|
||||
desc: 'Wallet id.'
|
||||
end
|
||||
given type: ->(val) { val == 'address_confirmation' } do
|
||||
requires :hash,
|
||||
type: String,
|
||||
desc: 'Address txid.'
|
||||
requires :address,
|
||||
type: String,
|
||||
desc: 'User Address.'
|
||||
requires :walletId,
|
||||
type: String,
|
||||
desc: 'Wallet id.'
|
||||
end
|
||||
end
|
||||
post '/webhooks/:event' do
|
||||
proces_webhook_event(params)
|
||||
status 200
|
||||
rescue StandardError => e
|
||||
Rails.logger.warn { "Cannot perform webhook: #{params}. Error: #{e}." }
|
||||
body errors: ["public.webhook.cannot_perfom_#{params['type']}"]
|
||||
status 422
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
36
app/api/v2/public/withdraw_limits.rb
Normal file
36
app/api/v2/public/withdraw_limits.rb
Normal file
@@ -0,0 +1,36 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module V2
|
||||
module Public
|
||||
class WithdrawLimits < Grape::API
|
||||
helpers ::API::V2::Admin::Helpers
|
||||
|
||||
desc 'Returns withdraw limits table as paginated collection',
|
||||
is_array: true,
|
||||
success: API::V2::Entities::WithdrawLimit
|
||||
params do
|
||||
optional :group,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:group][:desc] },
|
||||
coerce_with: ->(c) { c.strip.downcase }
|
||||
optional :kyc_level,
|
||||
type: String,
|
||||
desc: -> { API::V2::Entities::WithdrawLimit.documentation[:kyc_level][:desc] }
|
||||
use :pagination
|
||||
use :ordering
|
||||
end
|
||||
get '/withdraw_limits' do
|
||||
ransack_params = API::V2::Admin::Helpers::RansackBuilder.new(params)
|
||||
.eq(:group, :kyc_level)
|
||||
.build
|
||||
|
||||
search = WithdrawLimit.ransack(ransack_params)
|
||||
search.sorts = "#{params[:order_by]} #{params[:ordering]}"
|
||||
|
||||
present paginate(Rails.cache.fetch("withdraw_limits_#{params}", expires_in: 600) { search.result.load.to_a }), with: API::V2::Entities::WithdrawLimit
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user