Files
Dena/app/api/v2/management/withdraws.rb
2026-08-13 19:50:53 +03:30

156 lines
7.8 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# encoding: UTF-8
# frozen_string_literal: true
module API
module V2
module Management
class Withdraws < Grape::API
helpers do
def perform_action(withdraw, action)
withdraw.with_lock do
case action
when 'process'
withdraw.accept!
# Process fiat withdraw immediately. Crypto withdraws will be processed by workers.
if withdraw.currency.fiat?
withdraw.process!
withdraw.dispatch!
withdraw.success!
end
when 'cancel'
withdraw.cancel!
end
end
end
end
desc 'Returns withdraws as paginated collection.' do
@settings[:scope] = :read_withdraws
success API::V2::Management::Entities::Withdraw
end
params do
optional :uid, type: String, desc: 'The shared user ID.'
optional :currency, type: String, values: -> { Currency.codes(bothcase: true) }, desc: 'The currency code.'
optional :page, type: Integer, default: 1, integer_gt_zero: true, desc: 'The page number (defaults to 1).'
optional :limit, type: Integer, default: 100, range: 1..1000, desc: 'The number of objects per page (defaults to 100, maximum is 1000).'
optional :state, type: String, values: -> { Withdraw::STATES.map(&:to_s) }, desc: 'The state to filter by.'
end
post '/withdraws' do
currency = Currency.find(params[:currency]) if params[:currency].present?
member = Member.find_by!(uid: params[:uid]) if params[:uid].present?
Withdraw
.order(id: :desc)
.includes(:member, :currency)
.tap { |q| q.where!(currency: currency) if currency }
.tap { |q| q.where!(member: member) if member }
.tap { |q| q.where!(aasm_state: params[:state]) if params[:state] }
.page(params[:page])
.per(params[:limit])
.tap { |q| present q, with: API::V2::Management::Entities::Withdraw }
status 200
end
desc 'Returns withdraw by ID.' do
@settings[:scope] = :read_withdraws
success API::V2::Management::Entities::Withdraw
end
params do
requires :tid, type: String, desc: 'The shared transaction ID.'
end
post '/withdraws/get' do
present Withdraw.find_by!(params.slice(:tid)), with: API::V2::Management::Entities::Withdraw
end
desc 'Creates new withdraw.' do
@settings[:scope] = :write_withdraws
detail 'Creates new withdraw. The behaviours for fiat and crypto withdraws are different. ' \
'Fiat: money are immediately locked, withdraw state is set to «submitted», system workers ' \
'will validate withdraw later against suspected activity, and assign state to «rejected» or «accepted». ' \
'The processing will not begin automatically. The processing may be initiated manually from admin panel or by PUT /management_api/v1/withdraws/action. ' \
'Coin: money are immediately locked, withdraw state is set to «submitted», system workers ' \
'will validate withdraw later against suspected activity, validate withdraw address and ' \
'set state to «rejected» or «accepted». ' \
'Then in case state is «accepted» withdraw workers will perform interactions with blockchain. ' \
'The withdraw receives new state «processing». Then withdraw receives state either «confirming» or «failed».' \
'Then in case state is «confirming» withdraw confirmations workers will perform interactions with blockchain.' \
'Withdraw receives state «succeed» when it receives minimum necessary amount of confirmations.'
success API::V2::Management::Entities::Withdraw
end
params do
requires :uid, type: String, desc: 'The shared user ID.'
optional :tid, type: String, desc: 'The shared transaction ID. Must not exceed 64 characters. Peatio will generate one automatically unless supplied.'
optional :rid, type: String, desc: 'The beneficiary ID or wallet address on the Blockchain.'
optional :beneficiary_id, type: String, desc: 'ID of Active Beneficiary belonging to user.'
requires :currency, type: String, values: -> { Currency.codes(bothcase: true) }, desc: 'The currency code.'
requires :amount, type: BigDecimal, desc: 'The amount to withdraw.'
optional :note, type: String, desc: 'The note for withdraw.'
optional :action, type: String, values: %w[process], desc: 'The action to perform.'
optional :transfer_type, type: String,
values: { value: -> { Withdraw::TRANSFER_TYPES.keys }, message: 'account.withdraw.transfer_type_not_in_list' },
desc: -> { API::V2::Admin::Entities::Withdraw.documentation[:transfer_type][:desc] }
exactly_one_of :rid, :beneficiary_id
end
post '/withdraws/new' do
member = Member.find_by(uid: params[:uid])
currency = Currency.find(params[:currency])
unless currency.withdrawal_enabled?
error!({ errors: ['management.currency.withdrawal_disabled'] }, 422)
end
beneficiary = Beneficiary.find_by(id: params[:beneficiary_id]) if params[:beneficiary_id].present?
if params[:rid].blank? && beneficiary.blank?
error!({ errors: ['management.beneficiary.doesnt_exist'] }, 422)
elsif params[:rid].blank? && !beneficiary&.active?
error!({ errors: ['management.beneficiary.invalid_state_for_withdrawal'] }, 422)
end
if params[:tid].present?
error!({ errors: ['TID already exist'] }, 422) if Withdraw.where(tid: params[:tid]).present?
end
declared_params = declared(params, include_missing: false).slice(:tid, :rid, :note, :transfer_type).merge(
sum: params[:amount],
member: member,
currency: currency,
tid: params[:tid]
)
declared_params.merge!(beneficiary: beneficiary) if params[:beneficiary_id].present?
withdraw = "withdraws/#{currency.type}".camelize.constantize.new(declared_params)
withdraw.save!
withdraw.with_lock { withdraw.accept! }
perform_action(withdraw, params[:action]) if params[:action]
present withdraw, with: API::V2::Management::Entities::Withdraw
rescue ::Account::AccountError => e
report_api_error(e, request)
error!({ errors: [e.to_s] }, 422)
rescue => e
report_exception(e)
error!({ errors: ['Failed to create withdraw!'] }, 422)
end
desc 'Performs action on withdraw.' do
@settings[:scope] = :write_withdraws
detail '«process» system will lock the money, check for suspected activity, validate recipient address, and initiate the processing of the withdraw. ' \
'«cancel» system will mark withdraw as «canceled», and unlock the money.'
success API::V2::Management::Entities::Withdraw
end
params do
requires :tid, type: String, desc: 'The shared transaction ID.'
requires :action, type: String, values: %w[process cancel], desc: 'The action to perform.'
end
put '/withdraws/action' do
record = Withdraw.find_by!(params.slice(:tid))
perform_action(record, params[:action])
present record, with: API::V2::Management::Entities::Withdraw
end
end
end
end
end