~singpolyma/dev

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
1

[PATCH] add registration w/ bch

Details
Message ID
<20241107164611.50448-1-phdavis1027@gmail.com>
DKIM signature
pass
Download raw message
Patch: +212 -20
---
 forms/registration/bch.rb    | 19 +++++++++++
 lib/btc_sell_prices.rb       | 48 +++++++++++++++++++++------
 lib/registration.rb          | 64 ++++++++++++++++++++++++++++++------
 sgx_jmp.rb                   |  1 +
 test/test_bch_sell_prices.rb | 41 +++++++++++++++++++++++
 test/test_registration.rb    | 59 +++++++++++++++++++++++++++++++++
 6 files changed, 212 insertions(+), 20 deletions(-)
 create mode 100644 forms/registration/bch.rb
 create mode 100644 test/test_bch_sell_prices.rb

diff --git a/forms/registration/bch.rb b/forms/registration/bch.rb
new file mode 100644
index 0000000..3af32de
--- /dev/null
+++ b/forms/registration/bch.rb
@@ -0,0 +1,19 @@
result!
title "Activate using Bitcoin Cash"

field(
	label: "Minimual initial Bitcoin Cash deposit for activation",
	var: "amount",
	value: "%.6f" % @amount
)

field(
	label: "Bitcoin Cash address",
	var: "bch_addresses",
	value: @addr
)

instructions(
	"You will received a notification when your payment is complete." \
	"#{@final_message}"
)
diff --git a/lib/btc_sell_prices.rb b/lib/btc_sell_prices.rb
index f1783db..771f1a2 100644
--- a/lib/btc_sell_prices.rb
+++ b/lib/btc_sell_prices.rb
@@ -8,7 +8,7 @@ require "nokogiri"

require_relative "em"

class BTCSellPrices
class CryptoSellPrices
	def initialize(redis, oxr_app_id)
		@redis = redis
		@oxr = Money::Bank::OpenExchangeRatesBank.new(
@@ -17,25 +17,33 @@ class BTCSellPrices
		@oxr.app_id = oxr_app_id
	end

	def usd
		EMPromise.all([cad, cad_to_usd]).then { |(a, b)| a * b }
	end

	def ticker_row_selector
		raise NotImplementedError, "Subclass must implement"
	end

	def crypto_name
		raise NotImplementedError, "Subclass must implement"
	end

	def cad
		fetch_canadianbitcoins.then do |http|
			canadianbitcoins = Nokogiri::HTML.parse(http.response)
			cb = Nokogiri::HTML.parse(http.response)

			bitcoin_row = canadianbitcoins.at("#ticker > table > tbody > tr")
			unless bitcoin_row.at("td").text == "Bitcoin"
				raise "Bitcoin row has moved"
			row = cb.at(self.ticker_row_selector)
			unless row.at("td").text == self.crypto_name
				raise "#{crypto_name} row has moved"
			end

			BigDecimal(
				bitcoin_row.at("td:nth-of-type(4)").text.match(/^\$(\d+\.\d+)/)[1]
				row.at("td:nth-of-type(4)").text.match(/^\$(\d+\.\d+)/)[1]
			)
		end
	end

	def usd
		EMPromise.all([cad, cad_to_usd]).then { |(a, b)| a * b }
	end

protected

	def fetch_canadianbitcoins
@@ -59,3 +67,23 @@ protected
		end
	end
end

class BCHSellPrices < CryptoSellPrices
	def crypto_name
		"Bitcoin Cash"
	end

	def ticker_row_selector
		"#ticker > table > tbody > tr:nth-of-type(2)"
	end
end

class BTCSellPrices < CryptoSellPrices
	def crypto_name
		"Bitcoin"
	end

	def ticker_row_selector
		"#ticker > table > tbody > tr"
	end
end
diff --git a/lib/registration.rb b/lib/registration.rb
index ce18987..8252bb4 100644
--- a/lib/registration.rb
+++ b/lib/registration.rb
@@ -276,10 +276,18 @@ class Registration
			}.call(customer, tel, final_message: final_message, finish: finish)
		end

		class Bitcoin
			Payment.kinds[:bitcoin] = method(:new)
		class CryptoPaymentMethod
			def crypto_addrs
				raise NotImplementedError, "Subclass must implement"
			end

			THIRTY_DAYS = 60 * 60 * 24 * 30
			def reg_form_name
				raise NotImplementedError, "Subclass must implement"
			end

			def sell_prices
				raise NotImplementedError, "Subclass must implement"
			end

			def initialize(customer, tel, final_message: nil, **)
				@customer = customer
@@ -288,17 +296,17 @@ class Registration
				@final_message = final_message
			end

			attr_reader :customer_id, :tel

			def save
				TEL_SELECTIONS.set(@customer.jid, @tel)
			end

			attr_reader :customer_id, :tel

			def form(rate, addr)
				amount = CONFIG[:activation_amount] / rate

				FormTemplate.render(
					"registration/btc",
					reg_form_name,
					amount: amount,
					addr: addr,
					final_message: @final_message
@@ -314,9 +322,7 @@ class Registration
					}.then(&method(:handle_possible_prev))
				end
			end

		protected

			def handle_possible_prev(iq)
				raise "Action not allowed" unless iq.prev?

