Skip to content

Commit 057ab2a

Browse files
chumaknadyamnaichuk
authored andcommitted
Feature: Add manual deposit approve
1 parent 08f7d82 commit 057ab2a

File tree

7 files changed

+232
-27
lines changed

7 files changed

+232
-27
lines changed

app/api/v2/admin/deposits.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class Deposits < Grape::API
122122
desc: -> { API::V2::Admin::Entities::Refund.documentation[:address][:desc] }
123123
end
124124
post '/deposits/:id/refund' do
125-
admin_authorize! :wrrie, ::Deposit
125+
admin_authorize! :write, ::Deposit
126126

127127
deposit = Deposit.find(params[:id])
128128

app/models/deposit.rb

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,16 @@ class Deposit < ApplicationRecord
4848
state :collected
4949
state :fee_processing
5050
state :errored
51+
state :refunding
5152
event(:cancel) { transitions from: :submitted, to: :canceled }
5253
event(:reject) { transitions from: :submitted, to: :rejected }
5354
event :accept do
5455
transitions from: :submitted, to: :accepted
56+
5557
after do
56-
if currency.coin? && Peatio::App.config.deposit_funds_locked
58+
if currency.coin? && (Peatio::App.config.deposit_funds_locked ||
59+
Peatio::AML.adapter.present? ||
60+
Peatio::App.config.manual_deposit_approval)
5761
account.plus_locked_funds(amount)
5862
else
5963
account.plus_funds(amount)
@@ -66,17 +70,19 @@ class Deposit < ApplicationRecord
6670
end
6771

6872
event :process do
69-
if Peatio::AML.adapter.present?
70-
transitions from: %i[aml_processing aml_suspicious accepted errored], to: :aml_processing do
71-
after do
72-
process_collect! if aml_check!
73-
end
73+
transitions from: %i[aml_processing aml_suspicious accepted errored], to: :aml_processing do
74+
guard do
75+
Peatio::AML.adapter.present? || Peatio::App.config.manual_deposit_approval
7476
end
75-
else
76-
transitions from: %i[accepted skipped errored], to: :processing do
77-
guard { currency.coin? }
77+
78+
after do
79+
process_collect! if aml_check!
7880
end
7981
end
82+
83+
transitions from: %i[accepted skipped errored], to: :processing do
84+
guard { currency.coin? }
85+
end
8086
end
8187

8288
event :fee_process do
@@ -91,13 +97,24 @@ class Deposit < ApplicationRecord
9197

9298
event :process_collect do
9399
transitions from: %i[aml_processing aml_suspicious], to: :processing do
94-
guard { currency.coin? }
100+
guard do
101+
currency.coin? && (Peatio::AML.adapter.present? || Peatio::App.config.manual_deposit_approval)
102+
end
103+
104+
after do
105+
if !Peatio::App.config.deposit_funds_locked
106+
account.unlock_funds(amount)
107+
record_complete_operations!
108+
end
109+
end
95110
end
96-
end if Peatio::AML.adapter.present?
111+
end
97112

98113
event :aml_suspicious do
99-
transitions from: :aml_processing, to: :aml_suspicious
100-
end if Peatio::AML.adapter.present?
114+
transitions from: :aml_processing, to: :aml_suspicious do
115+
guard { Peatio::AML.adapter.present? || Peatio::App.config.manual_deposit_approval }
116+
end
117+
end
101118

102119
event :dispatch do
103120
transitions from: %i[processing fee_processing], to: :collected
@@ -117,6 +134,10 @@ class Deposit < ApplicationRecord
117134
end
118135

119136
def aml_check!
137+
# If there is no AML adapter on a platform and manual deposit approval enabled
138+
# system will return nil value to not proceed with automatic deposit collection in aml cron job
139+
return nil if Peatio::App.config.manual_deposit_approval && Peatio::AML.adapter.blank?
140+
120141
from_addresses.each do |address|
121142
result = Peatio::AML.check!(address, currency_id, member.uid)
122143
if result.risk_detected
@@ -225,7 +246,8 @@ def record_submit_operations!
225246
member_id: member_id
226247
)
227248

