Files
Dena/app/models/deposit.rb
2026-08-13 19:50:53 +03:30

295 lines
8.8 KiB
Ruby

# encoding: UTF-8
# frozen_string_literal: true
class Deposit < ApplicationRecord
STATES = %i[submitted canceled rejected accepted collected skipped processing fee_processing].freeze
SUCCEED_PROCESSING_STATES = %i[accepted collected skipped processing fee_processing].freeze
serialize :spread, Array
serialize :from_addresses, Array
include AASM
include AASM::Locking
include TIDIdentifiable
include FeeChargeable
extend Enumerize
TRANSFER_TYPES = { fiat: 100, crypto: 200 }.freeze
belongs_to :currency, required: true
belongs_to :member, required: true
acts_as_eventable prefix: 'deposit', on: %i[create update]
validates :tid, presence: true, uniqueness: { case_sensitive: false }
validates :aasm_state, :type, presence: true
validates :completed_at, presence: { if: :completed? }
validates :block_number, allow_blank: true, numericality: { greater_than_or_equal_to: 0, only_integer: true }
validates :amount,
numericality: {
greater_than_or_equal_to:
-> (deposit){ deposit.currency.min_deposit_amount }
}
validate :verify_limits, on: :create
scope :recent, -> { order(id: :desc) }
before_validation { self.completed_at ||= Time.current if completed? }
before_validation { self.transfer_type ||= currency.coin? ? 'crypto' : 'fiat' }
aasm whiny_transitions: false do
state :submitted, initial: true
state :canceled
state :rejected
state :accepted
state :aml_processing
state :aml_suspicious
state :processing
state :skipped
state :collected
state :fee_processing
event(:cancel) { transitions from: :submitted, to: :canceled }
event(:reject) { transitions from: :submitted, to: :rejected }
event :accept do
transitions from: :submitted, to: :accepted
after do
if currency.coin? && Peatio::App.config.deposit_funds_locked
account.plus_locked_funds(amount)
else
account.plus_funds(amount)
end
record_submit_operations!
end
end
event :skip do
transitions from: :processing, to: :skipped
end
event :process do
if Peatio::AML.adapter.present?
transitions from: %i[aml_processing aml_suspicious accepted], to: :aml_processing do
after do
process_collect! if aml_check!
end
end
else
transitions from: %i[accepted skipped], to: :processing do
guard { currency.coin? }
end
end
end
event :fee_process do
transitions from: %i[accepted processing skipped], to: :fee_processing do
guard { currency.coin? }
end
end
event :process_collect do
transitions from: %i[aml_processing aml_suspicious], to: :processing do
guard { currency.coin? }
end
end if Peatio::AML.adapter.present?
event :aml_suspicious do
transitions from: :aml_processing, to: :aml_suspicious
end if Peatio::AML.adapter.present?
event :dispatch do
transitions from: %i[processing fee_processing], to: :collected
after do
if Peatio::App.config.deposit_funds_locked
account.unlock_funds(amount)
record_complete_operations!
end
end
end
event :refund do
transitions from: %i[aml_suspicious skipped], to: :refunding do
guard { currency.coin? }
end
end
end
def aml_check!
from_addresses.each do |address|
result = Peatio::AML.check!(address, currency_id, member.uid)
if result.risk_detected
aml_suspicious!
return nil
end
return nil if result.pending
end
true
end
def verify_limits
limits = DepositLimit.for(kyc_level: member.level, group: member.group, kind: transfer_type)
# If there are no limits in DB or current user withdraw limit
# has 0.0 for 24 hour and 1 month it will skip this checks
return true if limits.limit_24_hour.zero? && limits.limit_1_month.zero?
# Withdraw limits in USD and withdraw sum in currency.
# Convert withdraw sums with price from the currency model.
sum_24_hours, sum_1_month = ::Deposit.sanitize_execute_sum_queries(member_id)
errors.add(:member_id, 'reached 24 hours limitation') if sum_24_hours >= limits.limit_24_hour
errors.add(:member_id, 'reached 1 month limitation') if sum_1_month >= limits.limit_1_month
end
def blockchain_api
currency.blockchain_api
end
def confirmations
return 0 if block_number.blank?
return blockchain.processed_height - block_number if (blockchain.processed_height - block_number) >= 0
'N/A'
rescue StandardError => e
report_exception(e)
'N/A'
end
def spread_to_transactions
spread.map { |s| Peatio::Transaction.new(s) }
end
def spread_between_wallets!
return false if spread.present?
spread = WalletService.new(Wallet.deposit_wallet(currency_id)).spread_deposit(self)
update!(spread: spread.map(&:as_json))
end
def spread
super.map(&:symbolize_keys)
end
def account
member&.get_account(currency)
end
def uid
member&.uid
end
def uid=(uid)
self.member = Member.find_by_uid(uid)
end
def as_json_for_event_api
{ tid: tid,
user: { uid: member.uid, email: member.email },
uid: member.uid,
currency: currency_id,
amount: amount.to_s('F'),
state: aasm_state,
created_at: created_at.iso8601,
updated_at: updated_at.iso8601,
completed_at: completed_at&.iso8601,
blockchain_address: address,
blockchain_txid: txid }
end
def completed?
!submitted?
end
private
# Creates dependant operations for deposit.
def record_submit_operations!
transaction do
# Credit main fiat/crypto Asset account.
Operations::Asset.credit!(
amount: amount + fee,
currency: currency,
reference: self
)
# Credit main fiat/crypto Revenue account.
Operations::Revenue.credit!(
amount: fee,
currency: currency,
reference: self,
member_id: member_id
)
kind = currency.coin? && Peatio::App.config.deposit_funds_locked ? :locked : :main
# Credit locked fiat/crypto Liability account.
Operations::Liability.credit!(
amount: amount,
currency: currency,
reference: self,
member_id: member_id,
kind: kind
)
end
end
# Creates dependant operations for complete deposit.
def record_complete_operations!
transaction do
Operations::Liability.transfer!(
amount: amount,
currency: currency,
reference: self,
from_kind: :locked,
to_kind: :main,
member_id: member_id
)
end
end
class << self
def sum_query
'SELECT sum(d.amount) as sum FROM deposits as d ' \
'where d.transfer_type = 100 ' \
'AND d.member_id = ? AND d.aasm_state IN (?) AND d.created_at > ?;'
end
def sanitize_execute_sum_queries(member_id)
squery_24h = ActiveRecord::Base.sanitize_sql_for_conditions([sum_query, member_id, SUCCEED_PROCESSING_STATES, 24.hours.ago])
squery_1m = ActiveRecord::Base.sanitize_sql_for_conditions([sum_query, member_id, SUCCEED_PROCESSING_STATES, 1.month.ago])
sum_withdraws_24_hours = ActiveRecord::Base.connection.exec_query(squery_24h).to_hash.first['sum'].to_d
sum_withdraws_1_month = ActiveRecord::Base.connection.exec_query(squery_1m).to_hash.first['sum'].to_d
[sum_withdraws_24_hours, sum_withdraws_1_month]
end
end
end
# == Schema Information
# Schema version: 20200827105929
#
# Table name: deposits
#
# member_id :integer not null
# currency_id :string(10) not null
# amount :decimal(32, 16) not null
# fee :decimal(32, 16) not null
# address :string(95)
# from_addresses :string(1000)
# txid :string(128)
# txout :integer
# aasm_state :string(30) not null
# block_number :integer
# type :string(30) not null
# transfer_type :integer
# tid :string(64) not null
# spread :string(1000)
# created_at :datetime not null
# updated_at :datetime not null
# completed_at :datetime
#
# Indexes
#
# index_deposits_on_aasm_state_and_member_id_and_currency_id (aasm_state,member_id,currency_id)
# index_deposits_on_currency_id (currency_id)
# index_deposits_on_currency_id_and_txid_and_txout (currency_id,txid,txout) UNIQUE
# index_deposits_on_member_id_and_txid (member_id,txid)
# index_deposits_on_tid (tid)
# index_deposits_on_type (type)
#