@@ -325,14 +331,52 @@ class Registration

			def addr_and_rate
				EMPromise.all([
					@customer.btc_addresses.then { |addrs|
					self.crypto_addrs.then { |addrs|
						addrs.first || @customer.add_btc_address
					},
					BTC_SELL_PRICES.public_send(@customer.currency.to_s.downcase)
					
					sell_prices.public_send(@customer.currency.to_s.downcase)
				])
			end
		end

		class Bitcoin < CryptoPaymentMethod
			Payment.kinds[:bitcoin] = method(:new)

			## TODO: This constant seems unused?
			THIRTY_DAYS = 60 * 60 * 24 * 30

			def reg_form_name
				"registration/btc"
			end

			def sell_prices
				BTC_SELL_PRICES
			end

			def crypto_addrs
				@customer.btc_addresses
			end
		end

		## Like Bitcoin
		class BCH < CryptoPaymentMethod
			Payment.kinds[:bch] = method(:new)

			def reg_form_name
				"registration/bch"
			end

			def sell_prices
				BCH_SELL_PRICES
			end

			def crypto_addrs
				@customer.bch_addresses
			end
		end


		class CreditCard
			Payment.kinds[:credit_card] = ->(*args, **kw) { self.for(*args, **kw) }

diff --git a/sgx_jmp.rb b/sgx_jmp.rb
index cd2bb12..10176f7 100644
--- a/sgx_jmp.rb
+++ b/sgx_jmp.rb
@@ -220,6 +220,7 @@ when_ready do
	REDIS = EM::Hiredis.connect
	MEMCACHE = EM::P::Memcache.connect
	BTC_SELL_PRICES = BTCSellPrices.new(REDIS, CONFIG[:oxr_app_id])
	BCH_SELL_PRICES = BCHSellPrices.new(REDIS, CONFIG[:oxr_app_id])
	DB = Postgres.connect(dbname: "jmp", size: 5)
	TEL_SELECTIONS = TelSelections.new

diff --git a/test/test_bch_sell_prices.rb b/test/test_bch_sell_prices.rb
new file mode 100644
index 0000000..9b8da94
--- /dev/null
+++ b/test/test_bch_sell_prices.rb
@@ -0,0 +1,41 @@
# frozen_string_literal: true

require "em-hiredis"
require "test_helper"
require "btc_sell_prices"

class BCHSellPricesTest < Minitest::Test
	def setup
		@redis = Minitest::Mock.new
		@subject = BCHSellPrices.new(@redis, "")
	end

	def test_cad
		stub_request(:get, "https://www.canadianbitcoins.com").to_return(
			body: "<div id='ticker'><table><tbody>" \
			      "<tr>" \
				  "<td>Monopoly Money</td><td></td><td></td><td>10 trillion</td>" \
				  "</tr>" \
				  "<tr>" \
				  "<td>Bitcoin Cash</td><td></td><td></td><td>$123.00</td>" \
				  "</tr>"
		)
		assert_equal BigDecimal(123), @subject.cad.sync
	end
	em :test_cad

	def test_usd
		stub_request(:get, "https://www.canadianbitcoins.com").to_return(
			body: "<div id='ticker'><table><tbody>" \
			      "<tr>" \
				  "<td>Monopoly Money</td><td></td><td></td><td>10 trillion</td>" \
				  "</tr>" \
				  "<tr>" \
				  "<td>Bitcoin Cash</td><td></td><td></td><td>$123.00</td>" \
				  "</tr>"
		)
		@redis.expect(:get, EMPromise.resolve("0.5"), ["cad_to_usd"])
		assert_equal BigDecimal(123) / 2, @subject.usd.sync
	end
	em :test_usd
end
diff --git a/test/test_registration.rb b/test/test_registration.rb
index e3bf4e4..4d0a566 100644
--- a/test/test_registration.rb
+++ b/test/test_registration.rb
@@ -574,6 +574,16 @@ class RegistrationTest < Minitest::Test
			assert_kind_of Registration::Payment::Bitcoin, result
		end

		def test_for_bch
			iq = Blather::Stanza::Iq::Command.new
			iq.form.fields = [
				{ var: "activation_method", value: "bch" },
				{ var: "plan_name", value: "test_usd" }
			]
			result = Registration::Payment.for(iq, customer, "+15555550000")
			assert_kind_of Registration::Payment::BCH, result
		end

		def test_for_credit_card
			braintree_customer = Minitest::Mock.new
			CustomerFinancials::BRAINTREE.expect(
@@ -673,6 +683,55 @@ class RegistrationTest < Minitest::Test
			em :test_write
		end

		class BCHTest < Minitest::Test
			Registration::Payment::BCH::BCH_SELL_PRICES = Minitest::Mock.new
			CustomerFinancials::REDIS = Minitest::Mock.new

			def setup
				@customer = Minitest::Mock.new(
					customer(plan_name: "test_usd")
				)
				@customer.expect(
					:add_btc_address,
					EMPromise.resolve("testaddr")
				)
				@bch = Registration::Payment::BCH.new(
					@customer,
					"+15555550000"
				)
			end

			def test_write
				CustomerFinancials::REDIS.expect(
					:smembers,
					EMPromise.resolve([]),
					["jmp_customer_bch_addresses-test"]
				)
				blather = Minitest::Mock.new
				Command::COMMAND_MANAGER.expect(
					:write,
					EMPromise.reject(SessionManager::Timeout.new),
					[Matching.new do |reply|
						assert_equal :canceled, reply.status
						assert_equal "1.000000", reply.form.field("amount").value
						assert_equal "testaddr", reply.form.field("bch_addresses").value
						true
					end]
				)
				Registration::Payment::BCH::BCH_SELL_PRICES.expect(
					:usd,
					EMPromise.resolve(BigDecimal(1))
				)
				@bch.stub(:save, EMPromise.resolve(nil)) do
					execute_command(blather: blather) do
						@bch.write
					end
				end
				assert_mock blather
			end
			em :test_write
		end

		class CreditCardTest < Minitest::Test
			def setup
				@credit_card = Registration::Payment::CreditCard.new(
-- 
2.34.1
Details
Message ID
<Zy0BcGhM4ZCteUfQ@singpolyma-beefy.lan>
In-Reply-To
<20241107164611.50448-1-phdavis1027@gmail.com> (view parent)
DKIM signature
pass
Download raw message
>---
> forms/registration/bch.rb    | 19 +++++++++++
> lib/btc_sell_prices.rb       | 48 +++++++++++++++++++++------
> lib/registration.rb          | 64 ++++++++++++++++++++++++++++++------
> sgx_jmp.rb                   |  1 +
> test/test_bch_sell_prices.rb | 41 +++++++++++++++++++++++
> test/test_registration.rb    | 59 +++++++++++++++++++++++++++++++++
> 6 files changed, 212 insertions(+), 20 deletions(-)
> create mode 100644 forms/registration/bch.rb
> create mode 100644 test/test_bch_sell_prices.rb
>
>diff --git a/lib/registration.rb b/lib/registration.rb
>index ce18987..8252bb4 100644
>--- a/lib/registration.rb
>+++ b/lib/registration.rb
>@@ -325,14 +331,52 @@ class Registration
>
> 			def addr_and_rate
> 				EMPromise.all([
>-					@customer.btc_addresses.then { |addrs|
>+					self.crypto_addrs.then { |addrs|
> 						addrs.first || @customer.add_btc_address

You call add_btc_address no matter which currency they want to pay with. So 
they'll never get a BCH address assigned.

> 					},
>-					BTC_SELL_PRICES.public_send(@customer.currency.to_s.downcase)
>+					
>+					sell_prices.public_send(@customer.currency.to_s.downcase)
> 				])
> 			end
> 		end
>
>+		class Bitcoin < CryptoPaymentMethod
>+			Payment.kinds[:bitcoin] = method(:new)
>+
>+			## TODO: This constant seems unused?
>+			THIRTY_DAYS = 60 * 60 * 24 * 30

If it is unused then remove it.

>+			def reg_form_name
>+				"registration/btc"
>+			end
>+
>+			def sell_prices
>+				BTC_SELL_PRICES
>+			end
>+
>+			def crypto_addrs
>+				@customer.btc_addresses
>+			end
>+		end
>+
>+		## Like Bitcoin
>+		class BCH < CryptoPaymentMethod
>+			Payment.kinds[:bch] = method(:new)
>+
>+			def reg_form_name
>+				"registration/bch"
>+			end
>+
>+			def sell_prices
>+				BCH_SELL_PRICES
>+			end
>+
>+			def crypto_addrs
>+				@customer.bch_addresses
>+			end
>+		end
>+
>+
> 		class CreditCard
> 			Payment.kinds[:credit_card] = ->(*args, **kw) { self.for(*args, **kw) }
>
>diff --git a/test/test_registration.rb b/test/test_registration.rb
>index e3bf4e4..4d0a566 100644
>--- a/test/test_registration.rb
>+++ b/test/test_registration.rb
>@@ -673,6 +683,55 @@ class RegistrationTest < Minitest::Test
> 			em :test_write
> 		end
>
>+		class BCHTest < Minitest::Test
>+			Registration::Payment::BCH::BCH_SELL_PRICES = Minitest::Mock.new
>+			CustomerFinancials::REDIS = Minitest::Mock.new
>+
>+			def setup
>+				@customer = Minitest::Mock.new(
>+					customer(plan_name: "test_usd")
>+				)
>+				@customer.expect(
>+					:add_btc_address,
>+					EMPromise.resolve("testaddr")
>+				)

Red flag to expect add_btc_address in the BCH test
Reply to thread Export thread (mbox)