228-
kind = currency.coin? && Peatio::App.config.deposit_funds_locked ? :locked : :main
249+
locked_kind_check = currency.coin? && (Peatio::App.config.deposit_funds_locked || Peatio::App.config.manual_deposit_approval)
250+
kind = locked_kind_check ? :locked : :main
229251
# Credit locked fiat/crypto Liability account.
230252
Operations::Liability.credit!(
231253
amount: amount,

app/models/refund.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class Refund < ApplicationRecord
1515

1616
event :process do
1717
transitions from: :pending, to: :processed
18+
1819
after do
1920
process_refund!
2021
end
@@ -26,7 +27,7 @@ class Refund < ApplicationRecord
2627
end
2728

2829
def process_refund!
29-
transaction = WalletService.new(Wallet.deposit.find_by(currency: deposit.currency)).refund!(self)
30+
transaction = WalletService.new(Wallet.active_deposit_wallet(deposit.currency.id)).refund!(self)
3031
deposit.refund! if transaction.present?
3132
end
3233
end

app/services/wallet_service.rb

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,24 @@ def deposit_collection_fees!(deposit, deposit_spread)
124124
end
125125

126126
def refund!(refund)
127-
refund_transaction = Peatio::Transaction.new(to_address: refund.address,
128-
amount: refund.deposit.amount)
127+
@adapter.configure(wallet: @wallet.to_wallet_api_settings,
128+
currency: refund.deposit.currency.to_blockchain_api_settings)
129+
130+
pa = PaymentAddress.find_by(wallet_id: @wallet.id, member: refund.deposit.member, address: refund.deposit.address)
131+
# NOTE: Deposit wallet configuration is tricky because wallet URI
132+
# is saved on Wallet model but wallet address and secret
133+
# are saved in PaymentAddress.
134+
@adapter.configure(
135+
wallet: @wallet.to_wallet_api_settings
136+
.merge(pa.details.symbolize_keys)
137+
.merge(address: pa.address)
138+
.tap { |s| s.merge!(secret: pa.secret) if pa.secret.present? }
139+
.compact
140+
)
129141

142+
refund_transaction = Peatio::Transaction.new(to_address: refund.address,
143+
amount: refund.deposit.amount,
144+
currency_id: refund.deposit.currency_id)
130145
@adapter.create_transaction!(refund_transaction, subtract_fee: true)
131146
end
132147

config/initializers/config.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44

55
Peatio::App.define do |config|
66
config.set(:deposit_funds_locked, 'false', type: :bool)
7+
config.set(:manual_deposit_approval, 'false', type: :bool)
78
end

spec/models/deposit_spec.rb

Lines changed: 137 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,34 @@
172172
end
173173
end
174174

175+
context 'with manual deposit approval' do
176+
before { Peatio::App.config.stubs(:manual_deposit_approval).returns(true) }
177+
context 'credits both legacy and operations based member balance for coin deposit' do
178+
subject { create(:deposit_btc, amount: 3.7) }
179+
180+
it do
181+
subject.accept!
182+
%i[main locked].each do |kind|
183+
expect(
184+
subject.member.balance_for(currency: subject.currency, kind: kind)
185+
).to eq(
186+
subject.member.legacy_balance_for(currency: subject.currency, kind: kind)
187+
)
188+
end
189+
190+
expect(subject.member.balance_for(currency: subject.currency, kind: :locked)).to eq 3.7
191+
expect(subject.member.balance_for(currency: subject.currency, kind: :main)).to eq 0
192+
193+
# Lock funds on deposit accepted step (1 liability)
194+
liabilities = Operations::Liability.where(currency_id: subject.currency.id, member_id: subject.member.id, reference_type: 'Deposit')
195+
expect(liabilities.count).to eq 1
196+
197+
account = Operations::Account.find_by(kind: :locked, currency_type: subject.currency.type, type: 'liability', scope: 'member')
198+
expect(liabilities.first.code).to eq account.code
199+
end
200+
end
201+
end
202+
175203
context 'with locked funds' do
176204
before { Peatio::App.config.stubs(:deposit_funds_locked).returns(true) }
177205
context 'credits both legacy and operations based member balance for coin deposit' do
@@ -204,18 +232,118 @@
204232
end
205233

206234
context :process do
207-
let(:crypto_deposit) { create(:deposit_btc, amount: 3.7) }
235+
context 'fiat deposit' do
236+
it 'doesnt process fiat deposit' do
237+
deposit.accept!
238+
expect(deposit.process!).to eq false
239+
end
240+
end
241+
242+
context 'coin deposit' do
243+
context 'automatic process' do
244+
context 'coin deposit' do
245+
subject { create(:deposit_btc, amount: 3.7) }
246+
it 'process coin deposit' do
247+
crypto_deposit = create(:deposit_btc, amount: 3.7)
248+
crypto_deposit.accept!
249+
expect(crypto_deposit.process!).to eq true
250+
expect(crypto_deposit.processing?).to eq true
251+
end
252+
end
253+
end
208254

209-
it 'doesnt process fiat deposit' do
210-
deposit.accept!
211-
expect(deposit.process!).to eq false
255+
context 'manual process' do
256+
before do
257+
Peatio::App.config.stubs(:manual_deposit_approval).returns(true)
258+
end
259+
260+
subject { create(:deposit_btc, amount: 3.7) }
261+
262+
it do
263+
subject.accept!
264+
subject.process!
265+
266+
expect(subject.aml_processing?).to eq true
267+
end
268+
end
212269
end
270+
end
213271

214-
it 'process coin deposit' do
215-
crypto_deposit = create(:deposit_btc, amount: 3.7)
216-
crypto_deposit.accept!
217-
expect(crypto_deposit.process!).to eq true
218-
expect(crypto_deposit.processing?).to eq true
272+
context 'process collect' do
273+
let(:crypto_deposit) { create(:deposit_btc, amount: 3.7) }
274+
275+
subject { crypto_deposit }
276+
277+
context 'with manual deposit approval' do
278+
context 'deposit_funds_locked disabled' do
279+
before do
280+
Peatio::App.config.stubs(:manual_deposit_approval).returns(true)
281+
crypto_deposit.accept!
282+
crypto_deposit.process!
283+
end
284+
285+
it 'process deposit collection' do
286+
crypto_deposit.process_collect!
287+
288+
expect(crypto_deposit.processing?).to eq true
289+
290+
%i[main locked].each do |kind|
291+
expect(
292+
subject.member.balance_for(currency: subject.currency, kind: kind)
293+
).to eq(
294+
subject.member.legacy_balance_for(currency: subject.currency, kind: kind)
295+
)
296+
297+
liabilities = Operations::Liability.where(currency_id: subject.currency.id, member_id: subject.member.id)
298+
expect(liabilities.count).to eq 3
299+
300+
# Lock funds on deposit accepted step (1 liability)
301+
account = Operations::Account.find_by(kind: :locked, currency_type: subject.currency.type, type: 'liability', scope: 'member')
302+
expect(liabilities.first.code).to eq account.code
303+
304+
# Moved funds from locked to main (2 liabilities)
305+
# debit
306+
account = Operations::Account.find_by(kind: :locked, currency_type: subject.currency.type, type: 'liability', scope: 'member')
307+
expect(liabilities.second.code).to eq account.code
308+
309+
# credit
310+
account = Operations::Account.find_by(kind: :main, currency_type: subject.currency.type, type: 'liability', scope: 'member')
311+
expect(liabilities.last.code).to eq account.code
312+
end
313+
end
314+
end
315+
316+
context 'deposit_funds_locked enabled' do
317+
before do
318+
Peatio::App.config.stubs(:deposit_funds_locked).returns(true)
319+
crypto_deposit.accept!
320+
crypto_deposit.process!
321+
end
322+
323+
it 'process deposit collection' do
324+
crypto_deposit.process_collect!
325+
326+
expect(crypto_deposit.processing?).to eq true
327+
328+
%i[main locked].each do |kind|
329+
expect(
330+
subject.member.balance_for(currency: subject.currency, kind: kind)
331+
).to eq(
332+
subject.member.legacy_balance_for(currency: subject.currency, kind: kind)
333+
)
334+
end
335+
336+
expect(subject.member.balance_for(currency: subject.currency, kind: :locked)).to eq 3.7
337+
expect(subject.member.balance_for(currency: subject.currency, kind: :main)).to eq 0
338+
339+
# Lock funds on deposit accepted step (1 liability)
340+
liabilities = Operations::Liability.where(currency_id: subject.currency.id, member_id: subject.member.id, reference_type: 'Deposit')
341+
expect(liabilities.count).to eq 1
342+
343+
account = Operations::Account.find_by(kind: :locked, currency_type: subject.currency.type, type: 'liability', scope: 'member')
344+
expect(liabilities.first.code).to eq account.code
345+
end
346+
end
219347
end
220348
end
221349

spec/services/wallet_service_spec.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,4 +819,42 @@
819819
end
820820
end
821821
end
822+
823+
context :refund do
824+
before do
825+
Peatio::Blockchain.registry.expects(:[])
826+
.with(:bitcoin)
827+
.returns(fake_blockchain_adapter.class)
828+
.at_least_once
829+
end
830+
831+
let!(:deposit_wallet) { create(:wallet, :fake_deposit) }
832+
833+
let(:amount) { 2 }
834+
let(:refund_deposit) { create(:deposit_btc, amount: amount, currency: currency) }
835+
836+
let(:fake_wallet_adapter) { FakeWallet.new }
837+
let(:service) { WalletService.new(deposit_wallet) }
838+
839+
let(:transaction) do
840+
Peatio::Transaction.new(hash: '0xfake',
841+
to_address: 'user_address',
842+
amount: refund_deposit.amount,
843+
currency_id: currency.id)
844+
end
845+
846+
let!(:refund) { Refund.create(deposit: refund_deposit, address: 'user_address') }
847+
848+
subject { service.refund!(refund) }
849+
850+
before do
851+
refund_deposit.member.payment_address(service.wallet.id).update(address: refund_deposit.address)
852+
service.adapter.expects(:create_transaction!).returns(transaction)
853+
end
854+
855+
it 'creates single transaction' do
856+
expect(subject).to eq(transaction)
857+
expect(subject).to be_a(Peatio::Transaction)
858+
end
859+
end
822860
end

0 commit comments

Comments
 (0)