From 1076175c97476392038b4f08d94583c88cff9df5 Mon Sep 17 00:00:00 2001 From: Maksym Naichuk Date: Sun, 6 Dec 2020 21:52:11 +0200 Subject: [PATCH 01/58] Bump master with 2.7.0. Update API docs --- VERSION | 2 +- config/initializers/versioning.rb | 2 +- docs/api/peatio_admin_api_v2.md | 2 +- docs/api/peatio_management_api_v2.md | 2 +- docs/api/peatio_user_api_v2.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index e70b4523ae..24ba9a38de 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.6.0 +2.7.0 diff --git a/config/initializers/versioning.rb b/config/initializers/versioning.rb index cd6ba99fcc..84ab9c58ad 100644 --- a/config/initializers/versioning.rb +++ b/config/initializers/versioning.rb @@ -5,7 +5,7 @@ module Peatio class Application - GIT_TAG = '2.6.0' + GIT_TAG = '2.7.0' GIT_SHA = '66aceba' BUILD_DATE = '2019-11-07 11:43:58+00:00' VERSION = GIT_TAG diff --git a/docs/api/peatio_admin_api_v2.md b/docs/api/peatio_admin_api_v2.md index 275d67de23..fd509dc291 100644 --- a/docs/api/peatio_admin_api_v2.md +++ b/docs/api/peatio_admin_api_v2.md @@ -1,7 +1,7 @@ # Peatio Admin API v2 Admin API high privileged API with RBAC. -## Version: 2.6.0 +## Version: 2.7.0 **Contact information:** openware.com diff --git a/docs/api/peatio_management_api_v2.md b/docs/api/peatio_management_api_v2.md index b6e0b31dc0..dd108ccc96 100644 --- a/docs/api/peatio_management_api_v2.md +++ b/docs/api/peatio_management_api_v2.md @@ -1,7 +1,7 @@ # Peatio Management API v2 Management API is server-to-server API with high privileges. -## Version: 2.6.0 +## Version: 2.7.0 **Contact information:** openware.com diff --git a/docs/api/peatio_user_api_v2.md b/docs/api/peatio_user_api_v2.md index b229b2e650..39240c33f2 100644 --- a/docs/api/peatio_user_api_v2.md +++ b/docs/api/peatio_user_api_v2.md @@ -1,7 +1,7 @@ # Peatio User API v2 API for Peatio application. -## Version: 2.6.0 +## Version: 2.7.0 **Contact information:** openware.com From bbe7d7a4ba29d54364f41f6fc464ad57ffa5504c Mon Sep 17 00:00:00 2001 From: Maksym Date: Fri, 25 Dec 2020 14:43:39 +0200 Subject: [PATCH 02/58] Enhancement: Cleanup application.yml (#2789) --- app/api/v2/account/withdraws.rb | 2 -- app/api/v2/helpers.rb | 6 ------ config/application.rb | 2 +- config/templates/application.yml.erb | 20 -------------------- spec/api/v2/account/withdraws_spec.rb | 10 ---------- 5 files changed, 1 insertion(+), 39 deletions(-) diff --git a/app/api/v2/account/withdraws.rb b/app/api/v2/account/withdraws.rb index ea49cbd2c6..f42ddbc981 100644 --- a/app/api/v2/account/withdraws.rb +++ b/app/api/v2/account/withdraws.rb @@ -91,8 +91,6 @@ class Withdraws < Grape::API post '/withdraws' do user_authorize! :create, ::Withdraw - withdraw_api_must_be_enabled! - beneficiary = current_user .beneficiaries .available_to_member diff --git a/app/api/v2/helpers.rb b/app/api/v2/helpers.rb index 97f0928a00..81153f1641 100644 --- a/app/api/v2/helpers.rb +++ b/app/api/v2/helpers.rb @@ -66,12 +66,6 @@ def trading_must_be_permitted! end end - def withdraw_api_must_be_enabled! - if ENV.false?('ENABLE_ACCOUNT_WITHDRAWAL_API') - error!({ errors: ['account.withdraw.disabled_api'] }, 422) - end - end - def current_user # jwt.payload provided by rack-jwt if request.env.key?('jwt.payload') diff --git a/config/application.rb b/config/application.rb index a1e6654344..44843f30fa 100644 --- a/config/application.rb +++ b/config/application.rb @@ -39,7 +39,7 @@ class Application < Rails::Application # 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') + config.time_zone = ENV.fetch('TIMEZONE', 'UTC') # Configure relative url root by setting URL_ROOT_PATH environment variable. # Used by microkube with API Gateway. diff --git a/config/templates/application.yml.erb b/config/templates/application.yml.erb index 830e1570af..3674b1baea 100644 --- a/config/templates/application.yml.erb +++ b/config/templates/application.yml.erb @@ -1,6 +1,4 @@ defaults: &defaults - TIMEZONE: 'Paris' - # Configure Redis URL, for a TCP connection: # `redis://:[password]@[hostname]:[port]/[db]` # (password, port and database are optional). @@ -8,12 +6,6 @@ defaults: &defaults 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. @@ -34,11 +26,6 @@ defaults: &defaults # 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. # @@ -116,15 +103,8 @@ defaults: &defaults 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: "" diff --git a/spec/api/v2/account/withdraws_spec.rb b/spec/api/v2/account/withdraws_spec.rb index e4c66cd778..c7190d327c 100644 --- a/spec/api/v2/account/withdraws_spec.rb +++ b/spec/api/v2/account/withdraws_spec.rb @@ -182,16 +182,6 @@ before { account.plus_funds(balance) } before { Vault::TOTP.stubs(:validate?).returns(true) } - context 'disabled account withdrawal API' do - before { ENV['ENABLE_ACCOUNT_WITHDRAWAL_API'] = 'false' } - after { ENV['ENABLE_ACCOUNT_WITHDRAWAL_API'] = 'true' } - it 'doesn\'t allow account withdrawal API call' do - api_post '/api/v2/account/withdraws', params: data, token: token - expect(response).to have_http_status(422) - expect(response).to include_api_error('account.withdraw.disabled_api') - end - end - context 'extremely precise values' do before { Currency.any_instance.stubs(:withdraw_fee).returns(BigDecimal(0)) } before { Currency.any_instance.stubs(:precision).returns(16) } From bc26dab8bbb61b1682ced9703cb66a6dcc7c8dba Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Feb 2021 16:08:29 +0300 Subject: [PATCH 03/58] Add guard to auto test changes --- Gemfile | 4 +++ Gemfile.lock | 32 +++++++++++++++++++++ Guardfile | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ bin/_guard-core | 29 +++++++++++++++++++ bin/guard | 29 +++++++++++++++++++ 5 files changed, 169 insertions(+) create mode 100644 Guardfile create mode 100755 bin/_guard-core create mode 100755 bin/guard diff --git a/Gemfile b/Gemfile index 7298836c87..e5e99112f1 100644 --- a/Gemfile +++ b/Gemfile @@ -72,6 +72,10 @@ group :development do gem 'annotate', '~> 3.1.0' gem 'ruby-prof', '~> 0.17.0', require: false gem 'listen', '>= 3.0.5', '< 3.2' + + gem 'rspec' + gem 'guard' + gem 'guard-rspec', github: 'caspark/guard-rspec' # Use from github to remove rspec < 4.0 dependencies end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index f7bd8b0b53..bc7a330f12 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,6 +6,14 @@ GIT rails (>= 4.1) vault (~> 0.14) +GIT + remote: https://github.com/caspark/guard-rspec + revision: 407ef8c62f3abad575bb66d53c02ba062a5ee8af + specs: + guard-rspec (4.7.3) + guard (~> 2.1) + guard-compat (~> 1.1) + GEM remote: https://rubygems.org/ specs: @@ -166,6 +174,7 @@ GEM ffi (1.15.0) figaro (1.1.1) thor (~> 0.14) + formatador (0.2.5) globalid (0.4.2) activesupport (>= 4.2.0) god (0.13.7) @@ -191,6 +200,16 @@ GEM rack grape_on_rails_routes (0.3.2) rails (>= 3.1.1) + guard (2.16.2) + formatador (>= 0.2.4) + listen (>= 2.7, < 4.0) + lumberjack (>= 1.0.12, < 2.0) + nenv (~> 0.1) + notiffany (~> 0.0) + pry (>= 0.9.12) + shellany (~> 0.0) + thor (>= 0.18.1) + guard-compat (1.2.1) hashdiff (1.0.1) hashie (3.6.0) hiredis (0.6.3) @@ -234,6 +253,7 @@ GEM loofah (2.9.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) + lumberjack (1.2.8) mail (2.7.1) mini_mime (>= 0.1.1) marcel (0.3.3) @@ -256,12 +276,16 @@ GEM mustermann-grape (1.0.1) mustermann (>= 1.0.0) mysql2 (0.5.3) + nenv (0.3.0) net-http-persistent (3.0.1) connection_pool (~> 2.2) nio4r (2.5.7) nokogiri (1.11.2) mini_portile2 (~> 2.5.0) racc (~> 1.4) + notiffany (0.1.3) + nenv (~> 0.1) + shellany (~> 0.0) parallel (1.20.1) parser (3.0.0.0) ast (~> 2.4.1) @@ -382,6 +406,10 @@ GEM reline (0.2.4) io-console (~> 0.5) rexml (3.2.4) + rspec (3.9.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) rspec-core (3.9.0) rspec-support (~> 3.9.0) rspec-expectations (3.9.0) @@ -424,6 +452,7 @@ GEM parser sentry-raven (2.9.0) faraday (>= 0.7.6, < 1.0) + shellany (0.0.1) sprockets (4.0.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) @@ -493,6 +522,8 @@ DEPENDENCIES grape-swagger-ui (~> 2.2.8) grape_logging (~> 1.8.0) grape_on_rails_routes (~> 0.3.2) + guard + guard-rspec! hashie (~> 3.6.0) hiredis (~> 0.6.0) influxdb (~> 0.7.0) @@ -524,6 +555,7 @@ DEPENDENCIES ransack (~> 2.3.2) rbtree (~> 0.4.2) redis (~> 4.1.2) + rspec rspec-rails (~> 3.8, >= 3.8.2) rspec-retry (~> 0.6) rubocop-rspec (~> 1.32) diff --git a/Guardfile b/Guardfile new file mode 100644 index 0000000000..f8404d9003 --- /dev/null +++ b/Guardfile @@ -0,0 +1,75 @@ +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +## Uncomment and set this to only include directories you want to watch +# directories %w(app lib config test spec features) \ +# .select{|d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist")} + +## Note: if you are using the `directories` clause above and you are not +## watching the project directory ('.'), then you will want to move +## the Guardfile to a watched dir and symlink it back, e.g. +# +# $ mkdir config +# $ mv Guardfile config/ +# $ ln -s config/Guardfile . +# +# and, you'll have to watch "config/Guardfile" instead of "Guardfile" +# +notification :tmux, display_message: true if ENV.has_key?('TMUX') + +# Note: The cmd option is now required due to the increasing number of ways +# rspec may be run, below are examples of the most common uses. +# * bundler: 'bundle exec rspec' +# * bundler binstubs: 'bin/rspec' +# * spring: 'bin/rspec' (This will use spring if running and you have +# installed the spring binstubs per the docs) +# * zeus: 'zeus rspec' (requires the server to be started separately) +# * 'just' rspec: 'rspec' + +guard :rspec, cmd: "bundle exec rspec" do + require "guard/rspec/dsl" + dsl = Guard::RSpec::Dsl.new(self) + + # Feel free to open issues for suggestions and improvements + + # RSpec files + rspec = dsl.rspec + watch(rspec.spec_helper) { rspec.spec_dir } + watch(rspec.spec_support) { rspec.spec_dir } + watch(rspec.spec_files) + + # Ruby files + ruby = dsl.ruby + dsl.watch_spec_files_for(ruby.lib_files) + + # Rails files + rails = dsl.rails(view_extensions: %w(erb haml slim)) + dsl.watch_spec_files_for(rails.app_files) + dsl.watch_spec_files_for(rails.views) + + watch(rails.controllers) do |m| + [ + rspec.spec.call("routing/#{m[1]}_routing"), + rspec.spec.call("controllers/#{m[1]}_controller"), + rspec.spec.call("acceptance/#{m[1]}") + ] + end + + # Rails config changes + watch(rails.spec_helper) { rspec.spec_dir } + watch(rails.routes) { "#{rspec.spec_dir}/routing" } + watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" } + + # Capybara features specs + watch(rails.view_dirs) { |m| rspec.spec.call("features/#{m[1]}") } + watch(rails.layouts) { |m| rspec.spec.call("features/#{m[1]}") } + + # Turnip features and steps + watch(%r{^spec/acceptance/(.+)\.feature$}) + watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m| + Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance" + end + + # Rake tasks + dsl.watch_spec_files_for(dsl.rake.rake_files) +end diff --git a/bin/_guard-core b/bin/_guard-core new file mode 100755 index 0000000000..cd565c3a6c --- /dev/null +++ b/bin/_guard-core @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application '_guard-core' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("guard", "_guard-core") diff --git a/bin/guard b/bin/guard new file mode 100755 index 0000000000..bcb966f4c1 --- /dev/null +++ b/bin/guard @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'guard' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path("../bundle", __FILE__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("guard", "guard") From 37fa0eda14b3ea4d9baf37ace96ac5961a64d888 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Fri, 5 Mar 2021 12:11:23 +0300 Subject: [PATCH 04/58] Enhancement: Use system timezone if no TIMEZONE env --- config/application.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/application.rb b/config/application.rb index 44843f30fa..c54931dab5 100644 --- a/config/application.rb +++ b/config/application.rb @@ -39,7 +39,7 @@ class Application < Rails::Application # 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', 'UTC') + config.time_zone = ENV.fetch('TIMEZONE', File.read('/etc/timezone').strip) # Configure relative url root by setting URL_ROOT_PATH environment variable. # Used by microkube with API Gateway. From 774cc752d89c7e958cc60d5da050a9e205a5345e Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Fri, 5 Mar 2021 17:40:15 +0300 Subject: [PATCH 05/58] Fix: uninitialized constant OWHDWallet --- config/initializers/wallet_api.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/initializers/wallet_api.rb b/config/initializers/wallet_api.rb index fc1287ef8f..4242d482d2 100644 --- a/config/initializers/wallet_api.rb +++ b/config/initializers/wallet_api.rb @@ -1,3 +1,5 @@ +require 'peatio/owhdwallet/wallet' +require 'peatio/opendax_cloud/wallet' Peatio::Wallet.registry[:bitcoind] = Bitcoin::Wallet Peatio::Wallet.registry[:geth] = Ethereum::Wallet Peatio::Wallet.registry[:parity] = Ethereum::Wallet From 0086603e9cc7abc3fc88cd26308cbc0c67fa6d48 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Wed, 10 Mar 2021 10:41:25 +0300 Subject: [PATCH 06/58] Fix: update wallet without blockchain api --- app/models/wallet.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/wallet.rb b/app/models/wallet.rb index f0526f2375..3fc5dc2c73 100644 --- a/app/models/wallet.rb +++ b/app/models/wallet.rb @@ -69,7 +69,7 @@ class Wallet < ApplicationRecord end before_validation do - next unless address? && blockchain.blockchain_api.supports_cash_addr_format? + next unless address? && blockchain.blockchain_api.try(:supports_cash_addr_format?) self.address = CashAddr::Converter.to_cash_address(address) end From f51abb41296e68bc847cedd30a5adeb367b2a916 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 11 Mar 2021 10:16:19 +0300 Subject: [PATCH 07/58] Add bitzlato gem and update jwt to 2.3.0.dev --- Gemfile | 6 +- Gemfile.lock | 17 +++++- Gemfile.plugin | 1 + lib/peatio/bitzlato/wallet.rb | 52 ++++++++++++++++++ spec/api/v2/account/deposits_spec.rb | 12 ++++ spec/lib/peatio/bitzlato/wallet_spec.rb | 73 +++++++++++++++++++++++++ 6 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 lib/peatio/bitzlato/wallet.rb create mode 100644 spec/lib/peatio/bitzlato/wallet_spec.rb diff --git a/Gemfile b/Gemfile index e5e99112f1..a4a5c78468 100644 --- a/Gemfile +++ b/Gemfile @@ -33,7 +33,11 @@ gem 'faraday_middleware', '~> 0.13.1' gem 'faye', '~> 1.4' gem 'eventmachine', '~> 1.2' gem 'em-synchrony', '~> 1.0' -gem 'jwt', '~> 2.2.0' + +# We use 2.3.0.dev for bitzlato client +# Fill free to update to rubygem version when it will be released +gem 'jwt', github: 'jwt/ruby-jwt' + gem 'email_validator', '~> 1.6.0' gem 'validate_url', '~> 1.0.4' gem 'god', '~> 0.13.7', require: false diff --git a/Gemfile.lock b/Gemfile.lock index bc7a330f12..ed93b2c200 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -14,6 +14,12 @@ GIT guard (~> 2.1) guard-compat (~> 1.1) +GIT + remote: https://github.com/jwt/ruby-jwt + revision: 2cea14fdae439773fafc59640178e5cf7a0af8a4 + specs: + jwt (2.3.0.dev) + GEM remote: https://rubygems.org/ specs: @@ -83,6 +89,10 @@ GEM better-faraday (1.0.8) activesupport (>= 4.0, < 6.0) faraday (~> 0.12) + bitzlato (0.1.2) + faraday (>= 0.17) + json (~> 2.0) + jwt (~> 2.3.0.dev) bootsnap (1.7.3) msgpack (~> 1.0) builder (3.2.4) @@ -227,7 +237,7 @@ GEM faraday_middleware (~> 0.13.1) faye (~> 1.2) peatio (>= 2.4.2) - jwt (2.2.2) + json (2.5.1) jwt-multisig (1.0.5) activesupport (>= 4.0) jwt (~> 2.2) @@ -494,6 +504,7 @@ DEPENDENCIES annotate (~> 3.1.0) arel-is-blank (~> 1.0.0) better-faraday (~> 1.0.5) + bitzlato (~> 0.1.2) bootsnap (>= 1.1.0) bullet (~> 5.9) bump (~> 0.7) @@ -529,7 +540,7 @@ DEPENDENCIES influxdb (~> 0.7.0) irb irix (~> 2.6.0) - jwt (~> 2.2.0) + jwt! jwt-multisig (~> 1.0.0) jwt-rack (~> 0.1.0) kaminari (~> 1.2.1) @@ -574,4 +585,4 @@ RUBY VERSION ruby 2.6.6p146 BUNDLED WITH - 2.1.4 + 2.2.15 diff --git a/Gemfile.plugin b/Gemfile.plugin index a1a43e7466..ec2936e0ea 100644 --- a/Gemfile.plugin +++ b/Gemfile.plugin @@ -9,3 +9,4 @@ gem 'peatio-bitcoincash', '~> 2.6.1' gem 'peatio-ripple', '~> 2.6.1' gem 'peatio-bitgo', '~> 2.6.6' gem 'peatio-electrum', '~> 2.6.2' +gem 'bitzlato', '~> 0.1.2' diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb new file mode 100644 index 0000000000..60f3e96389 --- /dev/null +++ b/lib/peatio/bitzlato/wallet.rb @@ -0,0 +1,52 @@ +module Bitzlato + class Wallet < Peatio::Wallet::Abstract + def initialize(features = {}) + @features = features + @settings = {} + end + + def configure(settings = {}) + # Clean client state during configure. + @client = nil + + @settings = settings + + @wallet = @settings.fetch(:wallet) do + raise Peatio::Wallet::MissingSettingError, :wallet + end.slice(:uri, :key, :uid) + + @currency = @settings.fetch(:currency) do + raise Peatio::Wallet::MissingSettingError, :currency + end.slice(:id) + end + + def create_deposit_intention!(account_id: , amount: ) + response = client + .post('/api/gate/v1/invoices', { + cryptocurrency: currency_id.to_s.upcase, + amount: amount, + comment: "Exchange service deposit for account #{account_id}" + }) + + { + id: response['id'], + links: response['link'].symbolize_keys, + expires_at: Time.at(response['expiryAt']/1000) + } + end + + private + + def currency_id + @currency.fetch(:id) + end + + def client + @client ||= Bitzlato::Client + .new(home_url: @wallet.fetch(:uri), + key: @wallet.fetch(:key), + uid: @wallet.fetch(:uid), + logger: Rails.env.development?) + end + end +end diff --git a/spec/api/v2/account/deposits_spec.rb b/spec/api/v2/account/deposits_spec.rb index 4d98dddb8b..59e3311f63 100644 --- a/spec/api/v2/account/deposits_spec.rb +++ b/spec/api/v2/account/deposits_spec.rb @@ -12,6 +12,18 @@ Ability.stubs(:user_permissions).returns({'member'=>{'read'=>['Deposit', 'PaymentAddress']}}) end + describe 'POST /api/v2/account/deposits' do + it 'requires authentication' do + api_post '/api/v2/account/deposits', params: { amount: 123 } + expect(response.code).to eq '401' + end + + it 'returns with auth token deposits' do + api_post '/api/v2/account/deposits', token: token, params: { currency: :btc, amount: 123 } + expect(response).to be_successful + end + end + describe 'GET /api/v2/account/deposits' do before do create(:deposit_btc, member: member, updated_at: 5.days.ago) diff --git a/spec/lib/peatio/bitzlato/wallet_spec.rb b/spec/lib/peatio/bitzlato/wallet_spec.rb new file mode 100644 index 0000000000..25d8460a2a --- /dev/null +++ b/spec/lib/peatio/bitzlato/wallet_spec.rb @@ -0,0 +1,73 @@ +describe Bitzlato::Wallet do + let(:wallet) { Bitzlato::Wallet.new } + + context :configure do + let(:settings) { { wallet: {}, currency: {} } } + it 'requires wallet' do + expect { wallet.configure(settings.except(:wallet)) }.to raise_error(Peatio::Wallet::MissingSettingError) + + expect { wallet.configure(settings) }.to_not raise_error + end + + it 'requires currency' do + expect { wallet.configure(settings.except(:currency)) }.to raise_error(Peatio::Wallet::MissingSettingError) + + expect { wallet.configure(settings) }.to_not raise_error + end + + it 'sets settings attribute' do + wallet.configure(settings) + expect(wallet.settings).to eq(settings.slice(*Ethereum::Wallet::SUPPORTED_SETTINGS)) + end + end + + context :create_deposit_intention! do + around do |example| + WebMock.disable_net_connect! + example.run + WebMock.allow_net_connect! + end + + let(:uri) { 'http://127.0.0.1:8000' } + let(:key) { + {"kty":"EC","alg":"ES256","crv":"P-256","x":"wwf6h_sZhv6TXAYz4XrdXZVpLo_uoNESbaEf_zEydus","y":"OL-0AqcTNoaCBVAEpDNsU1bpZA7eQ9CtGPZGmEEg5QI","d":"nDTvKjSPQ4UAPiBmJKXeF1MKhuhLtjJtW6hypstWolk"} + } + + let(:settings) do + { + wallet: { uri: uri, key: key, uid: 'merchant_uid' }, + currency: { id: :btc } + } + end + + let(:response) do + { + "id"=>21, + "cryptocurrency"=>"BTC", + "amount"=>"1.1", + "comment"=>"gift from drew", + "link"=>{"telegram"=>"https://t.me/BTC_STAGE_BOT?start=b_9ac6b97e09ecbbfc0d365421f6b98a33", "web"=>"https://s-www.lgk.one/p2p/?start=b_9ac6b97e09ecbbfc0d365421f6b98a33"}, + "createdAt"=>1615444044115, + "expiryAt"=>1615530444115, + "completedAt"=>nil, + "status"=>"active" + } + end + + before do + wallet.configure(settings) + end + + it 'should create an address' do + stub_request(:post, uri + '/api/gate/v1/invoices') + .with(body: {"cryptocurrency":"BTC","amount":123,"comment":"Exchange service deposit for account uid12312"}.to_json) + .to_return(body: response.to_json, headers: { 'Content-Type': 'application/json' }) + + result = wallet.create_deposit_intention!(account_id: 'uid12312', amount: 123) + + expect(result[:id]).to eq 21 + expect(result[:links]).to be_a(Hash) + expect(result[:expires_at]).to be_a(Time) + end + end +end From 00371a4504c2a276495dfdc895d03b9d72bc7fd1 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 11 Mar 2021 10:16:43 +0300 Subject: [PATCH 08/58] Add bitzlato wallet to initializers --- config/initializers/wallet_api.rb | 2 ++ lib/peatio/bitzlato/wallet.rb | 1 + spec/lib/peatio/bitzlato/wallet_spec.rb | 1 + 3 files changed, 4 insertions(+) diff --git a/config/initializers/wallet_api.rb b/config/initializers/wallet_api.rb index 4242d482d2..19297c3402 100644 --- a/config/initializers/wallet_api.rb +++ b/config/initializers/wallet_api.rb @@ -1,5 +1,6 @@ require 'peatio/owhdwallet/wallet' require 'peatio/opendax_cloud/wallet' +require 'peatio/bitzlato/wallet' Peatio::Wallet.registry[:bitcoind] = Bitcoin::Wallet Peatio::Wallet.registry[:geth] = Ethereum::Wallet Peatio::Wallet.registry[:parity] = Ethereum::Wallet @@ -7,3 +8,4 @@ Peatio::Wallet.registry[:ow_hdwallet] = OWHDWallet::Wallet Peatio::Wallet.registry[:opendax] = OWHDWallet::Wallet Peatio::Wallet.registry[:opendax_cloud] = OpendaxCloud::Wallet +Peatio::Wallet.registry[:bitzlato] = Bitzlato::Wallet diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index 60f3e96389..7bd7b89e10 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -29,6 +29,7 @@ def create_deposit_intention!(account_id: , amount: ) }) { + amount: response['amount'].to_d, id: response['id'], links: response['link'].symbolize_keys, expires_at: Time.at(response['expiryAt']/1000) diff --git a/spec/lib/peatio/bitzlato/wallet_spec.rb b/spec/lib/peatio/bitzlato/wallet_spec.rb index 25d8460a2a..85aadb9d5b 100644 --- a/spec/lib/peatio/bitzlato/wallet_spec.rb +++ b/spec/lib/peatio/bitzlato/wallet_spec.rb @@ -66,6 +66,7 @@ result = wallet.create_deposit_intention!(account_id: 'uid12312', amount: 123) expect(result[:id]).to eq 21 + expect(result[:amount]).to eq 1.1 expect(result[:links]).to be_a(Hash) expect(result[:expires_at]).to be_a(Time) end From 0721fbde4e4fa0e630cefd91f72d1d13c342a955 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 11 Mar 2021 10:40:19 +0300 Subject: [PATCH 09/58] Add WalletService#create_deposit_intention! --- app/services/wallet_service.rb | 16 ++++++++++++++++ spec/services/wallet_service_spec.rb | 23 ++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index d1513e118a..1976be5c7f 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -6,6 +6,22 @@ def initialize(wallet) @adapter = Peatio::Wallet.registry[wallet.gateway.to_sym].new(wallet.settings.symbolize_keys) end + def create_deposit_intention!(member, amount) + currency = @wallet.currencies.first + @adapter.configure(wallet: @wallet.to_wallet_api_settings, + currency: { id: currency.id }) + + intention = @adapter.create_deposit_intention!(account_id: member.id, amount: amount) + Deposit.create!( + type: Deposit.name, + member: member, + currency: currency, + amount: intention[:amount], + transfer_type: currency.type == 'fiat' ? 'fiat' : 'crypto', + tid: [@adapter.class, intention[:id]].join('#'), + ) + end + def create_address!(uid, pa_details) @adapter.configure(wallet: @wallet.to_wallet_api_settings, currency: @wallet.currencies.first.to_blockchain_api_settings) diff --git a/spec/services/wallet_service_spec.rb b/spec/services/wallet_service_spec.rb index 68696fb2f0..9384ddadf1 100644 --- a/spec/services/wallet_service_spec.rb +++ b/spec/services/wallet_service_spec.rb @@ -26,6 +26,27 @@ Blockchain.any_instance.stubs(:blockchain_api).returns(BlockchainService.new(blockchain)) end + context :create_deposit_intention! do + let(:member) { create(:member) } + let(:amount) { 1.12 } + let(:intention) { { id: 123, amount: amount, links: { web: 'somelink', telegram: 'somelink' }, expires_at: 3.days.ago } } + before do + service.adapter.expects(:create_deposit_intention!).returns(intention) + end + + subject do + service.create_deposit_intention!(member, amount) + end + + fit 'creates depotion intention' do + expect(subject).to be_a(Deposit) + end + + fit 'deposit amount equals to requested' do + expect(subject.amount).to eq amount + end + end + context :create_address! do let(:account) { create(:member, :level_3, :barong).get_account(currency) } let(:blockchain_address) do @@ -740,7 +761,7 @@ let(:fake_wallet_adapter) { FakeWallet.new } let(:service) { WalletService.new(fee_wallet) } - let(:spread_deposit) do + let(:spread_deposit) do [Peatio::Transaction.new(to_address: 'fake-cold', amount: '2.0', currency_id: currency.id)] From 5ee1c067531538d29215be4dc8dece628d697e70 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 11 Mar 2021 17:57:24 +0300 Subject: [PATCH 10/58] Add /api/v2/account/deposits/intention --- app/api/v2/account/deposits.rb | 33 ++++++++++++++++++++++++++++ app/services/wallet_service.rb | 3 ++- lib/peatio/bitzlato/wallet.rb | 4 ++++ spec/api/v2/account/deposits_spec.rb | 16 ++++++++++---- spec/services/wallet_service_spec.rb | 5 +++-- 5 files changed, 54 insertions(+), 7 deletions(-) diff --git a/app/api/v2/account/deposits.rb b/app/api/v2/account/deposits.rb index ecaf60a26b..0b085316a3 100644 --- a/app/api/v2/account/deposits.rb +++ b/app/api/v2/account/deposits.rb @@ -10,6 +10,39 @@ class Deposits < Grape::API before { deposits_must_be_permitted! } + + desc 'Create deposit intention', + success: API::V2::Entities::Deposit + params do + requires :currency, + type: String, + values: { value: -> { Currency.visible.codes(bothcase: true) }, message: 'account.currency.doesnt_exist' }, + desc: 'Currency code' + requires :amount, + type: BigDecimal, + desc: 'The deposit amount.' + end + + post '/deposits/intention' do + currency = Currency.find(params[:currency]) + + unless currency.deposit_enabled? + error!({ errors: ['management.currency.deposit_disabled'] }, 422) + end + + wallet = Wallet.deposit_wallet(currency.id) + + unless wallet.present? + error!({ errors: ['account.wallet.not_found'] }, 422) + end + + deposit = WalletService + .new(wallet) + .create_deposit_intention!(current_user, params[:amount]) + + present deposit, with: API::V2::Entities::Deposit + end + desc 'Get your deposits history.', is_array: true, success: API::V2::Entities::Deposit diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 1976be5c7f..983bc3c473 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -11,6 +11,7 @@ def create_deposit_intention!(member, amount) @adapter.configure(wallet: @wallet.to_wallet_api_settings, currency: { id: currency.id }) + # TODO save links intention = @adapter.create_deposit_intention!(account_id: member.id, amount: amount) Deposit.create!( type: Deposit.name, @@ -18,7 +19,7 @@ def create_deposit_intention!(member, amount) currency: currency, amount: intention[:amount], transfer_type: currency.type == 'fiat' ? 'fiat' : 'crypto', - tid: [@adapter.class, intention[:id]].join('#'), + tid: @adapter.generate_unique_id(intention[:id]) ) end diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index 7bd7b89e10..26ed56f02d 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -20,6 +20,10 @@ def configure(settings = {}) end.slice(:id) end + def generate_unique_id(id) + [self.class.name, @wallet[:uid], id].join('-') + end + def create_deposit_intention!(account_id: , amount: ) response = client .post('/api/gate/v1/invoices', { diff --git a/spec/api/v2/account/deposits_spec.rb b/spec/api/v2/account/deposits_spec.rb index 59e3311f63..932abd5769 100644 --- a/spec/api/v2/account/deposits_spec.rb +++ b/spec/api/v2/account/deposits_spec.rb @@ -12,15 +12,23 @@ Ability.stubs(:user_permissions).returns({'member'=>{'read'=>['Deposit', 'PaymentAddress']}}) end - describe 'POST /api/v2/account/deposits' do + describe 'POST /api/v2/account/deposits/intention' do + let(:wallet) { Wallet.deposit.joins(:currencies).find_by(currencies: { id: currency }) } + let(:amount) { 12.1231 } it 'requires authentication' do - api_post '/api/v2/account/deposits', params: { amount: 123 } + api_post '/api/v2/account/deposits/intention', params: { amount: 123 } expect(response.code).to eq '401' end - it 'returns with auth token deposits' do - api_post '/api/v2/account/deposits', token: token, params: { currency: :btc, amount: 123 } + fit 'returns with auth token deposits' do + Wallet.any_instance.stubs(:gateway).returns(:bitzlato) + Wallet.any_instance.stubs(:settings).returns({ key: {}, uid: :some_acount_id, uri: 'uri' }) + Bitzlato::Wallet.any_instance.stubs(:create_deposit_intention!).returns({ amount: amount, id: :unique_intention_id, links: {}}) + api_post '/api/v2/account/deposits/intention', token: token, params: { currency: :btc, amount: amount } + expect(response).to be_successful + result = JSON.parse(response.body) + expect(result['amount']).to eq amount.to_s end end diff --git a/spec/services/wallet_service_spec.rb b/spec/services/wallet_service_spec.rb index 9384ddadf1..6142a6dedd 100644 --- a/spec/services/wallet_service_spec.rb +++ b/spec/services/wallet_service_spec.rb @@ -32,17 +32,18 @@ let(:intention) { { id: 123, amount: amount, links: { web: 'somelink', telegram: 'somelink' }, expires_at: 3.days.ago } } before do service.adapter.expects(:create_deposit_intention!).returns(intention) + service.adapter.expects(:generate_unique_id).returns('123') end subject do service.create_deposit_intention!(member, amount) end - fit 'creates depotion intention' do + it 'creates depotion intention' do expect(subject).to be_a(Deposit) end - fit 'deposit amount equals to requested' do + it 'deposit amount equals to requested' do expect(subject.amount).to eq amount end end From 54f3662177baf5bd174465719fe9e7cf8693010c Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 11 Mar 2021 18:08:11 +0300 Subject: [PATCH 11/58] Add Deposit#data --- app/models/deposit.rb | 1 + app/services/wallet_service.rb | 2 +- db/migrate/20210311145918_add_data_to_deposits.rb | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20210311145918_add_data_to_deposits.rb diff --git a/app/models/deposit.rb b/app/models/deposit.rb index 4aa3fb77ee..8e12b67560 100644 --- a/app/models/deposit.rb +++ b/app/models/deposit.rb @@ -6,6 +6,7 @@ class Deposit < ApplicationRecord serialize :spread, Array serialize :from_addresses, Array + serialize :data, JSON unless Rails.configuration.database_support_json include AASM include AASM::Locking diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 983bc3c473..a3f750c266 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -11,11 +11,11 @@ def create_deposit_intention!(member, amount) @adapter.configure(wallet: @wallet.to_wallet_api_settings, currency: { id: currency.id }) - # TODO save links intention = @adapter.create_deposit_intention!(account_id: member.id, amount: amount) Deposit.create!( type: Deposit.name, member: member, + data: intention.slice(:links), currency: currency, amount: intention[:amount], transfer_type: currency.type == 'fiat' ? 'fiat' : 'crypto', diff --git a/db/migrate/20210311145918_add_data_to_deposits.rb b/db/migrate/20210311145918_add_data_to_deposits.rb new file mode 100644 index 0000000000..05c14695b3 --- /dev/null +++ b/db/migrate/20210311145918_add_data_to_deposits.rb @@ -0,0 +1,5 @@ +class AddDataToDeposits < ActiveRecord::Migration[5.2] + def change + add_column :deposits, :data, :json + end +end From 700740ea50490be4a0d136756234e1fa8788c680 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Fri, 12 Mar 2021 09:47:50 +0300 Subject: [PATCH 12/58] Add poll_intenetion to Bitzlato wallet --- lib/peatio/bitzlato/wallet.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index 26ed56f02d..af0dab1b7a 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -40,6 +40,11 @@ def create_deposit_intention!(account_id: , amount: ) } end + def poll_intentions + client + .get('/api/gate/v1/invoices/')['data'] + end + private def currency_id From a2adace776551731cd9bddd1b4c918cd3a0f7abd Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 15 Mar 2021 10:40:56 +0300 Subject: [PATCH 13/58] Add Peatio::Bitzlato::Wallet#poll_intentions --- lib/peatio/bitzlato/wallet.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index af0dab1b7a..17c6e2a8ed 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -20,13 +20,9 @@ def configure(settings = {}) end.slice(:id) end - def generate_unique_id(id) - [self.class.name, @wallet[:uid], id].join('-') - end - def create_deposit_intention!(account_id: , amount: ) response = client - .post('/api/gate/v1/invoices', { + .post('/api/gate/v1/invoices/', { cryptocurrency: currency_id.to_s.upcase, amount: amount, comment: "Exchange service deposit for account #{account_id}" @@ -42,7 +38,14 @@ def create_deposit_intention!(account_id: , amount: ) def poll_intentions client - .get('/api/gate/v1/invoices/')['data'] + .get('/api/gate/v1/invoices/transactions/')['data'] + .map do |transaction| + { + id: transaction['invoiceId'], + amount: transaction['amount'].to_d, + cryptocurrency: transaction['cryptocurrency'] + } + end end private From dfa4615c52f731acf2879c2699f13f2a3bbb8f9f Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 15 Mar 2021 10:41:18 +0300 Subject: [PATCH 14/58] Add WalletService#poll_intentions --- app/services/wallet_service.rb | 28 +++++++++++++++++-- .../20210311145918_add_data_to_deposits.rb | 1 + spec/services/wallet_service_spec.rb | 1 - 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index a3f750c266..f5f07f03f7 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -15,14 +15,38 @@ def create_deposit_intention!(member, amount) Deposit.create!( type: Deposit.name, member: member, - data: intention.slice(:links), + data: intention.slice(:links, :expires_at), currency: currency, amount: intention[:amount], transfer_type: currency.type == 'fiat' ? 'fiat' : 'crypto', - tid: @adapter.generate_unique_id(intention[:id]) + intention_id: intention[:id] ) end + def poll_intentions + currency = @wallet.currencies.first + @adapter.configure(wallet: @wallet.to_wallet_api_settings, + currency: { id: currency.id }) + @adapter.poll_intentions.each do |intention| + deposit = Deposit.find_by(currency: currency, intention_id: intention[:id]) + if deposit.present? + if deposit.amount==intention[:amount] + deposit.with_lock do + if deposit.submitted? + deposit.accept! + else + Rails.logger.warn("Deposit #{deposit.id} has wrong status (#{deposit.aasm_state})") unless deposit.accepted? + end + end + else + Rails.logger.warn("Deposit and intention amounts are not equeal #{deposit.amount}<>#{intention[:amount]} with intention ##{intention[:id]} for #{currency.id} in wallet #{@wallet.name}") + end + else + Rails.logger.warn("No such deposit intention ##{intention[:id]} for #{currency.id} in wallet #{@wallet.name}") + end + end + end + def create_address!(uid, pa_details) @adapter.configure(wallet: @wallet.to_wallet_api_settings, currency: @wallet.currencies.first.to_blockchain_api_settings) diff --git a/db/migrate/20210311145918_add_data_to_deposits.rb b/db/migrate/20210311145918_add_data_to_deposits.rb index 05c14695b3..da4922e60a 100644 --- a/db/migrate/20210311145918_add_data_to_deposits.rb +++ b/db/migrate/20210311145918_add_data_to_deposits.rb @@ -1,5 +1,6 @@ class AddDataToDeposits < ActiveRecord::Migration[5.2] def change add_column :deposits, :data, :json + add_column :deposits, :intention_id, :bigint end end diff --git a/spec/services/wallet_service_spec.rb b/spec/services/wallet_service_spec.rb index 6142a6dedd..0988c54943 100644 --- a/spec/services/wallet_service_spec.rb +++ b/spec/services/wallet_service_spec.rb @@ -32,7 +32,6 @@ let(:intention) { { id: 123, amount: amount, links: { web: 'somelink', telegram: 'somelink' }, expires_at: 3.days.ago } } before do service.adapter.expects(:create_deposit_intention!).returns(intention) - service.adapter.expects(:generate_unique_id).returns('123') end subject do From 2ff81e7fa6209208265d9dd7dc70fa419f26c54f Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 15 Mar 2021 16:59:37 +0300 Subject: [PATCH 15/58] Add deposits polling job --- app/jobs/cron/deposits_polling.rb | 17 +++++++++++++++++ app/services/wallet_service.rb | 6 +++++- app/workers/daemons/cron_job.rb | 2 +- lib/daemons/daemons.god | 4 ++-- 4 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 app/jobs/cron/deposits_polling.rb diff --git a/app/jobs/cron/deposits_polling.rb b/app/jobs/cron/deposits_polling.rb new file mode 100644 index 0000000000..01f9e4d45b --- /dev/null +++ b/app/jobs/cron/deposits_polling.rb @@ -0,0 +1,17 @@ +# Run polling process for supported gateways +module Jobs + module Cron + module DepositsPolling + def self.process + Wallet.active.find_each do |w| + ws = WalletService.new(w) + ws.poll_intentions! if ws.support_polling? + rescue StandardError => e + report_exception_to_screen(e) + next + end + sleep 10 + end + end + end +end diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index f5f07f03f7..59ce6d7ba1 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -23,7 +23,11 @@ def create_deposit_intention!(member, amount) ) end - def poll_intentions + def support_polling? + @adapter.respond_to?(:poll_intentions) && @wallet.settings['allow_polling'] + end + + def poll_intentions! currency = @wallet.currencies.first @adapter.configure(wallet: @wallet.to_wallet_api_settings, currency: { id: currency.id }) diff --git a/app/workers/daemons/cron_job.rb b/app/workers/daemons/cron_job.rb index 67927477ad..387db4b876 100644 --- a/app/workers/daemons/cron_job.rb +++ b/app/workers/daemons/cron_job.rb @@ -6,7 +6,7 @@ module Workers module Daemons class CronJob < Base - JOBS = [Jobs::Cron::KLine, Jobs::Cron::Ticker, Jobs::Cron::StatsMemberPnl, Jobs::Cron::AML, Jobs::Cron::Refund, Jobs::Cron::WalletBalances].freeze + JOBS = [Jobs::Cron::KLine, Jobs::Cron::Ticker, Jobs::Cron::StatsMemberPnl, Jobs::Cron::AML, Jobs::Cron::Refund, Jobs::Cron::WalletBalances, Jobs::Cron::DepositsPolling].freeze def run JOBS.map { |j| Thread.new { process(j) } }.map(&:join) diff --git a/lib/daemons/daemons.god b/lib/daemons/daemons.god index 66756db718..3ff342b21b 100644 --- a/lib/daemons/daemons.god +++ b/lib/daemons/daemons.god @@ -96,9 +96,9 @@ daemon 'daemon:blockchain', script: 'daemons.rb', arguments: %w[ blockchain ] -daemon 'daemon:k', +daemon 'daemon:cron_job', script: 'daemons.rb', - arguments: %w[ k ] + arguments: %w[ cron_job ] daemon 'daemon:global_state', script: 'daemons.rb', From ea7a862d6e7d630c0ce68d3fb725bf5131e891a9 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Tue, 16 Mar 2021 11:34:45 +0300 Subject: [PATCH 16/58] Add transfer_links presentation for deposit --- app/api/v2/entities/deposit.rb | 11 +++++++++++ app/models/deposit.rb | 7 +++++++ app/services/wallet_service.rb | 1 - 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/app/api/v2/entities/deposit.rb b/app/api/v2/entities/deposit.rb index 034d47f9c8..48d23d90c1 100644 --- a/app/api/v2/entities/deposit.rb +++ b/app/api/v2/entities/deposit.rb @@ -73,6 +73,17 @@ class Deposit < Base } ) + expose( + :transfer_links, + documentation: { + type: String, + desc: 'Links to p2p page to make deposit trasnfer', + example: -> { + { telegram: 'https://t.me/BTC_STAGE_BOT?start=b_0f8c3db61f223ea9df072fd37e0b6315', web: 'https://s-www.lgk.one/p2p/?start=b_0f8c3db61f223ea9df072fd37e0b6315' } + } + }, + if: ->(deposit) { deposit.transfer_links.present? } + ) expose( :created_at, diff --git a/app/models/deposit.rb b/app/models/deposit.rb index 8e12b67560..30562300b2 100644 --- a/app/models/deposit.rb +++ b/app/models/deposit.rb @@ -123,6 +123,13 @@ def aml_check! true end + def transfer_links + # TODO rename data['links'] to transfer_links + # TODO rename data['expires_at'] to expires_at + # TODO Use txid instead of intention_id + data['links'] + end + def blockchain_api currency.blockchain_api end diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 59ce6d7ba1..4938ea3507 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -18,7 +18,6 @@ def create_deposit_intention!(member, amount) data: intention.slice(:links, :expires_at), currency: currency, amount: intention[:amount], - transfer_type: currency.type == 'fiat' ? 'fiat' : 'crypto', intention_id: intention[:id] ) end From a326860cc38da7aca4dd441a6c70b9249df7ab3b Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Wed, 17 Mar 2021 15:23:15 +0300 Subject: [PATCH 17/58] Add enable_intention to deposits API --- app/api/v2/entities/account.rb | 12 +++++++++++- app/api/v2/entities/deposit.rb | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/api/v2/entities/account.rb b/app/api/v2/entities/account.rb index 83e63def4a..e4ad27924d 100644 --- a/app/api/v2/entities/account.rb +++ b/app/api/v2/entities/account.rb @@ -34,7 +34,7 @@ class Account < Base expose( :deposit_address, - if: ->(account, _options) { account.currency.coin? }, + if: ->(account, _options) { account.currency.coin? && !Wallet.deposit_wallet(account.currency_id)&.settings&.fetch('enable_intention') }, using: API::V2::Entities::PaymentAddress, documentation: { desc: 'User deposit address', @@ -44,6 +44,16 @@ class Account < Base wallet = Wallet.deposit_wallet(account.currency_id) ::PaymentAddress.find_by(wallet: wallet, member: options[:current_user], remote: false) end + + expose( + :enable_intention, + documentation: { + desc: 'Show intention form instead of payment address generation', + type: JSON + } + ) do |account, options| + !!Wallet.deposit_wallet(account.currency_id)&.settings&.fetch('enable_intention') + end end end end diff --git a/app/api/v2/entities/deposit.rb b/app/api/v2/entities/deposit.rb index 48d23d90c1..7e06630aff 100644 --- a/app/api/v2/entities/deposit.rb +++ b/app/api/v2/entities/deposit.rb @@ -76,7 +76,7 @@ class Deposit < Base expose( :transfer_links, documentation: { - type: String, + type: JSON, desc: 'Links to p2p page to make deposit trasnfer', example: -> { { telegram: 'https://t.me/BTC_STAGE_BOT?start=b_0f8c3db61f223ea9df072fd37e0b6315', web: 'https://s-www.lgk.one/p2p/?start=b_0f8c3db61f223ea9df072fd37e0b6315' } From 75e562beb673b38f3c4e85e2e4975a61d1ebb8a9 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Wed, 17 Mar 2021 17:47:50 +0300 Subject: [PATCH 18/58] Add unique index for intention_id --- ...317141836_add_unique_index_to_intention_id_in_deposits.rb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 db/migrate/20210317141836_add_unique_index_to_intention_id_in_deposits.rb diff --git a/db/migrate/20210317141836_add_unique_index_to_intention_id_in_deposits.rb b/db/migrate/20210317141836_add_unique_index_to_intention_id_in_deposits.rb new file mode 100644 index 0000000000..8282241706 --- /dev/null +++ b/db/migrate/20210317141836_add_unique_index_to_intention_id_in_deposits.rb @@ -0,0 +1,5 @@ +class AddUniqueIndexToIntentionIdInDeposits < ActiveRecord::Migration[5.2] + def change + add_index :deposits, [:currency_id, :intention_id], unique: true, where: 'intention_id is not null' + end +end From 940ba938b8973c262fbe7448e1c89bd1dcb4934c Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Wed, 17 Mar 2021 17:48:19 +0300 Subject: [PATCH 19/58] Save remote_username when polling intentions --- app/services/wallet_service.rb | 1 + ...140626_add_remote_usernames_to_accounts.rb | 5 +++++ lib/peatio/bitzlato/wallet.rb | 1 + spec/services/wallet_service_spec.rb | 21 +++++++++++++++++++ 4 files changed, 28 insertions(+) create mode 100644 db/migrate/20210317140626_add_remote_usernames_to_accounts.rb diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 4938ea3507..461b366df9 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -37,6 +37,7 @@ def poll_intentions! deposit.with_lock do if deposit.submitted? deposit.accept! + deposit.account.update remote_usernames: (deposit.account.remote_usernames << intention[:username]).uniq else Rails.logger.warn("Deposit #{deposit.id} has wrong status (#{deposit.aasm_state})") unless deposit.accepted? end diff --git a/db/migrate/20210317140626_add_remote_usernames_to_accounts.rb b/db/migrate/20210317140626_add_remote_usernames_to_accounts.rb new file mode 100644 index 0000000000..b3daced2d9 --- /dev/null +++ b/db/migrate/20210317140626_add_remote_usernames_to_accounts.rb @@ -0,0 +1,5 @@ +class AddRemoteUsernamesToAccounts < ActiveRecord::Migration[5.2] + def change + add_column :accounts, :remote_usernames, :json, null: false, default: [] + end +end diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index 17c6e2a8ed..a08f1dbb5c 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -30,6 +30,7 @@ def create_deposit_intention!(account_id: , amount: ) { amount: response['amount'].to_d, + username: response['username'], id: response['id'], links: response['link'].symbolize_keys, expires_at: Time.at(response['expiryAt']/1000) diff --git a/spec/services/wallet_service_spec.rb b/spec/services/wallet_service_spec.rb index 0988c54943..dfa5ae3bcf 100644 --- a/spec/services/wallet_service_spec.rb +++ b/spec/services/wallet_service_spec.rb @@ -47,6 +47,27 @@ end end + context :poll_intentions! do + let(:member) { create(:member) } + let(:amount) { 1.12 } + let(:intention_id) { 12 } + let(:username) { 'ivan' } + + let(:intentions) { [ + { id: intention_id, amount: amount, username: username } + ] } + let!(:deposit) { create :deposit_btc, amount: amount, currency: wallet.currencies.first, intention_id: intention_id } + + before do + service.adapter.expects(:poll_intentions).returns(intentions) + end + + it 'accepts deposit' do + service.poll_intentions! + expect(deposit.reload).to be_accepted + end + end + context :create_address! do let(:account) { create(:member, :level_3, :barong).get_account(currency) } let(:blockchain_address) do From 4f9a477c3561252eeab0a8cf4242f0ca685f7347 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Mar 2021 10:09:17 +0300 Subject: [PATCH 20/58] Remove add_remote_usernames_to_accounts migration --- .../20210317140626_add_remote_usernames_to_accounts.rb | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 db/migrate/20210317140626_add_remote_usernames_to_accounts.rb diff --git a/db/migrate/20210317140626_add_remote_usernames_to_accounts.rb b/db/migrate/20210317140626_add_remote_usernames_to_accounts.rb deleted file mode 100644 index b3daced2d9..0000000000 --- a/db/migrate/20210317140626_add_remote_usernames_to_accounts.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AddRemoteUsernamesToAccounts < ActiveRecord::Migration[5.2] - def change - add_column :accounts, :remote_usernames, :json, null: false, default: [] - end -end From 9f87aabc14e2e459aaa38ac7f0633d166f2e0521 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Mar 2021 10:40:20 +0300 Subject: [PATCH 21/58] Save beneficiary where deposit accepted --- app/services/wallet_service.rb | 4 +++- spec/services/wallet_service_spec.rb | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 461b366df9..bf83eaec90 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -37,7 +37,9 @@ def poll_intentions! deposit.with_lock do if deposit.submitted? deposit.accept! - deposit.account.update remote_usernames: (deposit.account.remote_usernames << intention[:username]).uniq + deposit.account.member.beneficiaries + .create_with(data: { address: intention[:username] }) + .find_or_create_by!(name: intention[:username], currency: currency) if @wallet.settings['save_beneficiary'] else Rails.logger.warn("Deposit #{deposit.id} has wrong status (#{deposit.aasm_state})") unless deposit.accepted? end diff --git a/spec/services/wallet_service_spec.rb b/spec/services/wallet_service_spec.rb index dfa5ae3bcf..771a1d9bc0 100644 --- a/spec/services/wallet_service_spec.rb +++ b/spec/services/wallet_service_spec.rb @@ -52,6 +52,7 @@ let(:amount) { 1.12 } let(:intention_id) { 12 } let(:username) { 'ivan' } + let(:wallet) { create(:wallet, :fake_hot, settings: { 'save_beneficiary' => true } ) } let(:intentions) { [ { id: intention_id, amount: amount, username: username } @@ -66,6 +67,11 @@ service.poll_intentions! expect(deposit.reload).to be_accepted end + + it 'creates beneficiary' do + service.poll_intentions! + expect(deposit.account.member.beneficiaries.count).to eq(1) + end end context :create_address! do From 37b6ee5b45706ebde7e96f6e8d9b6440ad84d52a Mon Sep 17 00:00:00 2001 From: sixandfo Date: Thu, 18 Mar 2021 12:33:58 +0200 Subject: [PATCH 22/58] bump bitzlato plugin version --- Gemfile.plugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.plugin b/Gemfile.plugin index ec2936e0ea..2b380bbbd8 100644 --- a/Gemfile.plugin +++ b/Gemfile.plugin @@ -9,4 +9,4 @@ gem 'peatio-bitcoincash', '~> 2.6.1' gem 'peatio-ripple', '~> 2.6.1' gem 'peatio-bitgo', '~> 2.6.6' gem 'peatio-electrum', '~> 2.6.2' -gem 'bitzlato', '~> 0.1.2' +gem 'bitzlato', '~> 0.1.3' From ba6858339c9e5c336d3bb83cc2bfd7c7249b6a5c Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Mar 2021 15:27:26 +0300 Subject: [PATCH 23/58] Bump bitzlato gem to 0.1.3 --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index ed93b2c200..c0ab8fbe6d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -89,7 +89,7 @@ GEM better-faraday (1.0.8) activesupport (>= 4.0, < 6.0) faraday (~> 0.12) - bitzlato (0.1.2) + bitzlato (0.1.3) faraday (>= 0.17) json (~> 2.0) jwt (~> 2.3.0.dev) @@ -504,7 +504,7 @@ DEPENDENCIES annotate (~> 3.1.0) arel-is-blank (~> 1.0.0) better-faraday (~> 1.0.5) - bitzlato (~> 0.1.2) + bitzlato (~> 0.1.3) bootsnap (>= 1.1.0) bullet (~> 5.9) bump (~> 0.7) From 4a5e4fa6e6527d7dd76f29cd0646218460103c85 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Mar 2021 15:27:52 +0300 Subject: [PATCH 24/58] Fix: remove focus from deposits_spec --- spec/api/v2/account/deposits_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api/v2/account/deposits_spec.rb b/spec/api/v2/account/deposits_spec.rb index 932abd5769..d8f3ea57a1 100644 --- a/spec/api/v2/account/deposits_spec.rb +++ b/spec/api/v2/account/deposits_spec.rb @@ -20,7 +20,7 @@ expect(response.code).to eq '401' end - fit 'returns with auth token deposits' do + it 'returns with auth token deposits' do Wallet.any_instance.stubs(:gateway).returns(:bitzlato) Wallet.any_instance.stubs(:settings).returns({ key: {}, uid: :some_acount_id, uri: 'uri' }) Bitzlato::Wallet.any_instance.stubs(:create_deposit_intention!).returns({ amount: amount, id: :unique_intention_id, links: {}}) From 826eacc4f8aaef892f816a231425b5b605c83f0c Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Mar 2021 15:40:05 +0300 Subject: [PATCH 25/58] Use ENV to configure bitzlato client --- lib/peatio/bitzlato/wallet.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index a08f1dbb5c..14da818631 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -57,9 +57,9 @@ def currency_id def client @client ||= Bitzlato::Client - .new(home_url: @wallet.fetch(:uri), - key: @wallet.fetch(:key), - uid: @wallet.fetch(:uid), + .new(home_url: ENV.fetch('BITZLATO_API_URL', @wallet.fetch(:uri)), + key: ENV.fetch('BITZLATO_API_KEY', @wallet.fetch(:key)).yield_self { |key| key.is_a?(String) ? JSON.parse(key) : key }, + uid: ENV.fetch('BITZLATO_API_CLIENT_UID', @wallet.fetch(:uid)).to_i, logger: Rails.env.development?) end end From 51995b840e8a3170af7dc869410f584af70d061d Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Mar 2021 17:10:34 +0300 Subject: [PATCH 26/58] Bump bitzlato 0.1.4 --- Gemfile.lock | 4 ++-- Gemfile.plugin | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index c0ab8fbe6d..4caac1d84e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -89,7 +89,7 @@ GEM better-faraday (1.0.8) activesupport (>= 4.0, < 6.0) faraday (~> 0.12) - bitzlato (0.1.3) + bitzlato (0.1.4) faraday (>= 0.17) json (~> 2.0) jwt (~> 2.3.0.dev) @@ -504,7 +504,7 @@ DEPENDENCIES annotate (~> 3.1.0) arel-is-blank (~> 1.0.0) better-faraday (~> 1.0.5) - bitzlato (~> 0.1.3) + bitzlato (~> 0.1.4) bootsnap (>= 1.1.0) bullet (~> 5.9) bump (~> 0.7) diff --git a/Gemfile.plugin b/Gemfile.plugin index 2b380bbbd8..e465f9e82b 100644 --- a/Gemfile.plugin +++ b/Gemfile.plugin @@ -9,4 +9,4 @@ gem 'peatio-bitcoincash', '~> 2.6.1' gem 'peatio-ripple', '~> 2.6.1' gem 'peatio-bitgo', '~> 2.6.6' gem 'peatio-electrum', '~> 2.6.2' -gem 'bitzlato', '~> 0.1.3' +gem 'bitzlato', '~> 0.1.4' From 92cdccdc633cd2c518ea4a10a2a73e4b83db5f92 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Mar 2021 17:11:09 +0300 Subject: [PATCH 27/58] Add Bitzlato::Wallet.create_transaction! --- lib/peatio/bitzlato/wallet.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index 14da818631..0e13b19039 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -20,6 +20,24 @@ def configure(settings = {}) end.slice(:id) end + def create_transaction!(transaction, options = {}) + voucher = client.post( + '/api/p2p/vouchers/', + {'cryptocurrency': transaction.currency_id.upcase, 'amount': transaction.amount, 'method':'crypto','currency': 'USD'} + ) + + transaction.options = transaction.options.merge voucher: voucher + transaction.txout = voucher['deepLinkCode'] + transaction.hash = voucher['deepLinkCode'] + transaction + rescue Bitzlato::Client::Error => e + raise Peatio::Wallet::ClientError, e + end + + def load_balance! + 999_999_999 # Yeah! + end + def create_deposit_intention!(account_id: , amount: ) response = client .post('/api/gate/v1/invoices/', { From 59ea8a3b6906713a88208758176a29f8c6295506 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Mar 2021 17:25:30 +0300 Subject: [PATCH 28/58] Fix specs for Peatio::Bitzlato --- lib/peatio/bitzlato/wallet.rb | 2 +- spec/lib/peatio/bitzlato/wallet_spec.rb | 94 ++++++++++++++++++------- 2 files changed, 69 insertions(+), 27 deletions(-) diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index 0e13b19039..ff60c98d8b 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -26,7 +26,7 @@ def create_transaction!(transaction, options = {}) {'cryptocurrency': transaction.currency_id.upcase, 'amount': transaction.amount, 'method':'crypto','currency': 'USD'} ) - transaction.options = transaction.options.merge voucher: voucher + transaction.options = transaction.options.merge 'voucher' => voucher transaction.txout = voucher['deepLinkCode'] transaction.hash = voucher['deepLinkCode'] transaction diff --git a/spec/lib/peatio/bitzlato/wallet_spec.rb b/spec/lib/peatio/bitzlato/wallet_spec.rb index 85aadb9d5b..f863bf4c22 100644 --- a/spec/lib/peatio/bitzlato/wallet_spec.rb +++ b/spec/lib/peatio/bitzlato/wallet_spec.rb @@ -21,17 +21,24 @@ end end - context :create_deposit_intention! do + describe :requests do around do |example| WebMock.disable_net_connect! example.run WebMock.allow_net_connect! end + before do + wallet.configure(settings) + ENV['BITZLATO_API_KEY']=nil + ENV['BITZLATO_API_URL']=nil + ENV['BITZLATO_API_CLIENT_UID']=nil + end + let(:uri) { 'http://127.0.0.1:8000' } let(:key) { {"kty":"EC","alg":"ES256","crv":"P-256","x":"wwf6h_sZhv6TXAYz4XrdXZVpLo_uoNESbaEf_zEydus","y":"OL-0AqcTNoaCBVAEpDNsU1bpZA7eQ9CtGPZGmEEg5QI","d":"nDTvKjSPQ4UAPiBmJKXeF1MKhuhLtjJtW6hypstWolk"} - } + } let(:settings) do { @@ -40,35 +47,70 @@ } end - let(:response) do - { - "id"=>21, - "cryptocurrency"=>"BTC", - "amount"=>"1.1", - "comment"=>"gift from drew", - "link"=>{"telegram"=>"https://t.me/BTC_STAGE_BOT?start=b_9ac6b97e09ecbbfc0d365421f6b98a33", "web"=>"https://s-www.lgk.one/p2p/?start=b_9ac6b97e09ecbbfc0d365421f6b98a33"}, - "createdAt"=>1615444044115, - "expiryAt"=>1615530444115, - "completedAt"=>nil, - "status"=>"active" - } - end + context :create_transaction! do + let(:response) do + { + "deepLinkCode"=>"someHash", + "currency"=>{"code"=>"USD", "amount"=>"6965"}, + "cryptocurrency"=>{"code"=>"BTC", "amount"=>"0.12"}, + "createdAt"=>1616075809783, + "links"=>[ + {"type"=>"telegram bot @BTC_STAGE_BOT", "url"=>"https://telegram.me/BTC_STAGE_BOT?start=someHash"}, + {"type"=>"web exchange", "url"=>"https://s-www.lgk.one/p2p/?start=someHash"} + ], + "status"=>"active", + "cashedBy"=>nil, + "comment"=>nil + } + end - before do - wallet.configure(settings) + it 'show create withdrawal transaction' do + stub_request(:post, uri + '/api/p2p/vouchers/') + .with(body: {"cryptocurrency":"BTC","amount":123,"method":"crypto", 'currency': 'USD'}.to_json) + .to_return(body: response.to_json, headers: { 'Content-Type': 'application/json' }) + + + transaction = Peatio::Transaction.new(to_address: 1, + amount: 123, + currency_id: 'BTC', + options: { tid: 'tid' }) + + transaction = wallet.create_transaction!(transaction) + + expect(transaction).to be_a Peatio::Transaction + expect(transaction.txout).to be_present + expect(transaction.hash).to be_present + expect(transaction.options['voucher']).to be_present + end end - it 'should create an address' do - stub_request(:post, uri + '/api/gate/v1/invoices') - .with(body: {"cryptocurrency":"BTC","amount":123,"comment":"Exchange service deposit for account uid12312"}.to_json) - .to_return(body: response.to_json, headers: { 'Content-Type': 'application/json' }) + context :create_deposit_intention! do + let(:response) do + { + "id"=>21, + "cryptocurrency"=>"BTC", + "amount"=>"1.1", + "comment"=>"gift from drew", + "link"=>{"telegram"=>"https://t.me/BTC_STAGE_BOT?start=b_9ac6b97e09ecbbfc0d365421f6b98a33", "web"=>"https://s-www.lgk.one/p2p/?start=b_9ac6b97e09ecbbfc0d365421f6b98a33"}, + "createdAt"=>1615444044115, + "expiryAt"=>1615530444115, + "completedAt"=>nil, + "status"=>"active" + } + end + + it 'should create an invoice' do + stub_request(:post, uri + '/api/gate/v1/invoices/') + .with(body: {"cryptocurrency":"BTC","amount":123,"comment":"Exchange service deposit for account uid12312"}.to_json) + .to_return(body: response.to_json, headers: { 'Content-Type': 'application/json' }) - result = wallet.create_deposit_intention!(account_id: 'uid12312', amount: 123) + result = wallet.create_deposit_intention!(account_id: 'uid12312', amount: 123) - expect(result[:id]).to eq 21 - expect(result[:amount]).to eq 1.1 - expect(result[:links]).to be_a(Hash) - expect(result[:expires_at]).to be_a(Time) + expect(result[:id]).to eq 21 + expect(result[:amount]).to eq 1.1 + expect(result[:links]).to be_a(Hash) + expect(result[:expires_at]).to be_a(Time) + end end end end From 44e9ce2872e957295909549f864164a971d55509 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Mar 2021 18:01:07 +0300 Subject: [PATCH 29/58] Fix specs --- app/api/v2/entities/account.rb | 5 +++-- app/models/deposit.rb | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/api/v2/entities/account.rb b/app/api/v2/entities/account.rb index e4ad27924d..edb2ce8a4c 100644 --- a/app/api/v2/entities/account.rb +++ b/app/api/v2/entities/account.rb @@ -34,7 +34,7 @@ class Account < Base expose( :deposit_address, - if: ->(account, _options) { account.currency.coin? && !Wallet.deposit_wallet(account.currency_id)&.settings&.fetch('enable_intention') }, + if: ->(account, _options) { account.currency.coin? && !Wallet.deposit_wallet(account.currency_id)&.settings&.fetch('enable_intention', false) }, using: API::V2::Entities::PaymentAddress, documentation: { desc: 'User deposit address', @@ -47,12 +47,13 @@ class Account < Base expose( :enable_intention, + if: ->(account, _options) { Wallet.deposit_wallet(account.currency_id)&.settings&.fetch('enable_intention', false) }, documentation: { desc: 'Show intention form instead of payment address generation', type: JSON } ) do |account, options| - !!Wallet.deposit_wallet(account.currency_id)&.settings&.fetch('enable_intention') + true end end end diff --git a/app/models/deposit.rb b/app/models/deposit.rb index 30562300b2..94fd11ce07 100644 --- a/app/models/deposit.rb +++ b/app/models/deposit.rb @@ -127,7 +127,7 @@ def transfer_links # TODO rename data['links'] to transfer_links # TODO rename data['expires_at'] to expires_at # TODO Use txid instead of intention_id - data['links'] + data&.fetch 'links' end def blockchain_api From 127e82eaaea7571a47c48bbcbb0d4cea5848489c Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Mar 2021 18:01:38 +0300 Subject: [PATCH 30/58] Save links on withdraw by voucher --- app/services/wallet_service.rb | 9 +++++++-- lib/peatio/bitzlato/wallet.rb | 2 +- spec/lib/peatio/bitzlato/wallet_spec.rb | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index bf83eaec90..dca850f4f8 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -66,9 +66,14 @@ def build_withdrawal!(withdrawal) amount: withdrawal.amount, currency_id: withdrawal.currency_id, options: { tid: withdrawal.tid }) + transaction = @adapter.create_transaction!(transaction) - save_transaction(transaction.as_json.merge(from_address: @wallet.address), withdrawal) if transaction.present? - transaction + + withdrawal.with_lock do + save_transaction(transaction.as_json.merge(from_address: @wallet.address), withdrawal) if transaction.present? + withdrawal.update metadata: withdrawal.metadata.merge( 'links' => transaction.options['links'] ) if transaction.options.has_key? 'links' + transaction + end end def spread_deposit(deposit) diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index ff60c98d8b..645fac2a62 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -26,7 +26,7 @@ def create_transaction!(transaction, options = {}) {'cryptocurrency': transaction.currency_id.upcase, 'amount': transaction.amount, 'method':'crypto','currency': 'USD'} ) - transaction.options = transaction.options.merge 'voucher' => voucher + transaction.options = transaction.options.merge 'voucher' => voucher, 'links' => voucher['links'] transaction.txout = voucher['deepLinkCode'] transaction.hash = voucher['deepLinkCode'] transaction diff --git a/spec/lib/peatio/bitzlato/wallet_spec.rb b/spec/lib/peatio/bitzlato/wallet_spec.rb index f863bf4c22..454e39bf6b 100644 --- a/spec/lib/peatio/bitzlato/wallet_spec.rb +++ b/spec/lib/peatio/bitzlato/wallet_spec.rb @@ -81,6 +81,7 @@ expect(transaction.txout).to be_present expect(transaction.hash).to be_present expect(transaction.options['voucher']).to be_present + expect(transaction.options['links']).to be_present end end From 708bb2f633a8d9ad7f86afbd08d06d2a2fd692a7 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Mar 2021 21:38:13 +0300 Subject: [PATCH 31/58] Add specific ENV to specs --- spec/lib/peatio/bitzlato/wallet_spec.rb | 8 ++++++-- spec/spec_helper.rb | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/spec/lib/peatio/bitzlato/wallet_spec.rb b/spec/lib/peatio/bitzlato/wallet_spec.rb index 454e39bf6b..d7d71a21c2 100644 --- a/spec/lib/peatio/bitzlato/wallet_spec.rb +++ b/spec/lib/peatio/bitzlato/wallet_spec.rb @@ -81,7 +81,9 @@ expect(transaction.txout).to be_present expect(transaction.hash).to be_present expect(transaction.options['voucher']).to be_present - expect(transaction.options['links']).to be_present + expect(transaction.options['links']).to be_a(Array) + expect(transaction.options['links'].count).to eq(2) + expect(transaction.options['links'].first.keys).to eq(['title', 'url']) end end @@ -109,7 +111,9 @@ expect(result[:id]).to eq 21 expect(result[:amount]).to eq 1.1 - expect(result[:links]).to be_a(Hash) + expect(result[:links]).to be_a(Array) + expect(result[:links].count).to eq(2) + expect(result[:links].first.keys).to eq(['title', 'url']) expect(result[:expires_at]).to be_a(Time) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index d85aca4295..2998a4dd32 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -9,6 +9,10 @@ ENV['EVENT_API_JWT_PRIVATE_KEY'] ||= Base64.urlsafe_encode64(OpenSSL::PKey::RSA.generate(2048).to_pem) ENV['PEATIO_JWT_PRIVATE_KEY'] ||= Base64.urlsafe_encode64(OpenSSL::PKey::RSA.generate(2048).to_pem) ENV['WITHDRAW_ADMIN_APPROVE'] = 'true' +ENV['MINIMUM_MEMBER_LEVEL_FOR_DEPOSIT']='3' +ENV['MINIMUM_MEMBER_LEVEL_FOR_WITHDRAW']='3' +ENV['MINIMUM_MEMBER_LEVEL_FOR_TRADING']='3' +ENV['JWT_PUBLIC_KEY']=nil # We remove lib/peatio.rb from LOAD_PATH because of conflict with peatio gem. # lib/peatio.rb is added to LOAD_PATH later after requiring gems. From f231ec78e22e063a27d22ab2d03822ed2429ed6e Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Mar 2021 21:38:31 +0300 Subject: [PATCH 32/58] Add withdrawal support and specs --- app/api/v2/entities/deposit.rb | 7 +++++-- app/api/v2/entities/withdraw.rb | 17 +++++++++++++++++ app/models/deposit.rb | 2 +- app/services/wallet_service.rb | 2 +- lib/peatio/bitzlato/wallet.rb | 11 +++++++++-- 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/app/api/v2/entities/deposit.rb b/app/api/v2/entities/deposit.rb index 7e06630aff..3f48e86af0 100644 --- a/app/api/v2/entities/deposit.rb +++ b/app/api/v2/entities/deposit.rb @@ -77,9 +77,12 @@ class Deposit < Base :transfer_links, documentation: { type: JSON, - desc: 'Links to p2p page to make deposit trasnfer', + desc: 'Links to p2p page to make deposit transfer', example: -> { - { telegram: 'https://t.me/BTC_STAGE_BOT?start=b_0f8c3db61f223ea9df072fd37e0b6315', web: 'https://s-www.lgk.one/p2p/?start=b_0f8c3db61f223ea9df072fd37e0b6315' } + [ + { title: 'telegram', url: 'https://t.me/BTC_STAGE_BOT?start=b_0f8c3db61f223ea9df072fd37e0b6315' }, + { title: 'web', url: 'https://s-www.lgk.one/p2p/?start=b_0f8c3db61f223ea9df072fd37e0b6315' } + ] } }, if: ->(deposit) { deposit.transfer_links.present? } diff --git a/app/api/v2/entities/withdraw.rb b/app/api/v2/entities/withdraw.rb index 943eb2fb59..c7e016327f 100644 --- a/app/api/v2/entities/withdraw.rb +++ b/app/api/v2/entities/withdraw.rb @@ -117,6 +117,23 @@ class Withdraw < Base desc: 'The datetime when withdraw was completed' } ) + + expose( + :transfer_links, + if: ->(withdraw) { withdraw.metadata.has_key? 'links' }, + documentation: { + type: JSON, + desc: 'Links to confirm withdraw on external resource', + example: -> { + [ + { title: 'telegram', url: 'https://t.me/BTC_STAGE_BOT?start=b_0f8c3db61f223ea9df072fd37e0b6315' }, + { title: 'web', url: 'https://s-www.lgk.one/p2p/?start=b_0f8c3db61f223ea9df072fd37e0b6315' } + ] + } + } + ) do |withdraw| + withdraw.metadata['links'] + end end end end diff --git a/app/models/deposit.rb b/app/models/deposit.rb index 94fd11ce07..ec3d2a5f76 100644 --- a/app/models/deposit.rb +++ b/app/models/deposit.rb @@ -127,7 +127,7 @@ def transfer_links # TODO rename data['links'] to transfer_links # TODO rename data['expires_at'] to expires_at # TODO Use txid instead of intention_id - data&.fetch 'links' + data&.fetch 'links', [] end def blockchain_api diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index dca850f4f8..53a9937ef6 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -71,7 +71,7 @@ def build_withdrawal!(withdrawal) withdrawal.with_lock do save_transaction(transaction.as_json.merge(from_address: @wallet.address), withdrawal) if transaction.present? - withdrawal.update metadata: withdrawal.metadata.merge( 'links' => transaction.options['links'] ) if transaction.options.has_key? 'links' + withdrawal.update metadata: withdrawal.metadata.merge( 'links' => transaction.options['links'] ) if transaction.options&.has_key? 'links' transaction end end diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index 645fac2a62..f2b9ae9770 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -26,7 +26,13 @@ def create_transaction!(transaction, options = {}) {'cryptocurrency': transaction.currency_id.upcase, 'amount': transaction.amount, 'method':'crypto','currency': 'USD'} ) - transaction.options = transaction.options.merge 'voucher' => voucher, 'links' => voucher['links'] + transaction.options = transaction + .options + .merge( + 'voucher' => voucher, + 'links' => voucher['links'].map { |link| { 'title' => link['type'], 'url' => link['url'] } } + ) + transaction.txout = voucher['deepLinkCode'] transaction.hash = voucher['deepLinkCode'] transaction @@ -35,6 +41,7 @@ def create_transaction!(transaction, options = {}) end def load_balance! + # TODO fetch actual balance 999_999_999 # Yeah! end @@ -50,7 +57,7 @@ def create_deposit_intention!(account_id: , amount: ) amount: response['amount'].to_d, username: response['username'], id: response['id'], - links: response['link'].symbolize_keys, + links: response['link'].each_with_object([]) { |e, a| a << { 'title' => e.first, 'url' => e.second } }, expires_at: Time.at(response['expiryAt']/1000) } end From 9cee052e71fa8652adfad4638a770fe893cb64ab Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 18 Mar 2021 21:59:55 +0300 Subject: [PATCH 33/58] Poll withdraws --- app/jobs/cron/deposits_polling.rb | 8 ++++--- app/services/wallet_service.rb | 37 +++++++++++++++++++++++++++++++ lib/peatio/bitzlato/wallet.rb | 13 +++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/app/jobs/cron/deposits_polling.rb b/app/jobs/cron/deposits_polling.rb index 01f9e4d45b..cd7efc1c08 100644 --- a/app/jobs/cron/deposits_polling.rb +++ b/app/jobs/cron/deposits_polling.rb @@ -1,14 +1,16 @@ # Run polling process for supported gateways module Jobs module Cron + # TODO rename to transfer polling module DepositsPolling def self.process Wallet.active.find_each do |w| - ws = WalletService.new(w) - ws.poll_intentions! if ws.support_polling? + next unless ws.support_polling? + WalletService + .new(w) + .poll_transfers! rescue StandardError => e report_exception_to_screen(e) - next end sleep 10 end diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 53a9937ef6..452c818212 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -26,6 +26,43 @@ def support_polling? @adapter.respond_to?(:poll_intentions) && @wallet.settings['allow_polling'] end + def poll_transfers! + poll_intentions! + poll_withdraws! + end + + def poll_withdraws! + currency = @wallet.currencies.first + @adapter.configure(wallet: @wallet.to_wallet_api_settings, + currency: { id: currency.id }) + @adapter.poll_vouchers.each do |voucher| + withdraw = Withdraw.find_by(txid: voucher[:id], currency_id: voucher[:currency]) + if withdraw.present? + if withdraw.amount==voucher[:amount] + withdraw.with_lock do + case voucher[:status] + when 'cashed' + if withdraw.confirming? + Rails.logger.info("Withdraw #{withdraw.id} successed") + withdraw.success! + else + Rails.logger.warn("Withdraw #{withdraw.id} has wrong status (#{withdraw.aasm_state})") + end + when 'active' + # do nothing + else + Rails.logger.error("Voucher #{voucher[:id]} has unknown status (#{voucher[:status]})") + end + end + else + Rails.logger.error("Withdraw and intention amounts are not equeal #{withdraw.amount}<>#{voucher[:amount]} with voucher ##{voucher[:id]} for #{currency.id} in wallet #{@wallet.name}") + end + else + Rails.logger.warn("No such withdraw voucher ##{voucher[:id]} for #{currency.id} in wallet #{@wallet.name}") + end + end + end + def poll_intentions! currency = @wallet.currencies.first @adapter.configure(wallet: @wallet.to_wallet_api_settings, diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index f2b9ae9770..84d76dc486 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -74,6 +74,19 @@ def poll_intentions end end + def poll_vouchers + client + .get('/api/p2p/vouchers/')['data'] + .map do |voucher| + { + id: voucher['deepLinkCode'], + status: voucher['status'], + amount: voucher.dig('cryptocurrency', 'amount').to_d, + currency: voucher.dig('cryptocurrency', 'code').downcase + } + end + end + private def currency_id From 8f7dfc153a4cf0d9dabbff3667ad035de2f242c1 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 22 Mar 2021 09:14:46 +0300 Subject: [PATCH 34/58] Minor fix in deposits polling --- app/jobs/cron/deposits_polling.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/jobs/cron/deposits_polling.rb b/app/jobs/cron/deposits_polling.rb index cd7efc1c08..6bab89290e 100644 --- a/app/jobs/cron/deposits_polling.rb +++ b/app/jobs/cron/deposits_polling.rb @@ -5,10 +5,9 @@ module Cron module DepositsPolling def self.process Wallet.active.find_each do |w| + ws = WalletService .new(w) next unless ws.support_polling? - WalletService - .new(w) - .poll_transfers! + ws.poll_transfers! rescue StandardError => e report_exception_to_screen(e) end From 4c08060f95be6f7154c3cff552f7c1ac69d7a7dc Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 22 Mar 2021 09:31:56 +0300 Subject: [PATCH 35/58] Rename poll_intentions to poll_deposits --- app/jobs/cron/deposits_polling.rb | 18 ------------------ app/jobs/cron/transfers_polling.rb | 27 +++++++++++++++++++++++++++ app/services/wallet_service.rb | 13 ++++++------- app/workers/daemons/cron_job.rb | 10 +++++++++- lib/peatio/bitzlato/wallet.rb | 2 +- spec/services/wallet_service_spec.rb | 8 ++++---- 6 files changed, 47 insertions(+), 31 deletions(-) delete mode 100644 app/jobs/cron/deposits_polling.rb create mode 100644 app/jobs/cron/transfers_polling.rb diff --git a/app/jobs/cron/deposits_polling.rb b/app/jobs/cron/deposits_polling.rb deleted file mode 100644 index 6bab89290e..0000000000 --- a/app/jobs/cron/deposits_polling.rb +++ /dev/null @@ -1,18 +0,0 @@ -# Run polling process for supported gateways -module Jobs - module Cron - # TODO rename to transfer polling - module DepositsPolling - def self.process - Wallet.active.find_each do |w| - ws = WalletService .new(w) - next unless ws.support_polling? - ws.poll_transfers! - rescue StandardError => e - report_exception_to_screen(e) - end - sleep 10 - end - end - end -end diff --git a/app/jobs/cron/transfers_polling.rb b/app/jobs/cron/transfers_polling.rb new file mode 100644 index 0000000000..c40f5084fd --- /dev/null +++ b/app/jobs/cron/transfers_polling.rb @@ -0,0 +1,27 @@ +# Run polling process for supported gateways +module Jobs + module Cron + module TransfersPolling + def self.process + Wallet.active.find_each do |w| + ws = WalletService .new(w) + poll_deposits ws if ws.support_deposits_polling? + poll_withdraws ws if ws.support_withdraws_polling? + end + sleep 10 + end + + def self.poll_withdraws(ws) + ws.poll_withdraws! + rescue StandardError => e + report_exception_to_screen(e) + end + + def self.poll_deposits(ws) + ws.poll_deposits! + rescue StandardError => e + report_exception_to_screen(e) + end + end + end +end diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 452c818212..4649334dcc 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -22,13 +22,12 @@ def create_deposit_intention!(member, amount) ) end - def support_polling? - @adapter.respond_to?(:poll_intentions) && @wallet.settings['allow_polling'] + def support_deposits_polling? + @adapter.respond_to?(:poll_deposits) && @wallet.settings['allow_deposits_polling'] end - def poll_transfers! - poll_intentions! - poll_withdraws! + def support_withdraws_polling? + @adapter.respond_to?(:poll_withdraws) && @wallet.settings['allow_withdraws_polling'] end def poll_withdraws! @@ -63,11 +62,11 @@ def poll_withdraws! end end - def poll_intentions! + def poll_deposits! currency = @wallet.currencies.first @adapter.configure(wallet: @wallet.to_wallet_api_settings, currency: { id: currency.id }) - @adapter.poll_intentions.each do |intention| + @adapter.poll_deposits.each do |intention| deposit = Deposit.find_by(currency: currency, intention_id: intention[:id]) if deposit.present? if deposit.amount==intention[:amount] diff --git a/app/workers/daemons/cron_job.rb b/app/workers/daemons/cron_job.rb index 387db4b876..126b953402 100644 --- a/app/workers/daemons/cron_job.rb +++ b/app/workers/daemons/cron_job.rb @@ -6,7 +6,15 @@ module Workers module Daemons class CronJob < Base - JOBS = [Jobs::Cron::KLine, Jobs::Cron::Ticker, Jobs::Cron::StatsMemberPnl, Jobs::Cron::AML, Jobs::Cron::Refund, Jobs::Cron::WalletBalances, Jobs::Cron::DepositsPolling].freeze + JOBS = [ + Jobs::Cron::KLine, + Jobs::Cron::Ticker, + Jobs::Cron::StatsMemberPnl, + Jobs::Cron::AML, + Jobs::Cron::Refund, + Jobs::Cron::WalletBalances, + Jobs::Cron::TransfersPolling, + ].freeze def run JOBS.map { |j| Thread.new { process(j) } }.map(&:join) diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index 84d76dc486..fef30dcc7c 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -62,7 +62,7 @@ def create_deposit_intention!(account_id: , amount: ) } end - def poll_intentions + def poll_deposits client .get('/api/gate/v1/invoices/transactions/')['data'] .map do |transaction| diff --git a/spec/services/wallet_service_spec.rb b/spec/services/wallet_service_spec.rb index 771a1d9bc0..fc9969e892 100644 --- a/spec/services/wallet_service_spec.rb +++ b/spec/services/wallet_service_spec.rb @@ -47,7 +47,7 @@ end end - context :poll_intentions! do + context :poll_deposits! do let(:member) { create(:member) } let(:amount) { 1.12 } let(:intention_id) { 12 } @@ -60,16 +60,16 @@ let!(:deposit) { create :deposit_btc, amount: amount, currency: wallet.currencies.first, intention_id: intention_id } before do - service.adapter.expects(:poll_intentions).returns(intentions) + service.adapter.expects(:poll_deposits).returns(intentions) end it 'accepts deposit' do - service.poll_intentions! + service.poll_deposits! expect(deposit.reload).to be_accepted end it 'creates beneficiary' do - service.poll_intentions! + service.poll_deposits! expect(deposit.account.member.beneficiaries.count).to eq(1) end end From 33ee7ac90bdec50513c553476608750100ec5943 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 22 Mar 2021 10:11:20 +0300 Subject: [PATCH 36/58] Bump bitzlato 0.1.6 --- Gemfile.lock | 4 ++-- Gemfile.plugin | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4caac1d84e..2b9ffdf259 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -89,7 +89,7 @@ GEM better-faraday (1.0.8) activesupport (>= 4.0, < 6.0) faraday (~> 0.12) - bitzlato (0.1.4) + bitzlato (0.1.6) faraday (>= 0.17) json (~> 2.0) jwt (~> 2.3.0.dev) @@ -504,7 +504,7 @@ DEPENDENCIES annotate (~> 3.1.0) arel-is-blank (~> 1.0.0) better-faraday (~> 1.0.5) - bitzlato (~> 0.1.4) + bitzlato (~> 0.1.6) bootsnap (>= 1.1.0) bullet (~> 5.9) bump (~> 0.7) diff --git a/Gemfile.plugin b/Gemfile.plugin index e465f9e82b..022e9dacdd 100644 --- a/Gemfile.plugin +++ b/Gemfile.plugin @@ -9,4 +9,4 @@ gem 'peatio-bitcoincash', '~> 2.6.1' gem 'peatio-ripple', '~> 2.6.1' gem 'peatio-bitgo', '~> 2.6.6' gem 'peatio-electrum', '~> 2.6.2' -gem 'bitzlato', '~> 0.1.4' +gem 'bitzlato', '~> 0.1.6' From ee355ab3f337b52fbaa697ded790583c65f25157 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 22 Mar 2021 12:16:29 +0300 Subject: [PATCH 37/58] Add payments polling to Bitzlato::Wallet --- app/services/wallet_service.rb | 42 ++++---- lib/peatio/bitzlato/wallet.rb | 59 +++++++++-- spec/lib/peatio/bitzlato/wallet_spec.rb | 127 +++++++++++++++++++++++- 3 files changed, 192 insertions(+), 36 deletions(-) diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 4649334dcc..7f96bc0a00 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -34,31 +34,25 @@ def poll_withdraws! currency = @wallet.currencies.first @adapter.configure(wallet: @wallet.to_wallet_api_settings, currency: { id: currency.id }) - @adapter.poll_vouchers.each do |voucher| - withdraw = Withdraw.find_by(txid: voucher[:id], currency_id: voucher[:currency]) - if withdraw.present? - if withdraw.amount==voucher[:amount] - withdraw.with_lock do - case voucher[:status] - when 'cashed' - if withdraw.confirming? - Rails.logger.info("Withdraw #{withdraw.id} successed") - withdraw.success! - else - Rails.logger.warn("Withdraw #{withdraw.id} has wrong status (#{withdraw.aasm_state})") - end - when 'active' - # do nothing - else - Rails.logger.error("Voucher #{voucher[:id]} has unknown status (#{voucher[:status]})") - end - end - else - Rails.logger.error("Withdraw and intention amounts are not equeal #{withdraw.amount}<>#{voucher[:amount]} with voucher ##{voucher[:id]} for #{currency.id} in wallet #{@wallet.name}") - end - else - Rails.logger.warn("No such withdraw voucher ##{voucher[:id]} for #{currency.id} in wallet #{@wallet.name}") + + @adapter.poll_withdraws.each do |withdraw_info| + next unless withdraw_info[:is_done] + withdraw = Withdraw.find_by(txid: withdraw_info.id, currency_id: withdraw_info.currency) + if withdraw.nil? + Rails.logger.warn("No such withdraw withdraw_info ##{withdraw.id} for #{currency.id} in wallet #{@wallet.name}") + next + end + if withdraw.amount!=withdraw_info.amount + Rails.logger.error("Withdraw and intention amounts are not equeal #{withdraw.amount}<>#{withdraw_info.amount} with withdraw_info ##{withdraw_info.id} for #{currency.id} in wallet #{@wallet.name}") + next end + unless withdraw.confirming? + Rails.logger.warn("Withdraw #{withdraw.id} has wrong status (#{withdraw.aasm_state})") + next + end + + Rails.logger.info("Withdraw #{withdraw.id} successed") + withdraw.success! end end diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index fef30dcc7c..ced0d40d7b 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -1,5 +1,10 @@ +require 'digest' + module Bitzlato class Wallet < Peatio::Wallet::Abstract + class WithdrawInfo + attr_accessor :is_done, :id, :currency, :amount + end def initialize(features = {}) @features = features @settings = {} @@ -13,7 +18,7 @@ def configure(settings = {}) @wallet = @settings.fetch(:wallet) do raise Peatio::Wallet::MissingSettingError, :wallet - end.slice(:uri, :key, :uid) + end.slice(:uri, :key, :uid, :withdraw_polling_methods) @currency = @settings.fetch(:currency) do raise Peatio::Wallet::MissingSettingError, :currency @@ -74,21 +79,57 @@ def poll_deposits end end + def poll_withdraws + if @wallet[:withdraw_polling_methods].blank? + Rails.logger.error("No withdraw_polling_methods key in settings for bitzlato wallet") + return + end + + withdraws = [] + + @wallet[:withdraw_polling_methods].each do |method| + case method + when 'vouchers' + withdraws += poll_vouchers + when 'payments' + withdraws += poll_payments + else + Rails.logger.error("Unknown withdraw_polling_methods (#{method})") + next + end + end + + withdraws + end + + private + + def poll_payments + client + .get('/api/gate/v1/payments/list/') + .map do |payment| + WithdrawInfo.new.tap do |w| + w.id = Digest::MD5.hexdigest payment.slice('publicName', 'amount', 'cryptocurrency', 'date').values.map(&:to_s).sort.join + w.is_done = payment['status'] == 'done' + w.amount = payment['amount'].to_d + w.currency = payment['cryptocurrency'] + end + end + end + def poll_vouchers client .get('/api/p2p/vouchers/')['data'] .map do |voucher| - { - id: voucher['deepLinkCode'], - status: voucher['status'], - amount: voucher.dig('cryptocurrency', 'amount').to_d, - currency: voucher.dig('cryptocurrency', 'code').downcase - } + WithdrawInfo.new.tap do |w| + w.id = voucher['deepLinkCode'] + w.is_done = voucher['status'] == 'cashed' + w.amount = voucher.dig('cryptocurrency', 'amount').to_d + w.currency = voucher.dig('cryptocurrency', 'code').downcase + end end end - private - def currency_id @currency.fetch(:id) end diff --git a/spec/lib/peatio/bitzlato/wallet_spec.rb b/spec/lib/peatio/bitzlato/wallet_spec.rb index d7d71a21c2..af8b6ab93f 100644 --- a/spec/lib/peatio/bitzlato/wallet_spec.rb +++ b/spec/lib/peatio/bitzlato/wallet_spec.rb @@ -37,16 +37,137 @@ let(:uri) { 'http://127.0.0.1:8000' } let(:key) { - {"kty":"EC","alg":"ES256","crv":"P-256","x":"wwf6h_sZhv6TXAYz4XrdXZVpLo_uoNESbaEf_zEydus","y":"OL-0AqcTNoaCBVAEpDNsU1bpZA7eQ9CtGPZGmEEg5QI","d":"nDTvKjSPQ4UAPiBmJKXeF1MKhuhLtjJtW6hypstWolk"} + {"kty":"EC","alg":"ES256","crv":"P-256", + "x":"wwf6h_sZhv6TXAYz4XrdXZVpLo_uoNESbaEf_zEydus", + "y":"OL-0AqcTNoaCBVAEpDNsU1bpZA7eQ9CtGPZGmEEg5QI", + "d":"nDTvKjSPQ4UAPiBmJKXeF1MKhuhLtjJtW6hypstWolk"} } let(:settings) do { - wallet: { uri: uri, key: key, uid: 'merchant_uid' }, - currency: { id: :btc } + wallet: { uri: uri, key: key, uid: 'merchant_uid', withdraw_polling_methods: ['vouchers', 'payments'] }, + currency: { id: :btc }, } end + context :poll_payments do + let(:response) do + [ + { + "publicName": "dapi", + "links": nil, + "amount": 0.21, + "cryptocurrency": "BTC", + "type": "auto", + "status": "done", + "date": 1616396531426 + }, + { + "publicName": "dapi", + "links": nil, + "amount": 0.2, + "cryptocurrency": "BTC", + "type": "auto", + "status": "done", + "date": 1616396505639 + }, + { + "publicName": "dapi", + "links": nil, + "amount": 0.19, + "cryptocurrency": "BTC", + "type": "auto", + "status": "done", + "date": 1616396365270 + } + ] + end + + it do + stub_request(:get, "http://127.0.0.1:8000/api/gate/v1/payments/list/") + .to_return(body: response.to_json, headers: { 'Content-Type': 'application/json' }) + payments = wallet.send :poll_payments + expect(payments.count).to eq 3 + expect(payments.second.is_done).to be_truthy + end + end + + context :poll_vouchers do + let(:response) do + { + "total": 2, + "data": [ + { + "deepLinkCode": "c_c8e8f34d2fff9f5dbc222939feeefbe5", + "currency": { + "code": "USD", + "amount": "5385" + }, + "cryptocurrency": { + "code": "BTC", + "amount": "1" + }, + "createdAt": 1616127762606, + "links": [ + { + "type": "telegram bot @BTC_STAGE_BOT", + "url": "https://telegram.me/BTC_STAGE_BOT?start=c_c8e8f34d2fff9f5dbc222939feeefbe5" + }, + { + "type": "web exchange", + "url": "https://s-www.lgk.one/p2p/?start=c_c8e8f34d2fff9f5dbc222939feeefbe5" + } + ], + "status": "none", + "cashedBy": "EasySammieFrey" + }, + { + "deepLinkCode": "c_c8e8f34d2fff9f5dbc222939feeefbe5", + "currency": { + "code": "USD", + "amount": "5385" + }, + "cryptocurrency": { + "code": "BTC", + "amount": "0.0931216" + }, + "createdAt": 1616127762606, + "links": [ + { + "type": "telegram bot @BTC_STAGE_BOT", + "url": "https://telegram.me/BTC_STAGE_BOT?start=c_c8e8f34d2fff9f5dbc222939feeefbe5" + }, + { + "type": "web exchange", + "url": "https://s-www.lgk.one/p2p/?start=c_c8e8f34d2fff9f5dbc222939feeefbe5" + } + ], + "status": "cashed", + "cashedBy": "EasySammieFrey" + }, + ] } + end + + it do + stub_request(:get, "http://127.0.0.1:8000/api/p2p/vouchers/") + .to_return(body: response.to_json, headers: { 'Content-Type': 'application/json' }) + vouchers = wallet.send :poll_vouchers + expect(vouchers.count).to eq 2 + expect(vouchers.first.is_done).to be_falsey + expect(vouchers.second.is_done).to be_truthy + end + end + + context :poll_withdraws do + it do + wallet.expects(:poll_vouchers).returns [] + wallet.expects(:poll_payments).returns [] + withdraws = wallet.poll_withdraws + + expect(withdraws).to be_a Array + end + end + context :create_transaction! do let(:response) do { From cc339eac45ac67b2df7422fc33731a35b8c3f55c Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 22 Mar 2021 12:19:11 +0300 Subject: [PATCH 38/58] Fix minor in WalletService#build_withdrawal! --- app/services/wallet_service.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 7f96bc0a00..4f75aad1d1 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -100,10 +100,11 @@ def build_withdrawal!(withdrawal) transaction = @adapter.create_transaction!(transaction) withdrawal.with_lock do - save_transaction(transaction.as_json.merge(from_address: @wallet.address), withdrawal) if transaction.present? + save_transaction(transaction.as_json.merge(from_address: @wallet.address), withdrawal) withdrawal.update metadata: withdrawal.metadata.merge( 'links' => transaction.options['links'] ) if transaction.options&.has_key? 'links' - transaction - end + end if transaction.present? + + transaction end def spread_deposit(deposit) From 00990cfab38d5ff75bb4d27ba047564ff727e98e Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 22 Mar 2021 15:19:49 +0300 Subject: [PATCH 39/58] Add Bitzlato::Wallet#create_payment --- lib/peatio/bitzlato/wallet.rb | 44 +++++++-- spec/lib/peatio/bitzlato/wallet_spec.rb | 113 ++++++++++++++++-------- 2 files changed, 112 insertions(+), 45 deletions(-) diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index ced0d40d7b..aef10987fe 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -5,6 +5,10 @@ class Wallet < Peatio::Wallet::Abstract class WithdrawInfo attr_accessor :is_done, :id, :currency, :amount end + + WITHDRAW_METHODS = %w[voucher payment] + WITHDRAW_POLLING_METHODS = %w[vouchers payments] + def initialize(features = {}) @features = features @settings = {} @@ -18,7 +22,13 @@ def configure(settings = {}) @wallet = @settings.fetch(:wallet) do raise Peatio::Wallet::MissingSettingError, :wallet - end.slice(:uri, :key, :uid, :withdraw_polling_methods) + end.slice(:uri, :key, :uid) + + @withdraw_polling_methods = @settings.dig(:wallet, :withdraw_polling_methods) + raise Peatio::Wallet::MissingSettingError, 'wallet.withdraw_polling_methods' unless @withdraw_polling_methods.present? && (@withdraw_polling_methods - WITHDRAW_POLLING_METHODS).empty? + + @withdraw_method = @settings.dig(:wallet, :withdraw_method) + raise Peatio::Wallet::MissingSettingError, 'wallet.withdraw_method' unless WITHDRAW_METHODS.include? @withdraw_method @currency = @settings.fetch(:currency) do raise Peatio::Wallet::MissingSettingError, :currency @@ -26,9 +36,32 @@ def configure(settings = {}) end def create_transaction!(transaction, options = {}) + case @withdraw_method + when 'voucher' + create_voucher! transaction, options + when 'payment' + create_payment! transaction, options + else + raise Peatio::Wallet::ClientError, "Unknown withdraw_polling_method specified (#{@withdraw_method})" + end + end + + def create_payment!(transaction, options = {}) + client.post( + '/api/gate/v1/payments/create', + { client: transaction.to_address, cryptocurrency: transaction.currency_id.upcase, amount: transaction.amount, payedBefore: true } + ) + transaction.txout = 'unknown' + transaction.hash = 'unknown' + transaction + rescue Bitzlato::Client::Error => e + raise Peatio::Wallet::ClientError, e + end + + def create_voucher!(transaction, options = {}) voucher = client.post( '/api/p2p/vouchers/', - {'cryptocurrency': transaction.currency_id.upcase, 'amount': transaction.amount, 'method':'crypto','currency': 'USD'} + { cryptocurrency: transaction.currency_id.upcase, amount: transaction.amount, method: 'crypto', currency: 'USD'} ) transaction.options = transaction @@ -80,14 +113,9 @@ def poll_deposits end def poll_withdraws - if @wallet[:withdraw_polling_methods].blank? - Rails.logger.error("No withdraw_polling_methods key in settings for bitzlato wallet") - return - end - withdraws = [] - @wallet[:withdraw_polling_methods].each do |method| + @withdraw_polling_methods.each do |method| case method when 'vouchers' withdraws += poll_vouchers diff --git a/spec/lib/peatio/bitzlato/wallet_spec.rb b/spec/lib/peatio/bitzlato/wallet_spec.rb index af8b6ab93f..36b8adcc0f 100644 --- a/spec/lib/peatio/bitzlato/wallet_spec.rb +++ b/spec/lib/peatio/bitzlato/wallet_spec.rb @@ -1,25 +1,25 @@ describe Bitzlato::Wallet do let(:wallet) { Bitzlato::Wallet.new } - context :configure do - let(:settings) { { wallet: {}, currency: {} } } - it 'requires wallet' do - expect { wallet.configure(settings.except(:wallet)) }.to raise_error(Peatio::Wallet::MissingSettingError) + #context :configure do + #let(:settings) { { wallet: {}, currency: {} } } + #it 'requires wallet' do + #expect { wallet.configure(settings.except(:wallet)) }.to raise_error(Peatio::Wallet::MissingSettingError) - expect { wallet.configure(settings) }.to_not raise_error - end + #expect { wallet.configure(settings) }.to_not raise_error + #end - it 'requires currency' do - expect { wallet.configure(settings.except(:currency)) }.to raise_error(Peatio::Wallet::MissingSettingError) + #it 'requires currency' do + #expect { wallet.configure(settings.except(:currency)) }.to raise_error(Peatio::Wallet::MissingSettingError) - expect { wallet.configure(settings) }.to_not raise_error - end + #expect { wallet.configure(settings) }.to_not raise_error + #end - it 'sets settings attribute' do - wallet.configure(settings) - expect(wallet.settings).to eq(settings.slice(*Ethereum::Wallet::SUPPORTED_SETTINGS)) - end - end + #it 'sets settings attribute' do + #wallet.configure(settings) + #expect(wallet.settings).to eq(settings.slice(*Ethereum::Wallet::SUPPORTED_SETTINGS)) + #end + #end describe :requests do around do |example| @@ -43,9 +43,11 @@ "d":"nDTvKjSPQ4UAPiBmJKXeF1MKhuhLtjJtW6hypstWolk"} } + let(:withdraw_method) { 'voucher' } + let(:settings) do { - wallet: { uri: uri, key: key, uid: 'merchant_uid', withdraw_polling_methods: ['vouchers', 'payments'] }, + wallet: { uri: uri, key: key, uid: 'merchant_uid', withdraw_method: withdraw_method, withdraw_polling_methods: ['vouchers', 'payments'] }, currency: { id: :btc }, } end @@ -168,9 +170,50 @@ end end + context :create_transaction! do - let(:response) do - { + let(:source_transaction) { + Peatio::Transaction.new(to_address: 1, + amount: 123, + currency_id: 'BTC', + options: { tid: 'tid' }) + } + + context :voucher do + let(:withdraw_method) { 'voucher' } + it 'create withdrawal transaction' do + wallet.expects(:create_voucher!) + wallet.create_transaction!(source_transaction) + end + end + + context :payment do + let(:withdraw_method) { 'payment' } + it 'create withdrawal transaction' do + wallet.expects(:create_payment!) + wallet.create_transaction!(source_transaction) + end + end + + context :create_payment! do + let(:response) do + end + it 'show create withdrawal transaction' do + stub_request(:post, uri + '/api/gate/v1/payments/create') + .with( body: "{\"client\":1,\"cryptocurrency\":\"BTC\",\"amount\":123,\"payedBefore\":true}" ) + .to_return(body: response.to_json, headers: { 'Content-Type': 'application/json' }) + + transaction = wallet.create_payment!(source_transaction) + + expect(transaction).to be_a Peatio::Transaction + expect(transaction.txout).to be_present + expect(transaction.hash).to be_present + end + end + + context :create_voucher! do + let(:response) do + { "deepLinkCode"=>"someHash", "currency"=>{"code"=>"USD", "amount"=>"6965"}, "cryptocurrency"=>{"code"=>"BTC", "amount"=>"0.12"}, @@ -182,29 +225,25 @@ "status"=>"active", "cashedBy"=>nil, "comment"=>nil - } - end - - it 'show create withdrawal transaction' do - stub_request(:post, uri + '/api/p2p/vouchers/') - .with(body: {"cryptocurrency":"BTC","amount":123,"method":"crypto", 'currency': 'USD'}.to_json) - .to_return(body: response.to_json, headers: { 'Content-Type': 'application/json' }) + } + end + it 'create voucher' do + stub_request(:post, uri + '/api/p2p/vouchers/') + .with(body: {"cryptocurrency":"BTC","amount":123,"method":"crypto", 'currency': 'USD'}.to_json) + .to_return(body: response.to_json, headers: { 'Content-Type': 'application/json' }) - transaction = Peatio::Transaction.new(to_address: 1, - amount: 123, - currency_id: 'BTC', - options: { tid: 'tid' }) - transaction = wallet.create_transaction!(transaction) + transaction = wallet.create_voucher!(source_transaction) - expect(transaction).to be_a Peatio::Transaction - expect(transaction.txout).to be_present - expect(transaction.hash).to be_present - expect(transaction.options['voucher']).to be_present - expect(transaction.options['links']).to be_a(Array) - expect(transaction.options['links'].count).to eq(2) - expect(transaction.options['links'].first.keys).to eq(['title', 'url']) + expect(transaction).to be_a Peatio::Transaction + expect(transaction.txout).to be_present + expect(transaction.hash).to be_present + expect(transaction.options['voucher']).to be_present + expect(transaction.options['links']).to be_a(Array) + expect(transaction.options['links'].count).to eq(2) + expect(transaction.options['links'].first.keys).to eq(['title', 'url']) + end end end From 93a850f214cb93e04b97d76f0a6a430b75615a4b Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 22 Mar 2021 17:00:24 +0300 Subject: [PATCH 40/58] Integration fixes --- Gemfile.lock | 16 +++++++++++----- Gemfile.plugin | 2 +- app/api/v2/account/deposits.rb | 2 ++ app/services/wallet_service.rb | 4 ++-- lib/peatio/bitzlato/wallet.rb | 20 ++++++++++---------- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2b9ffdf259..7c55c2d813 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -14,6 +14,16 @@ GIT guard (~> 2.1) guard-compat (~> 1.1) +GIT + remote: https://github.com/finfex/bitzlato + revision: ab4466933259f9e4e4f385786fdad81df324ced1 + branch: main + specs: + bitzlato (0.1.7) + faraday (>= 0.17) + json (~> 2.0) + jwt (~> 2.3.0.dev) + GIT remote: https://github.com/jwt/ruby-jwt revision: 2cea14fdae439773fafc59640178e5cf7a0af8a4 @@ -89,10 +99,6 @@ GEM better-faraday (1.0.8) activesupport (>= 4.0, < 6.0) faraday (~> 0.12) - bitzlato (0.1.6) - faraday (>= 0.17) - json (~> 2.0) - jwt (~> 2.3.0.dev) bootsnap (1.7.3) msgpack (~> 1.0) builder (3.2.4) @@ -504,7 +510,7 @@ DEPENDENCIES annotate (~> 3.1.0) arel-is-blank (~> 1.0.0) better-faraday (~> 1.0.5) - bitzlato (~> 0.1.6) + bitzlato! bootsnap (>= 1.1.0) bullet (~> 5.9) bump (~> 0.7) diff --git a/Gemfile.plugin b/Gemfile.plugin index 022e9dacdd..aedc6f72bc 100644 --- a/Gemfile.plugin +++ b/Gemfile.plugin @@ -9,4 +9,4 @@ gem 'peatio-bitcoincash', '~> 2.6.1' gem 'peatio-ripple', '~> 2.6.1' gem 'peatio-bitgo', '~> 2.6.6' gem 'peatio-electrum', '~> 2.6.2' -gem 'bitzlato', '~> 0.1.6' +gem 'bitzlato', github: 'finfex/bitzlato', branch: 'main' diff --git a/app/api/v2/account/deposits.rb b/app/api/v2/account/deposits.rb index 0b085316a3..c1c38febd4 100644 --- a/app/api/v2/account/deposits.rb +++ b/app/api/v2/account/deposits.rb @@ -41,6 +41,8 @@ class Deposits < Grape::API .create_deposit_intention!(current_user, params[:amount]) present deposit, with: API::V2::Entities::Deposit + rescue => err + binding.pry end desc 'Get your deposits history.', diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 4f75aad1d1..882351092d 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -36,10 +36,10 @@ def poll_withdraws! currency: { id: currency.id }) @adapter.poll_withdraws.each do |withdraw_info| - next unless withdraw_info[:is_done] + next unless withdraw_info.is_done withdraw = Withdraw.find_by(txid: withdraw_info.id, currency_id: withdraw_info.currency) if withdraw.nil? - Rails.logger.warn("No such withdraw withdraw_info ##{withdraw.id} for #{currency.id} in wallet #{@wallet.name}") + Rails.logger.warn("No such withdraw withdraw_info ##{withdraw_info.id} for #{currency.id} in wallet #{@wallet.name}") next end if withdraw.amount!=withdraw_info.amount diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index aef10987fe..e9d07acf2e 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -24,19 +24,16 @@ def configure(settings = {}) raise Peatio::Wallet::MissingSettingError, :wallet end.slice(:uri, :key, :uid) - @withdraw_polling_methods = @settings.dig(:wallet, :withdraw_polling_methods) - raise Peatio::Wallet::MissingSettingError, 'wallet.withdraw_polling_methods' unless @withdraw_polling_methods.present? && (@withdraw_polling_methods - WITHDRAW_POLLING_METHODS).empty? - - @withdraw_method = @settings.dig(:wallet, :withdraw_method) - raise Peatio::Wallet::MissingSettingError, 'wallet.withdraw_method' unless WITHDRAW_METHODS.include? @withdraw_method - @currency = @settings.fetch(:currency) do raise Peatio::Wallet::MissingSettingError, :currency end.slice(:id) end def create_transaction!(transaction, options = {}) - case @withdraw_method + withdraw_method = @settings.dig(:wallet, :withdraw_method) + raise Peatio::Wallet::MissingSettingError, 'wallet.withdraw_method' unless WITHDRAW_METHODS.include? withdraw_method + + case withdraw_method when 'voucher' create_voucher! transaction, options when 'payment' @@ -115,7 +112,10 @@ def poll_deposits def poll_withdraws withdraws = [] - @withdraw_polling_methods.each do |method| + withdraw_polling_methods = @settings.dig(:wallet, :withdraw_polling_methods) + raise Peatio::Wallet::MissingSettingError, 'wallet.withdraw_polling_methods' unless withdraw_polling_methods.present? && (withdraw_polling_methods - WITHDRAW_POLLING_METHODS).empty? + + withdraw_polling_methods.each do |method| case method when 'vouchers' withdraws += poll_vouchers @@ -165,9 +165,9 @@ def currency_id def client @client ||= Bitzlato::Client .new(home_url: ENV.fetch('BITZLATO_API_URL', @wallet.fetch(:uri)), - key: ENV.fetch('BITZLATO_API_KEY', @wallet.fetch(:key)).yield_self { |key| key.is_a?(String) ? JSON.parse(key) : key }, + key: ENV.fetch('BITZLATO_API_KEY', @wallet.fetch(:key)).yield_self { |key| key.is_a?(String) ? JSON.parse(key) : key }.transform_keys(&:to_sym), uid: ENV.fetch('BITZLATO_API_CLIENT_UID', @wallet.fetch(:uid)).to_i, - logger: Rails.env.development?) + logger: ENV.true?('BITZLATO_API_LOGGER')) end end end From e705f2d82c783938c80790bc1c83f8440a4f3e17 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Tue, 23 Mar 2021 09:30:24 +0300 Subject: [PATCH 41/58] Save deposit username as beneficiary --- app/services/wallet_service.rb | 10 +++++++--- lib/peatio/bitzlato/wallet.rb | 3 ++- spec/services/wallet_service_spec.rb | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 882351092d..73b2e3411c 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -67,9 +67,13 @@ def poll_deposits! deposit.with_lock do if deposit.submitted? deposit.accept! - deposit.account.member.beneficiaries - .create_with(data: { address: intention[:username] }) - .find_or_create_by!(name: intention[:username], currency: currency) if @wallet.settings['save_beneficiary'] + + # Save beneficiary for future withdraws + if @wallet.settings['save_beneficiary'] && intention[:address].present? + deposit.account.member.beneficiaries + .create_with(data: { address: intention[:address] }, state: :active) + .find_or_create_by!(name: [@wallet.settings['beneficiary_prefix'], intention[:address]].compact.join(':'), currency: currency) + end else Rails.logger.warn("Deposit #{deposit.id} has wrong status (#{deposit.aasm_state})") unless deposit.accepted? end diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index e9d07acf2e..f7694aa533 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -102,9 +102,10 @@ def poll_deposits .get('/api/gate/v1/invoices/transactions/')['data'] .map do |transaction| { + address: transaction['username'], id: transaction['invoiceId'], amount: transaction['amount'].to_d, - cryptocurrency: transaction['cryptocurrency'] + currency: transaction['cryptocurrency'] } end end diff --git a/spec/services/wallet_service_spec.rb b/spec/services/wallet_service_spec.rb index fc9969e892..0c9fc72e8f 100644 --- a/spec/services/wallet_service_spec.rb +++ b/spec/services/wallet_service_spec.rb @@ -55,7 +55,7 @@ let(:wallet) { create(:wallet, :fake_hot, settings: { 'save_beneficiary' => true } ) } let(:intentions) { [ - { id: intention_id, amount: amount, username: username } + { id: intention_id, amount: amount, address: username } ] } let!(:deposit) { create :deposit_btc, amount: amount, currency: wallet.currencies.first, intention_id: intention_id } From 2f82046981c58b5413a22f689c2a0fe83f808a97 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Tue, 23 Mar 2021 09:46:48 +0300 Subject: [PATCH 42/58] Minor improvement beneficary saving from deposits --- app/services/wallet_service.rb | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 73b2e3411c..53485b7ff9 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -69,10 +69,15 @@ def poll_deposits! deposit.accept! # Save beneficiary for future withdraws - if @wallet.settings['save_beneficiary'] && intention[:address].present? - deposit.account.member.beneficiaries - .create_with(data: { address: intention[:address] }, state: :active) - .find_or_create_by!(name: [@wallet.settings['beneficiary_prefix'], intention[:address]].compact.join(':'), currency: currency) + if @wallet.settings['save_beneficiary'] + if intention[:address].present? + Rails.logger.info("Save #{intention[:address]} as beneficiary for #{deposit.account.id}") + deposit.account.member.beneficiaries + .create_with(data: { address: intention[:address] }, state: :active) + .find_or_create_by!(name: [@wallet.settings['beneficiary_prefix'], intention[:address]].compact.join(':'), currency: currency) + else + Rails.logger.warn("Deposit #{deposit.id} has no address to save to beneficiaries") + end end else Rails.logger.warn("Deposit #{deposit.id} has wrong status (#{deposit.aasm_state})") unless deposit.accepted? From ddcb9581c7ceabc5d9ffc2bd0114a8ef6ebfecdb Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Wed, 24 Mar 2021 08:04:18 +0300 Subject: [PATCH 43/58] Confirm withdraw if payment successful --- app/services/wallet_service.rb | 1 + lib/peatio/bitzlato/wallet.rb | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 53485b7ff9..5ff656766b 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -111,6 +111,7 @@ def build_withdrawal!(withdrawal) withdrawal.with_lock do save_transaction(transaction.as_json.merge(from_address: @wallet.address), withdrawal) withdrawal.update metadata: withdrawal.metadata.merge( 'links' => transaction.options['links'] ) if transaction.options&.has_key? 'links' + withdraw.success! if withdraw.confirming? && transaction.options&.fetch('completed', false) end if transaction.present? transaction diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index f7694aa533..0d15b10def 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -50,6 +50,7 @@ def create_payment!(transaction, options = {}) ) transaction.txout = 'unknown' transaction.hash = 'unknown' + transaction.options.merge( 'completed' => true ) transaction rescue Bitzlato::Client::Error => e raise Peatio::Wallet::ClientError, e @@ -61,11 +62,9 @@ def create_voucher!(transaction, options = {}) { cryptocurrency: transaction.currency_id.upcase, amount: transaction.amount, method: 'crypto', currency: 'USD'} ) - transaction.options = transaction - .options - .merge( - 'voucher' => voucher, - 'links' => voucher['links'].map { |link| { 'title' => link['type'], 'url' => link['url'] } } + transaction.options.merge!( + 'voucher' => voucher, + 'links' => voucher['links'].map { |link| { 'title' => link['type'], 'url' => link['url'] } } ) transaction.txout = voucher['deepLinkCode'] From 12806924d732d8fe3c06fd1d0023555ac0078c7a Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 29 Mar 2021 10:18:43 +0300 Subject: [PATCH 44/58] Fix: Use input currency for deposit intention --- app/api/v2/account/deposits.rb | 4 +--- app/services/wallet_service.rb | 3 +-- spec/services/wallet_service_spec.rb | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/app/api/v2/account/deposits.rb b/app/api/v2/account/deposits.rb index c1c38febd4..6d7efce63a 100644 --- a/app/api/v2/account/deposits.rb +++ b/app/api/v2/account/deposits.rb @@ -38,11 +38,9 @@ class Deposits < Grape::API deposit = WalletService .new(wallet) - .create_deposit_intention!(current_user, params[:amount]) + .create_deposit_intention!(current_user, currency, params[:amount]) present deposit, with: API::V2::Entities::Deposit - rescue => err - binding.pry end desc 'Get your deposits history.', diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 5ff656766b..d5b653bca1 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -6,8 +6,7 @@ def initialize(wallet) @adapter = Peatio::Wallet.registry[wallet.gateway.to_sym].new(wallet.settings.symbolize_keys) end - def create_deposit_intention!(member, amount) - currency = @wallet.currencies.first + def create_deposit_intention!(member, currency, amount) @adapter.configure(wallet: @wallet.to_wallet_api_settings, currency: { id: currency.id }) diff --git a/spec/services/wallet_service_spec.rb b/spec/services/wallet_service_spec.rb index 0c9fc72e8f..2cdaad5b89 100644 --- a/spec/services/wallet_service_spec.rb +++ b/spec/services/wallet_service_spec.rb @@ -35,7 +35,7 @@ end subject do - service.create_deposit_intention!(member, amount) + service.create_deposit_intention!(member, currency, amount) end it 'creates depotion intention' do From 93b8579cca1fab685095f957e9fe48cf9e0552b9 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 29 Mar 2021 18:34:10 +0300 Subject: [PATCH 45/58] Fix: poll deposits and withdraws for every currency in the wallet --- app/services/wallet_service.rb | 93 ++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index d5b653bca1..1717da29e8 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -30,63 +30,66 @@ def support_withdraws_polling? end def poll_withdraws! - currency = @wallet.currencies.first - @adapter.configure(wallet: @wallet.to_wallet_api_settings, - currency: { id: currency.id }) + @wallet.currencies.each do |currency| + @adapter.configure(wallet: @wallet.to_wallet_api_settings, + currency: { id: currency.id }) + + @adapter.poll_withdraws.each do |withdraw_info| + next unless withdraw_info.is_done + withdraw = Withdraw.find_by(txid: withdraw_info.id, currency_id: withdraw_info.currency) + if withdraw.nil? + Rails.logger.warn("No such withdraw withdraw_info ##{withdraw_info.id} for #{currency.id} in wallet #{@wallet.name}") + next + end + if withdraw.amount!=withdraw_info.amount + Rails.logger.error("Withdraw and intention amounts are not equeal #{withdraw.amount}<>#{withdraw_info.amount} with withdraw_info ##{withdraw_info.id} for #{currency.id} in wallet #{@wallet.name}") + next + end + unless withdraw.confirming? + Rails.logger.warn("Withdraw #{withdraw.id} has wrong status (#{withdraw.aasm_state})") + next + end - @adapter.poll_withdraws.each do |withdraw_info| - next unless withdraw_info.is_done - withdraw = Withdraw.find_by(txid: withdraw_info.id, currency_id: withdraw_info.currency) - if withdraw.nil? - Rails.logger.warn("No such withdraw withdraw_info ##{withdraw_info.id} for #{currency.id} in wallet #{@wallet.name}") - next + Rails.logger.info("Withdraw #{withdraw.id} successed") + withdraw.success! end - if withdraw.amount!=withdraw_info.amount - Rails.logger.error("Withdraw and intention amounts are not equeal #{withdraw.amount}<>#{withdraw_info.amount} with withdraw_info ##{withdraw_info.id} for #{currency.id} in wallet #{@wallet.name}") - next - end - unless withdraw.confirming? - Rails.logger.warn("Withdraw #{withdraw.id} has wrong status (#{withdraw.aasm_state})") - next - end - - Rails.logger.info("Withdraw #{withdraw.id} successed") - withdraw.success! end end def poll_deposits! - currency = @wallet.currencies.first - @adapter.configure(wallet: @wallet.to_wallet_api_settings, - currency: { id: currency.id }) - @adapter.poll_deposits.each do |intention| - deposit = Deposit.find_by(currency: currency, intention_id: intention[:id]) - if deposit.present? - if deposit.amount==intention[:amount] - deposit.with_lock do - if deposit.submitted? - deposit.accept! - - # Save beneficiary for future withdraws - if @wallet.settings['save_beneficiary'] - if intention[:address].present? - Rails.logger.info("Save #{intention[:address]} as beneficiary for #{deposit.account.id}") - deposit.account.member.beneficiaries - .create_with(data: { address: intention[:address] }, state: :active) - .find_or_create_by!(name: [@wallet.settings['beneficiary_prefix'], intention[:address]].compact.join(':'), currency: currency) - else - Rails.logger.warn("Deposit #{deposit.id} has no address to save to beneficiaries") + @wallet.currencies.each do |currency| + @adapter.configure(wallet: @wallet.to_wallet_api_settings, + currency: { id: currency.id }) + + @adapter.poll_deposits.each do |intention| + deposit = Deposit.find_by(currency: currency, intention_id: intention[:id]) + if deposit.present? + if deposit.amount==intention[:amount] + deposit.with_lock do + if deposit.submitted? + deposit.accept! + + # Save beneficiary for future withdraws + if @wallet.settings['save_beneficiary'] + if intention[:address].present? + Rails.logger.info("Save #{intention[:address]} as beneficiary for #{deposit.account.id}") + deposit.account.member.beneficiaries + .create_with(data: { address: intention[:address] }, state: :active) + .find_or_create_by!(name: [@wallet.settings['beneficiary_prefix'], intention[:address]].compact.join(':'), currency: currency) + else + Rails.logger.warn("Deposit #{deposit.id} has no address to save to beneficiaries") + end end + else + Rails.logger.warn("Deposit #{deposit.id} has wrong status (#{deposit.aasm_state})") unless deposit.accepted? end - else - Rails.logger.warn("Deposit #{deposit.id} has wrong status (#{deposit.aasm_state})") unless deposit.accepted? end + else + Rails.logger.warn("Deposit and intention amounts are not equeal #{deposit.amount}<>#{intention[:amount]} with intention ##{intention[:id]} for #{currency.id} in wallet #{@wallet.name}") end else - Rails.logger.warn("Deposit and intention amounts are not equeal #{deposit.amount}<>#{intention[:amount]} with intention ##{intention[:id]} for #{currency.id} in wallet #{@wallet.name}") + Rails.logger.warn("No such deposit intention ##{intention[:id]} for #{currency.id} in wallet #{@wallet.name}") end - else - Rails.logger.warn("No such deposit intention ##{intention[:id]} for #{currency.id} in wallet #{@wallet.name}") end end end From 4d71a474c9801372df12c81f95fd244d926ce478 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 29 Mar 2021 18:36:24 +0300 Subject: [PATCH 46/58] Improve: mimemagic to 0.3.10 --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 5f146a8571..53dabefab7 100644 --- a/README.md +++ b/README.md @@ -228,4 +228,3 @@ Peatio is released under the terms of the [MIT license](http://peatio.mit-licens [Peatio](http://en.wikipedia.org/wiki/Pixiu) (Chinese: 貔貅) is a Chinese mythical hybrid creature considered to be a very powerful protector to practitioners of Feng Shui. - From 6d64d853dc5a9b37ab25df59014cf07e8360c11b Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Mon, 29 Mar 2021 18:59:21 +0300 Subject: [PATCH 47/58] Improve: currencies seeding updates existed currency --- lib/tasks/seed.rake | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/tasks/seed.rake b/lib/tasks/seed.rake index 194b7c1904..d0f15efc16 100644 --- a/lib/tasks/seed.rake +++ b/lib/tasks/seed.rake @@ -18,8 +18,12 @@ namespace :seed do task currencies: :environment do Currency.transaction do YAML.load_file(Rails.root.join('config/seed/currencies.yml')).each do |hash| - next if Currency.exists?(id: hash.fetch('id')) - Currency.create!(hash) + currency = Currency.find_by(id: hash.fetch('id')) + if currency.present? + currency.update! hash + else + Currency.create!(hash) + end end end end From b280ee7b56f44fab4f56bfef40a9944248c2a198 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Wed, 31 Mar 2021 10:10:12 +0300 Subject: [PATCH 48/58] fix specs --- app/services/wallet_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 1717da29e8..9f985d22f2 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -113,7 +113,7 @@ def build_withdrawal!(withdrawal) withdrawal.with_lock do save_transaction(transaction.as_json.merge(from_address: @wallet.address), withdrawal) withdrawal.update metadata: withdrawal.metadata.merge( 'links' => transaction.options['links'] ) if transaction.options&.has_key? 'links' - withdraw.success! if withdraw.confirming? && transaction.options&.fetch('completed', false) + withdrawal.success! if withdrawal.confirming? && transaction.options&.fetch('completed', false) end if transaction.present? transaction From 8bca10f750b0b70e65687c64650cc61c342043f8 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 1 Apr 2021 18:13:14 +0300 Subject: [PATCH 49/58] Improvement: reseeding wallets updates its data --- lib/tasks/seed.rake | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/tasks/seed.rake b/lib/tasks/seed.rake index d0f15efc16..a70a07681f 100644 --- a/lib/tasks/seed.rake +++ b/lib/tasks/seed.rake @@ -93,11 +93,15 @@ namespace :seed do task wallets: :environment do Wallet.transaction do YAML.load_file(Rails.root.join('config/seed/wallets.yml')).each do |hash| - next if Wallet.exists?(name: hash.fetch('name')) if hash['currency_ids'].is_a?(String) hash['currency_ids'] = hash['currency_ids'].split(',') end - Wallet.create!(hash) + wallet = Wallet.find_by(name: hash.fetch('name')) + if wallet.present? + wallet.update! hash + else + Wallet.create!(hash) + end end end end From d1a986711208e4345b8817ed693bbb8a15c65b83 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 1 Apr 2021 18:14:00 +0300 Subject: [PATCH 50/58] Improvement: wallet validation doesn't raise for non blockchain wallets --- app/models/wallet.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/wallet.rb b/app/models/wallet.rb index 3fc5dc2c73..4e03fce26c 100644 --- a/app/models/wallet.rb +++ b/app/models/wallet.rb @@ -69,7 +69,7 @@ class Wallet < ApplicationRecord end before_validation do - next unless address? && blockchain.blockchain_api.try(:supports_cash_addr_format?) + next unless address? && blockchain.try(:blockchain_api).try(:supports_cash_addr_format?) self.address = CashAddr::Converter.to_cash_address(address) end From 0e3750382f6cdac827d0ce7fff21cfbaee204c32 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 1 Apr 2021 18:21:11 +0300 Subject: [PATCH 51/58] Temporary fix Bitzlato::Wallet --- lib/peatio/bitzlato/wallet.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index 0d15b10def..4d5bbe8a3f 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -48,8 +48,9 @@ def create_payment!(transaction, options = {}) '/api/gate/v1/payments/create', { client: transaction.to_address, cryptocurrency: transaction.currency_id.upcase, amount: transaction.amount, payedBefore: true } ) - transaction.txout = 'unknown' - transaction.hash = 'unknown' + transaction.txout = 'unknown' # TODO put payment_id + # Future txid + transaction.hash = Time.now.to_i.to_s # TODO put payment_id transaction.options.merge( 'completed' => true ) transaction rescue Bitzlato::Client::Error => e From 302cabf3f62b21921cf085107f29d9276afdc46d Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Tue, 13 Apr 2021 15:22:59 +0300 Subject: [PATCH 52/58] Improvement: Detailed error on order validation --- app/models/order.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/order.rb b/app/models/order.rb index 34a84f07ce..74a9d24182 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -176,7 +176,7 @@ def submit_order compute_locked end - raise ::Account::AccountError unless member_balance >= locked + raise ::Account::AccountError, "member_balance > locked = #{member_balance}>#{locked}" unless member_balance >= locked return trigger_third_party_creation unless market.engine.peatio_engine? From 72edb3d7297ebaa9801937f2a8ae09e3207bfbec Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Tue, 13 Apr 2021 15:23:24 +0300 Subject: [PATCH 53/58] Improvement: Direct withdraw confirmation --- app/services/wallet_service.rb | 2 +- lib/peatio/bitzlato/wallet.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 9f985d22f2..6800806300 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -113,7 +113,7 @@ def build_withdrawal!(withdrawal) withdrawal.with_lock do save_transaction(transaction.as_json.merge(from_address: @wallet.address), withdrawal) withdrawal.update metadata: withdrawal.metadata.merge( 'links' => transaction.options['links'] ) if transaction.options&.has_key? 'links' - withdrawal.success! if withdrawal.confirming? && transaction.options&.fetch('completed', false) + withdrawal.success! if withdrawal.confirming? && transaction.status == 'succeed' end if transaction.present? transaction diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index 4d5bbe8a3f..70ba12b99f 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -51,7 +51,7 @@ def create_payment!(transaction, options = {}) transaction.txout = 'unknown' # TODO put payment_id # Future txid transaction.hash = Time.now.to_i.to_s # TODO put payment_id - transaction.options.merge( 'completed' => true ) + transaction.status = 'succeed' transaction rescue Bitzlato::Client::Error => e raise Peatio::Wallet::ClientError, e From 0ad379135764d33edd3001fd81983b49c06bdb72 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Wed, 14 Apr 2021 13:25:44 +0300 Subject: [PATCH 54/58] Improvement: Save payment ID in bitzlato wallet --- Gemfile.lock | 4 ++-- lib/peatio/bitzlato/wallet.rb | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 7c55c2d813..71cd2be268 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -16,10 +16,10 @@ GIT GIT remote: https://github.com/finfex/bitzlato - revision: ab4466933259f9e4e4f385786fdad81df324ced1 + revision: 4481878a52c14d85ade8f58cdd598b2b8a9e193b branch: main specs: - bitzlato (0.1.7) + bitzlato (0.1.8) faraday (>= 0.17) json (~> 2.0) jwt (~> 2.3.0.dev) diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index 70ba12b99f..3e99671d25 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -44,13 +44,12 @@ def create_transaction!(transaction, options = {}) end def create_payment!(transaction, options = {}) - client.post( + response = client.post( '/api/gate/v1/payments/create', { client: transaction.to_address, cryptocurrency: transaction.currency_id.upcase, amount: transaction.amount, payedBefore: true } ) - transaction.txout = 'unknown' # TODO put payment_id - # Future txid - transaction.hash = Time.now.to_i.to_s # TODO put payment_id + payment_id = response['paymentId'] || raise("No payment ID in response") + transaction.hash = transaction.txout = [client.uid, payment_id] * ':' transaction.status = 'succeed' transaction rescue Bitzlato::Client::Error => e From d1bebbf2149098baccc22775751b11b1f772d298 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Wed, 14 Apr 2021 14:09:30 +0300 Subject: [PATCH 55/58] Improve: Withdraw polling --- app/services/wallet_service.rb | 5 +++-- lib/peatio/bitzlato/wallet.rb | 14 ++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/services/wallet_service.rb b/app/services/wallet_service.rb index 6800806300..b5cd924c07 100644 --- a/app/services/wallet_service.rb +++ b/app/services/wallet_service.rb @@ -36,7 +36,8 @@ def poll_withdraws! @adapter.poll_withdraws.each do |withdraw_info| next unless withdraw_info.is_done - withdraw = Withdraw.find_by(txid: withdraw_info.id, currency_id: withdraw_info.currency) + next if withdraw_info.withdraw_id.nil? + withdraw = Withdraw.find_by(id: withdraw_info.withdraw_id) if withdraw.nil? Rails.logger.warn("No such withdraw withdraw_info ##{withdraw_info.id} for #{currency.id} in wallet #{@wallet.name}") next @@ -106,7 +107,7 @@ def build_withdrawal!(withdrawal) transaction = Peatio::Transaction.new(to_address: withdrawal.rid, amount: withdrawal.amount, currency_id: withdrawal.currency_id, - options: { tid: withdrawal.tid }) + options: { tid: withdrawal.tid, withdrawal_id: withdrawal.id }) transaction = @adapter.create_transaction!(transaction) diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index 3e99671d25..7df8ece8f5 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -3,7 +3,7 @@ module Bitzlato class Wallet < Peatio::Wallet::Abstract class WithdrawInfo - attr_accessor :is_done, :id, :currency, :amount + attr_accessor :is_done, :withdraw_id, :currency, :amount end WITHDRAW_METHODS = %w[voucher payment] @@ -44,12 +44,14 @@ def create_transaction!(transaction, options = {}) end def create_payment!(transaction, options = {}) + key = transaction.options[:withdrawal_id] || raise("No withdrawal ID") response = client.post( '/api/gate/v1/payments/create', - { client: transaction.to_address, cryptocurrency: transaction.currency_id.upcase, amount: transaction.amount, payedBefore: true } + { clientProvidedId: key, client: transaction.to_address, cryptocurrency: transaction.currency_id.upcase, amount: transaction.amount, payedBefore: true } ) payment_id = response['paymentId'] || raise("No payment ID in response") - transaction.hash = transaction.txout = [client.uid, payment_id] * ':' + transaction.hash = transaction.txout = generate_transaction_id payment_id + transaction.options.merge! payment_id: payment_id transaction.status = 'succeed' transaction rescue Bitzlato::Client::Error => e @@ -137,7 +139,7 @@ def poll_payments .get('/api/gate/v1/payments/list/') .map do |payment| WithdrawInfo.new.tap do |w| - w.id = Digest::MD5.hexdigest payment.slice('publicName', 'amount', 'cryptocurrency', 'date').values.map(&:to_s).sort.join + w.withdraw_id = payment['clientProvidedId'] w.is_done = payment['status'] == 'done' w.amount = payment['amount'].to_d w.currency = payment['cryptocurrency'] @@ -162,6 +164,10 @@ def currency_id @currency.fetch(:id) end + def generate_transaction_id id + [client.uid, id] * ':' + end + def client @client ||= Bitzlato::Client .new(home_url: ENV.fetch('BITZLATO_API_URL', @wallet.fetch(:uri)), From 5950ba3bb129f592e3a07764516946f903a272f5 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Wed, 14 Apr 2021 14:48:02 +0300 Subject: [PATCH 56/58] Update bitzlato client --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 71cd2be268..58fe451d39 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -16,7 +16,7 @@ GIT GIT remote: https://github.com/finfex/bitzlato - revision: 4481878a52c14d85ade8f58cdd598b2b8a9e193b + revision: 53b9c814a0be82f7d39c36abc4b9f37770bff405 branch: main specs: bitzlato (0.1.8) From 5d711fbe1372932ad2d28cd6a02d9400b2ef741c Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Fri, 16 Apr 2021 15:52:28 +0300 Subject: [PATCH 57/58] Improvement: Change Deposit#intention_id to string --- ...10416125059_change_deposit_intention_type_to_string.rb | 5 +++++ lib/peatio/bitzlato/wallet.rb | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20210416125059_change_deposit_intention_type_to_string.rb diff --git a/db/migrate/20210416125059_change_deposit_intention_type_to_string.rb b/db/migrate/20210416125059_change_deposit_intention_type_to_string.rb new file mode 100644 index 0000000000..fd34877bf7 --- /dev/null +++ b/db/migrate/20210416125059_change_deposit_intention_type_to_string.rb @@ -0,0 +1,5 @@ +class ChangeDepositIntentionTypeToString < ActiveRecord::Migration[5.2] + def change + change_column :deposits, :intention_id, :string + end +end diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index 7df8ece8f5..fc11ec29f4 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -50,7 +50,7 @@ def create_payment!(transaction, options = {}) { clientProvidedId: key, client: transaction.to_address, cryptocurrency: transaction.currency_id.upcase, amount: transaction.amount, payedBefore: true } ) payment_id = response['paymentId'] || raise("No payment ID in response") - transaction.hash = transaction.txout = generate_transaction_id payment_id + transaction.hash = transaction.txout = generate_id payment_id transaction.options.merge! payment_id: payment_id transaction.status = 'succeed' transaction @@ -92,7 +92,7 @@ def create_deposit_intention!(account_id: , amount: ) { amount: response['amount'].to_d, username: response['username'], - id: response['id'], + id: generate_id(response['id']), links: response['link'].each_with_object([]) { |e, a| a << { 'title' => e.first, 'url' => e.second } }, expires_at: Time.at(response['expiryAt']/1000) } @@ -104,7 +104,7 @@ def poll_deposits .map do |transaction| { address: transaction['username'], - id: transaction['invoiceId'], + id: generate_id(transaction['invoiceId']), amount: transaction['amount'].to_d, currency: transaction['cryptocurrency'] } @@ -164,7 +164,7 @@ def currency_id @currency.fetch(:id) end - def generate_transaction_id id + def generate_id id [client.uid, id] * ':' end From d7460bb6c3a943ebde8eb4ffcd1dfcafcc89fc40 Mon Sep 17 00:00:00 2001 From: Danil Pismenny Date: Thu, 22 Apr 2021 12:32:55 +0300 Subject: [PATCH 58/58] fix specs --- lib/peatio/bitzlato/wallet.rb | 2 +- spec/lib/peatio/bitzlato/wallet_spec.rb | 29 ++++--------------------- 2 files changed, 5 insertions(+), 26 deletions(-) diff --git a/lib/peatio/bitzlato/wallet.rb b/lib/peatio/bitzlato/wallet.rb index fc11ec29f4..4bcd9a2964 100644 --- a/lib/peatio/bitzlato/wallet.rb +++ b/lib/peatio/bitzlato/wallet.rb @@ -152,7 +152,7 @@ def poll_vouchers .get('/api/p2p/vouchers/')['data'] .map do |voucher| WithdrawInfo.new.tap do |w| - w.id = voucher['deepLinkCode'] + w.withdraw_id = voucher['deepLinkCode'] w.is_done = voucher['status'] == 'cashed' w.amount = voucher.dig('cryptocurrency', 'amount').to_d w.currency = voucher.dig('cryptocurrency', 'code').downcase diff --git a/spec/lib/peatio/bitzlato/wallet_spec.rb b/spec/lib/peatio/bitzlato/wallet_spec.rb index 36b8adcc0f..748be3b27c 100644 --- a/spec/lib/peatio/bitzlato/wallet_spec.rb +++ b/spec/lib/peatio/bitzlato/wallet_spec.rb @@ -1,26 +1,6 @@ describe Bitzlato::Wallet do let(:wallet) { Bitzlato::Wallet.new } - #context :configure do - #let(:settings) { { wallet: {}, currency: {} } } - #it 'requires wallet' do - #expect { wallet.configure(settings.except(:wallet)) }.to raise_error(Peatio::Wallet::MissingSettingError) - - #expect { wallet.configure(settings) }.to_not raise_error - #end - - #it 'requires currency' do - #expect { wallet.configure(settings.except(:currency)) }.to raise_error(Peatio::Wallet::MissingSettingError) - - #expect { wallet.configure(settings) }.to_not raise_error - #end - - #it 'sets settings attribute' do - #wallet.configure(settings) - #expect(wallet.settings).to eq(settings.slice(*Ethereum::Wallet::SUPPORTED_SETTINGS)) - #end - #end - describe :requests do around do |example| WebMock.disable_net_connect! @@ -176,7 +156,7 @@ Peatio::Transaction.new(to_address: 1, amount: 123, currency_id: 'BTC', - options: { tid: 'tid' }) + options: { withdrawal_id: 12, tid: 'tid' }) } context :voucher do @@ -196,11 +176,10 @@ end context :create_payment! do - let(:response) do - end + let(:response) { { paymentId: 12 }} it 'show create withdrawal transaction' do stub_request(:post, uri + '/api/gate/v1/payments/create') - .with( body: "{\"client\":1,\"cryptocurrency\":\"BTC\",\"amount\":123,\"payedBefore\":true}" ) + .with( body: "{\"clientProvidedId\":12,\"client\":1,\"cryptocurrency\":\"BTC\",\"amount\":123,\"payedBefore\":true}" ) .to_return(body: response.to_json, headers: { 'Content-Type': 'application/json' }) transaction = wallet.create_payment!(source_transaction) @@ -269,7 +248,7 @@ result = wallet.create_deposit_intention!(account_id: 'uid12312', amount: 123) - expect(result[:id]).to eq 21 + expect(result[:id]).to eq '0:21' expect(result[:amount]).to eq 1.1 expect(result[:links]).to be_a(Array) expect(result[:links].count).to eq(2)