peatio-nem2 1.0.47

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fc47ec6d9091eb1b690f0f3144deafe94bc99a09a6d2d15c6cbabbff80105853
4
+ data.tar.gz: 34197bc743c33388a1ba81bcd75b5f385aa74de5b68c6bb671759bf6dd566111
5
+ SHA512:
6
+ metadata.gz: '080a808583b7ef8247538a5d285aa151b3c790d1a88b525d1c93ba78e249e48104f274e720bfac064c051d8089fa0b9d280c0bfecd8b1ffb6365bc3973b90330'
7
+ data.tar.gz: 64b92b4715562cd843c748f41c82a3c181cb4a84ffe034c667a9dcc0d563948174259695426e13386bcac4a3beb0fd91f669b6d38e7b6cbc474a3a1c29f80cf5
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ Gemfile.lock
2
+ .rspec_status
3
+ pkg/*
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,15 @@
1
+ image: ruby-2.6.9
2
+
3
+ # Cache gems in between builds
4
+ cache:
5
+ paths:
6
+ - vendor/ruby
7
+
8
+ before_script:
9
+ - ruby -v # Print out ruby version for debugging
10
+ - bundle config set path 'vendor' # Install dependencies into ./vendor/ruby
11
+ - bundle install -j $(nproc)
12
+
13
+ rspec:
14
+ script:
15
+ - rspec spec
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rspec_status ADDED
@@ -0,0 +1,10 @@
1
+ example_id | status | run_time |
2
+ --------------------------------------- | ------ | --------------- |
3
+ ./spec/peatio/nem/client_spec.rb[1:1:1] | passed | 0.00199 seconds |
4
+ ./spec/peatio/nem/client_spec.rb[1:2:1] | passed | 0.0054 seconds |
5
+ ./spec/peatio/nem/client_spec.rb[1:3:1] | passed | 0.05286 seconds |
6
+ ./spec/peatio/nem/client_spec.rb[1:3:2] | passed | 0.00794 seconds |
7
+ ./spec/peatio/nem/wallet_spec.rb[1:1:1] | passed | 0.0002 seconds |
8
+ ./spec/peatio/nem/wallet_spec.rb[1:1:2] | passed | 0.00016 seconds |
9
+ ./spec/peatio/nem/wallet_spec.rb[1:1:3] | passed | 0.00086 seconds |
10
+ ./spec/peatio/nem2_spec.rb[1:1] | passed | 0.00136 seconds |
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in peatio-nem2.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Emiliano
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # Peatio::Nem2
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/peatio/nem2`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'peatio-nem2'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install peatio-nem2
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Development
26
+
27
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
28
+
29
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
30
+
31
+ ## Contributing
32
+
33
+ Bug reports and pull requests are welcome on GitHub at https://git.rewards4earth.com/rewards4earth/peatio-nem2.
34
+
35
+ ## License
36
+
37
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "peatio/nem2"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,10 @@
1
+ - key: nem-testnet
2
+ name: Nem Testnet
3
+ client: nem # API client name.
4
+ server: http://127.0.0.1:7890 # Public Nem node endpoint.
5
+ height: 3487157 # Initial block number from which sync will be started.
6
+ min_confirmations: 6 # Minimal confirmations needed for withdraw and deposit confirmation.
7
+ explorer:
8
+ address: https://explorer.nemtool.com/#/s_account?account={address}
9
+ transaction: https://explorer.nemtool.com/#/s_tx?hash={txid}
10
+ status: active
@@ -0,0 +1,18 @@
1
+ - id: erth
2
+ name: ErthPoint
3
+ blockchain_key: nem-testnet
4
+ symbol: 'Ł'
5
+ type: coin
6
+ precision: 8
7
+ base_factor: 100_000_000
8
+ enabled: true
9
+ # Deposits with less amount are skipped during blockchain synchronization.
10
+ # We advise to set value 10 times bigger than the network fee to prevent losses.
11
+ min_deposit_amount: 0.0001
12
+ min_collection_amount: 0.0001
13
+ withdraw_limit_24h: 0.5
14
+ withdraw_limit_72h: 1.2
15
+ deposit_fee: 0
16
+ withdraw_fee: 0
17
+ position: 1
18
+ options: {}
@@ -0,0 +1,57 @@
1
+
2
+ - name: Nem Deposit Wallet
3
+ blockchain_key: nem-testnet
4
+ currency_id: erth
5
+ # Address where deposits will be collected to.
6
+ address: '0x2b9fBC10EbAeEc28a8Fc10069C0BC29E45eBEB9C' # IMPORTANT: Always wrap this value in quotes!
7
+ kind: deposit # Wallet kind (deposit, hot, warm, cold or fee).
8
+ nsig: 1 # Number of signatures required for performing withdraw.
9
+ max_balance: 0.0
10
+ status: active
11
+ gateway: nem # Gateway client name.
12
+ settings:
13
+ #
14
+ # Nem gateway client settings.
15
+ uri: http://127.0.0.1:7890
16
+ secret: 'changeme'
17
+ testnet: true
18
+ access_token: 'v2x659261647b540ee3acda5c50ae4e878we323474eea5cbff9b9615139629'
19
+ wallet_id: '5e5388ad80334347ceb3540c741d'
20
+
21
+ - name: Nem Hot Wallet
22
+ blockchain_key: nem-testnet
23
+ currency_id: erth
24
+ # Address where deposits will be collected to.
25
+ address: '0x270704935783087a01c7a28d8f2d8f01670c8050' # IMPORTANT: Always wrap this value in quotes!
26
+ kind: hot # Wallet kind (deposit, hot, warm, cold or fee).
27
+ nsig: 1 # Number of signatures required for performing withdraw.
28
+ max_balance: 100.0
29
+ status: active
30
+ gateway: nem # Gateway client name.
31
+ settings:
32
+ #
33
+ # Nem gateway client settings.
34
+ uri: http://127.0.0.1:7890
35
+ secret: 'test'
36
+ testnet: true
37
+ access_token: 'v2x659261647b540ee3acda5c50ae4e878we323474eea5cbff9b9615139629'
38
+ wallet_id: '5e5388ad80334347ceb3540c741d'
39
+
40
+ - name: Nem Warm Wallet
41
+ blockchain_key: nem-testnet
42
+ currency_id: erth
43
+ # Address where deposits will be collected to.
44
+ address: '0x2b9fBC10EbAeEc28a8Fc10069C0BC29E45eBEB9C' # IMPORTANT: Always wrap this value in quotes!
45
+ kind: warm # Wallet kind (deposit, hot, warm, cold or fee).
46
+ nsig: 1 # Number of signatures required for performing withdraw.
47
+ max_balance: 1000.0
48
+ status: active
49
+ gateway: nem # Gateway client name.
50
+ settings:
51
+ #
52
+ # Nem gateway client settings.
53
+ uri: http://127.0.0.1:7890
54
+ secret: 'test'
55
+ testnet: true
56
+ access_token: 'v2x659261647b540ee3acda5c50ae4e878we323474eea5cbff9b9615139629'
57
+ wallet_id: '5e5388ad80334347ceb3540c741d'
@@ -0,0 +1,20 @@
1
+ module Peatio
2
+ module Nem2
3
+ # TODO: Processing of unconfirmed transactions from mempool isn't supported now.
4
+ class Blockchain < Peatio::Blockchain::Abstract
5
+
6
+ DEFAULT_FEATURES = {case_sensitive: true, cash_addr_format: false}.freeze
7
+
8
+ def initialize(custom_features = {})
9
+ @features = DEFAULT_FEATURES.merge(custom_features).slice(*SUPPORTED_FEATURES)
10
+ @settings = {}
11
+ end
12
+
13
+ def configure(settings = {})
14
+ # Clean client state during configure.
15
+ @client = nil
16
+ @settings.merge!(settings.slice(*SUPPORTED_SETTINGS))
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,52 @@
1
+ require 'faraday'
2
+ require 'better-faraday'
3
+
4
+ module Peatio
5
+ module Nem2
6
+ class Client
7
+ Error = Class.new(StandardError)
8
+ ConnectionError = Class.new(Error)
9
+
10
+ class ResponseError < Error
11
+ def initialize(msg)
12
+ super "#{msg}"
13
+ end
14
+ end
15
+
16
+ def initialize(endpoint)
17
+ @endpoint = URI.parse(endpoint)
18
+ end
19
+
20
+ def rest_api(verb, path, data = nil)
21
+ args = [@endpoint.to_s + path]
22
+
23
+ if data
24
+ if %i[post put patch].include?(verb)
25
+ args << data.compact.to_json
26
+ args << { 'Content-Type' => 'application/json' }
27
+ else
28
+ args << data.compact
29
+ args << {}
30
+ end
31
+ else
32
+ args << nil
33
+ args << {}
34
+ end
35
+
36
+ args.last['Accept'] = 'application/json'
37
+
38
+ response = Faraday.send(verb, *args)
39
+ response.assert_success!
40
+ response = JSON.parse(response.body)
41
+ response['error'].tap { |error| raise ResponseError.new(error) if error }
42
+ response
43
+ rescue Faraday::Error => e
44
+ if e.is_a?(Faraday::ConnectionFailed) || e.is_a?(Faraday::TimeoutError)
45
+ raise ConnectionError, e
46
+ else
47
+ raise ConnectionError, JSON.parse(e.response.body)['message']
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,42 @@
1
+ module Peatio
2
+ module Nem2
3
+ module Hooks
4
+ BLOCKCHAIN_VERSION_REQUIREMENT = "~> 1.0.0"
5
+ WALLET_VERSION_REQUIREMENT = "~> 1.0.0"
6
+
7
+ class << self
8
+ def check_compatibility
9
+ unless Gem::Requirement.new(BLOCKCHAIN_VERSION_REQUIREMENT)
10
+ .satisfied_by?(Gem::Version.new(Peatio::Blockchain::VERSION))
11
+ [
12
+ "Nem blockchain version requirement was not satisfied by Peatio::Blockchain.",
13
+ "Nem blockchain requires #{BLOCKCHAIN_VERSION_REQUIREMENT}.",
14
+ "Peatio::Blockchain version is #{Peatio::Blockchain::VERSION}"
15
+ ].join('\n').tap { |s| Kernel.abort s }
16
+ end
17
+
18
+ unless Gem::Requirement.new(WALLET_VERSION_REQUIREMENT)
19
+ .satisfied_by?(Gem::Version.new(Peatio::Wallet::VERSION))
20
+ [
21
+ "Nem wallet version requirement was not satisfied by Peatio::Wallet.",
22
+ "Nem wallet requires #{WALLET_VERSION_REQUIREMENT}.",
23
+ "Peatio::Wallet version is #{Peatio::Wallet::VERSION}"
24
+ ].join('\n').tap { |s| Kernel.abort s }
25
+ end
26
+ end
27
+
28
+ def register
29
+ Peatio::Blockchain.registry[:nem] = Nem2::Blockchain
30
+ Peatio::Wallet.registry[:nem] = Nem2::Wallet
31
+ end
32
+ end
33
+
34
+ if defined?(Rails::Railtie)
35
+ require "peatio/nem2/railtie"
36
+ else
37
+ check_compatibility
38
+ register
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,13 @@
1
+ module Peatio
2
+ module Nem2
3
+ class Railtie < Rails::Railtie
4
+ config.before_initialize do
5
+ Hooks.check_compatibility
6
+ end
7
+
8
+ config.after_initialize do
9
+ Hooks.register
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module Peatio
2
+ module Nem2
3
+ VERSION = "1.0.47"
4
+ end
5
+ end
@@ -0,0 +1,342 @@
1
+ module Peatio
2
+ module Nem2
3
+ class Wallet < Peatio::Wallet::Abstract
4
+ TIME_DIFFERENCE_IN_MINUTES = 10
5
+ XLM_MEMO_TYPES = { 'memoId': 'id', 'memoText': 'text', 'memoHash': 'hash', 'memoReturn': 'return' }
6
+
7
+ DEFAULT_FEATURES = { skip_deposit_collection: false }.freeze
8
+
9
+ def initialize(custom_features = {})
10
+ @features = DEFAULT_FEATURES.merge(custom_features).slice(*SUPPORTED_FEATURES)
11
+ @settings = {}
12
+ end
13
+
14
+ def configure(settings = {})
15
+ # Clean client state during configure.
16
+ @client = nil
17
+
18
+ @settings.merge!(settings.slice(*SUPPORTED_SETTINGS))
19
+
20
+ @wallet = @settings.fetch(:wallet) do
21
+ raise Peatio::Wallet::MissingSettingError, :wallet
22
+ end.slice(:uri, :address, :secret, :access_token, :wallet_id, :testnet)
23
+
24
+ @currency = @settings.fetch(:currency) do
25
+ raise Peatio::Wallet::MissingSettingError, :currency
26
+ end.slice(:id, :base_factor, :code, :options)
27
+ end
28
+
29
+ def create_address!(options = {})
30
+ currency = erc20_currency_id
31
+ options.deep_symbolize_keys!
32
+
33
+ if options.dig(:pa_details, :address_id).present? &&
34
+ options.dig(:pa_details, :updated_at).present? &&
35
+ time_difference_in_minutes(options.dig(:pa_details, :updated_at)) >= TIME_DIFFERENCE_IN_MINUTES
36
+
37
+ response = client.rest_api(:get, "#{currency}/wallet/#{wallet_id}/address/#{options.dig(:pa_details, :address_id)}")
38
+ { address: response['address'], secret: nem_wallet_passphrase }
39
+ elsif options.dig(:pa_details, :address_id).blank?
40
+ response = client.rest_api(:post, "#{currency}/wallet/#{wallet_id}/address")
41
+ { address: response['address'], secret: nem_wallet_passphrase, details: { address_id: response['id'] }}
42
+ end
43
+ rescue Nem2::Client::Error => e
44
+ raise Peatio::Wallet::ClientError, e
45
+ end
46
+
47
+ def create_transaction!(transaction, options = {})
48
+ currency_options = @currency.fetch(:options).slice(:gas_limit, :gas_price, :erc20_contract_address)
49
+
50
+ if currency_options[:gas_limit].present? && currency_options[:gas_price].present?
51
+ options.merge!(currency_options)
52
+ create_eth_transaction(transaction, options)
53
+ else
54
+ amount = convert_to_base_unit(transaction.amount)
55
+
56
+ if options[:subtract_fee].to_s == 'true'
57
+ fee = build_raw_transaction(transaction)
58
+ baseFeeInfo = fee.dig('feeInfo','fee')
59
+ fee = baseFeeInfo.present? ? baseFeeInfo : fee.dig('txInfo','Fee')
60
+ amount -= fee.to_i
61
+ end
62
+
63
+ response = client.rest_api(:post, "#{currency_id}/wallet/#{wallet_id}/sendcoins", {
64
+ address: normalize_address(transaction.to_address.to_s),
65
+ amount: amount.to_s,
66
+ walletPassphrase: nem_wallet_passphrase,
67
+ memo: xlm_memo(transaction.to_address.to_s)
68
+ }.compact)
69
+
70
+ if response['feeString'].present?
71
+ fee = convert_from_base_unit(response['feeString'])
72
+ transaction.fee = fee
73
+ end
74
+
75
+ transaction.hash = normalize_txid(response['txid'])
76
+ transaction.fee_currency_id = erc20_currency_id
77
+ transaction
78
+ end
79
+ rescue Nem2::Client::Error => e
80
+ raise Peatio::Wallet::ClientError, e
81
+ end
82
+
83
+
84
+ def build_raw_transaction(transaction)
85
+ client.rest_api(:post, "#{currency_id}/wallet/#{wallet_id}/tx/build", {
86
+ recipients: [{
87
+ address: transaction.to_address,
88
+ amount: convert_to_base_unit(transaction.amount).to_s
89
+ }]
90
+ }.compact)
91
+ end
92
+
93
+ def create_eth_transaction(transaction, options = {})
94
+ amount = convert_to_base_unit(transaction.amount)
95
+ hop = true unless options.slice(:gas_price).present?
96
+
97
+ fee_estimate = fee_estimate(amount.to_s, hop)
98
+
99
+ if transaction.options.present? && transaction.options[:gas_price].present?
100
+ options[:gas_price] = transaction.options[:gas_price]
101
+ else
102
+ options[:gas_price] = fee_estimate['minGasPrice'].to_i
103
+ end
104
+
105
+ response = client.rest_api(:post, "#{currency_id}/wallet/#{wallet_id}/sendcoins", {
106
+ address: transaction.to_address.to_s,
107
+ amount: amount.to_s,
108
+ walletPassphrase: nem_wallet_passphrase,
109
+ gas: options.fetch(:gas_limit).to_i,
110
+ gasPrice: options.fetch(:gas_price).to_i,
111
+ hop: hop
112
+ }.compact)
113
+
114
+ if response['feeString'].present?
115
+ fee = convert_from_base_unit(response['feeString'])
116
+ transaction.fee = fee
117
+ end
118
+
119
+ transaction.hash = normalize_txid(response['txid'])
120
+ transaction.fee_currency_id = erc20_currency_id
121
+ transaction.options = options
122
+ transaction
123
+ end
124
+
125
+ def fee_estimate(amount, hop)
126
+ client.rest_api(:get, "#{erc20_currency_id}/tx/fee", { amount: amount, hop: hop }.compact)
127
+ end
128
+
129
+ def load_balance!
130
+ if @currency.fetch(:options).slice(:erc20_contract_address).present?
131
+ load_erc20_balance!
132
+ else
133
+ response = client.rest_api(:get, "#{currency_id}/wallet/#{wallet_id}")
134
+ convert_from_base_unit(response.fetch('balanceString'))
135
+ end
136
+ rescue Nem2::Client::Error => e
137
+ raise Peatio::Wallet::ClientError, e
138
+ end
139
+
140
+ def load_erc20_balance!
141
+ response = client.rest_api(:get, "#{erc20_currency_id}/wallet/#{wallet_id}?allTokens=true")
142
+ convert_from_base_unit(response.dig('tokens', currency_id, 'balanceString'))
143
+ rescue Nem2::Client::Error => e
144
+ raise Peatio::Wallet::ClientError, e
145
+ end
146
+
147
+ def trigger_webhook_event(request)
148
+ currency = @wallet.fetch(:testnet).present? ? 't' + @currency.fetch(:id) : @currency.fetch(:id)
149
+ if request.params['type'] == 'transfer'
150
+ return unless currency == request.params['coin'] &&
151
+ @wallet.fetch(:wallet_id) == request.params['wallet']
152
+ else
153
+ return unless @wallet.fetch(:wallet_id) == request.params['walletId']
154
+ end
155
+
156
+ if request.params['type'] == 'transfer'
157
+ transactions = fetch_transfer!(request.params['transfer'])
158
+ return transactions
159
+ elsif request.params['type'] == 'address_confirmation'
160
+ address_id = fetch_address_id(request.params['address'])
161
+ return { address_id: address_id, address: request.params['address'], currency_id: currency_id }
162
+ end
163
+ end
164
+
165
+ def register_webhooks!(url)
166
+ transfer_webhook(url)
167
+ address_confirmation_webhook(url)
168
+ end
169
+
170
+ def fetch_address_id(address)
171
+ currency = erc20_currency_id
172
+ client.rest_api(:get, "#{currency}/wallet/#{wallet_id}/address/#{address}")
173
+ .fetch('id')
174
+ rescue Nem2::Client::Error => e
175
+ raise Peatio::Wallet::ClientError, e
176
+ end
177
+
178
+ def fetch_transfer!(id)
179
+ response = client.rest_api(:get, "#{currency_id}/wallet/#{wallet_id}/transfer/#{id}")
180
+ parse_entries(response['entries']).map do |entry|
181
+ to_address = if response.dig('coinSpecific', 'memo').present?
182
+ memo = response.dig('coinSpecific', 'memo')
183
+ memo_type = memo.kind_of?(Array) ? memo.first : memo
184
+ build_address(entry['address'], memo_type)
185
+ else
186
+ entry['address']
187
+ end
188
+ state = define_transaction_state(response['state'])
189
+
190
+ if response['outputs'].present?
191
+ output = response['outputs'].find { |out| out['address'] == to_address }
192
+ txout = output['index'] if output.present?
193
+ end
194
+
195
+ if response['feeString'].present?
196
+ fee = convert_from_base_unit(response['feeString']) / response['entries'].count
197
+ end
198
+
199
+ transaction = Peatio::Transaction.new(
200
+ currency_id: @currency.fetch(:id),
201
+ amount: convert_from_base_unit(entry['valueString']),
202
+ fee: fee,
203
+ fee_currency_id: erc20_currency_id,
204
+ hash: normalize_txid(response['txid']),
205
+ to_address: to_address,
206
+ block_number: response['height'],
207
+ txout: txout.to_i,
208
+ status: state
209
+ )
210
+
211
+ transaction if transaction.valid?
212
+ end.compact
213
+ rescue Nem2::Client::Error => e
214
+ raise Peatio::Wallet::ClientError, e
215
+ end
216
+
217
+ def transfer_webhook(url)
218
+ client.rest_api(:post, "#{currency_id}/wallet/#{wallet_id}/webhooks", {
219
+ type: 'transfer',
220
+ allToken: true,
221
+ url: url,
222
+ label: "webhook for #{url}",
223
+ listenToFailureStates: false
224
+ })
225
+ end
226
+
227
+ def address_confirmation_webhook(url)
228
+ client.rest_api(:post, "#{currency_id}/wallet/#{wallet_id}/webhooks", {
229
+ type: 'address_confirmation',
230
+ allToken: true,
231
+ url: url,
232
+ label: "webhook for #{url}",
233
+ listenToFailureStates: false
234
+ })
235
+ end
236
+
237
+ def parse_entries(entries)
238
+ entries.map do |e|
239
+ e if e["valueString"].to_i.positive?
240
+ end.compact
241
+ end
242
+
243
+ private
244
+
245
+ def client
246
+ uri = @wallet.fetch(:uri) { raise Peatio::Wallet::MissingSettingError, :uri }
247
+ access_token = @wallet.fetch(:access_token) { raise Peatio::Wallet::MissingSettingError, :access_token }
248
+
249
+ currency_code_prefix = @wallet.fetch(:testnet) ? 't' : ''
250
+ uri = uri.gsub(/\/+\z/, '') + '/' + currency_code_prefix
251
+ @client ||= Client.new(uri, access_token)
252
+ end
253
+
254
+ def build_address(address, memo)
255
+ "#{address}?memoId=#{memo['value']}"
256
+ end
257
+
258
+ # All these functions will have to be done with the coin set to eth or teth
259
+ # since that is the actual coin type being used.
260
+ def erc20_currency_id
261
+ return 'eth' if @currency.fetch(:options).slice(:erc20_contract_address).present?
262
+
263
+ currency_id
264
+ end
265
+
266
+ def xlm_memo(address)
267
+ build_xlm_memo(address) if @currency.fetch(:id) == 'xlm'
268
+ end
269
+
270
+ def build_xlm_memo(address)
271
+ case address.split('?').last.split('=').first
272
+ when 'memoId'
273
+ memo_value_from(address, 'memoId')
274
+ when 'memoText'
275
+ memo_value_from(address, 'memoText')
276
+ when 'memoHash'
277
+ memo_value_from(address, 'memoHash')
278
+ when 'memoReturn'
279
+ memo_value_from(address, 'memoReturn')
280
+ end
281
+ end
282
+
283
+ def memo_value_from(address, type)
284
+ memo_value = address.partition(type + '=').last
285
+ return { type: XLM_MEMO_TYPES[type.to_sym], value: memo_value } if memo_value.present?
286
+ end
287
+
288
+ def currency_id
289
+ @currency.fetch(:id) { raise Peatio::Wallet::MissingSettingError, :id }
290
+ end
291
+
292
+ def nem_wallet_passphrase
293
+ @wallet.fetch(:secret)
294
+ end
295
+
296
+ def wallet_id
297
+ @wallet.fetch(:wallet_id)
298
+ end
299
+
300
+ def normalize_address(address)
301
+ if @currency.fetch(:id) == 'xlm'
302
+ address.split('?').first
303
+ else
304
+ address
305
+ end
306
+ end
307
+
308
+ def normalize_txid(txid)
309
+ txid.downcase
310
+ end
311
+
312
+ def convert_from_base_unit(value)
313
+ value.to_d / @currency.fetch(:base_factor)
314
+ end
315
+
316
+ def convert_to_base_unit(value)
317
+ x = value.to_d * @currency.fetch(:base_factor)
318
+ unless (x % 1).zero?
319
+ raise Peatio::WalletClient::Error,
320
+ "Failed to convert value to base (smallest) unit because it exceeds the maximum precision: " \
321
+ "#{value.to_d} - #{x.to_d} must be equal to zero."
322
+ end
323
+ x.to_i
324
+ end
325
+
326
+ def time_difference_in_minutes(updated_at)
327
+ (Time.now - updated_at)/60
328
+ end
329
+
330
+ def define_transaction_state(state)
331
+ case state
332
+ when 'unconfirmed'
333
+ 'pending'
334
+ when 'confirmed'
335
+ 'success'
336
+ when 'failed','rejected'
337
+ 'failed'
338
+ end
339
+ end
340
+ end
341
+ end
342
+ end
@@ -0,0 +1,14 @@
1
+ require "active_support/core_ext/enumerable"
2
+ require "peatio"
3
+
4
+ module Peatio
5
+ module Nem2
6
+ class Error < StandardError; end
7
+ require "peatio/nem2/version"
8
+ require "peatio/nem2/client"
9
+ require "peatio/nem2/blockchain"
10
+ require "peatio/nem2/wallet"
11
+ require "peatio/nem2/hooks"
12
+ require "peatio/nem2/client"
13
+ end
14
+ end
@@ -0,0 +1,51 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "peatio/nem2/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "peatio-nem2"
8
+ spec.version = Peatio::Nem2::VERSION
9
+ spec.authors = ["Emiliano"]
10
+ spec.email = ["emi@rewards4earth.com"]
11
+
12
+ spec.summary = %q{Peatio Blockchain Plugin}
13
+ spec.description = %q{Peatio Blockchain Plugin}
14
+ spec.homepage = "https://www.erthexchange.com.au"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ #if spec.respond_to?(:metadata)
20
+ # spec.metadata["allowed_push_host"] = 'http://rubygems.org'
21
+ #
22
+ # spec.metadata["homepage_uri"] = spec.homepage
23
+ # spec.metadata["source_code_uri"] = "https://git.rewards4earth.com/rewards4earth/peatio-nem2"
24
+ #else
25
+ # raise "RubyGems 2.0 or newer is required to protect against " \
26
+ # "public gem pushes."
27
+ #end
28
+
29
+ # Specify which files should be added to the gem when it is released.
30
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
31
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
32
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
33
+ end
34
+ spec.bindir = "exe"
35
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
36
+ spec.require_paths = ["lib"]
37
+
38
+ spec.add_development_dependency "bundler", "~> 1.17"
39
+ spec.add_development_dependency "rake", "~> 13.0"
40
+ spec.add_development_dependency "rspec", "~> 3.0"
41
+ spec.add_development_dependency "pry-byebug"
42
+ spec.add_development_dependency "webmock", "~> 3.5"
43
+ spec.add_development_dependency "mocha", "~> 1.8"
44
+
45
+ spec.add_dependency "activesupport", "~> 5.2.3"
46
+ spec.add_dependency "better-faraday", "~> 1.0.5"
47
+ spec.add_dependency "faraday", "~> 0.17"
48
+ spec.add_dependency "memoist", "~> 0.16.0"
49
+ spec.add_dependency "peatio", ">= 0.6.3"
50
+ spec.add_dependency 'net-http-persistent', '~> 3.0.1'
51
+ end
metadata ADDED
@@ -0,0 +1,232 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: peatio-nem2
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.47
5
+ platform: ruby
6
+ authors:
7
+ - Emiliano
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-06-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.17'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.17'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry-byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: webmock
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.5'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.5'
83
+ - !ruby/object:Gem::Dependency
84
+ name: mocha
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.8'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.8'
97
+ - !ruby/object:Gem::Dependency
98
+ name: activesupport
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 5.2.3
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 5.2.3
111
+ - !ruby/object:Gem::Dependency
112
+ name: better-faraday
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 1.0.5
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 1.0.5
125
+ - !ruby/object:Gem::Dependency
126
+ name: faraday
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.17'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.17'
139
+ - !ruby/object:Gem::Dependency
140
+ name: memoist
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 0.16.0
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 0.16.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: peatio
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: 0.6.3
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: 0.6.3
167
+ - !ruby/object:Gem::Dependency
168
+ name: net-http-persistent
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: 3.0.1
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: 3.0.1
181
+ description: Peatio Blockchain Plugin
182
+ email:
183
+ - emi@rewards4earth.com
184
+ executables: []
185
+ extensions: []
186
+ extra_rdoc_files: []
187
+ files:
188
+ - ".gitignore"
189
+ - ".gitlab-ci.yml"
190
+ - ".rspec"
191
+ - ".rspec_status"
192
+ - Gemfile
193
+ - LICENSE.txt
194
+ - README.md
195
+ - Rakefile
196
+ - bin/console
197
+ - bin/setup
198
+ - config/blockchains.yml
199
+ - config/currencies.yml
200
+ - config/wallets.yml
201
+ - lib/peatio/nem2.rb
202
+ - lib/peatio/nem2/blockchain.rb
203
+ - lib/peatio/nem2/client.rb
204
+ - lib/peatio/nem2/hooks.rb
205
+ - lib/peatio/nem2/railtie.rb
206
+ - lib/peatio/nem2/version.rb
207
+ - lib/peatio/nem2/wallet.rb
208
+ - peatio-nem2.gemspec
209
+ homepage: https://www.erthexchange.com.au
210
+ licenses:
211
+ - MIT
212
+ metadata: {}
213
+ post_install_message:
214
+ rdoc_options: []
215
+ require_paths:
216
+ - lib
217
+ required_ruby_version: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - ">="
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
222
+ required_rubygems_version: !ruby/object:Gem::Requirement
223
+ requirements:
224
+ - - ">="
225
+ - !ruby/object:Gem::Version
226
+ version: '0'
227
+ requirements: []
228
+ rubygems_version: 3.0.9
229
+ signing_key:
230
+ specification_version: 4
231
+ summary: Peatio Blockchain Plugin
232
+ test_files: []