tipjar 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,29 @@
1
+ module Bitbot::Prize
2
+ # create and initialise the random number generator
3
+ prng = Random.new
4
+ # create the rules for winning
5
+
6
+ # No win
7
+ # [1-865] 86.5% chance
8
+
9
+
10
+ # Standard chat win of 10 + 1 - 500 satoshi max of 501 satoshi (0.00501mBTC)
11
+ # [866 - 940] 7.5% chance
12
+ def prize_win_std
13
+ end
14
+
15
+ # Minor prize win of 1000 satoshi max 1000 satoshi (0.01mBTC)
16
+ # [941-990] 5% chance
17
+ def prize_win_minor
18
+ end
19
+
20
+ # Major prize win of 10000 satoshi max of 10000 satoshi (0.1mBTC)
21
+ # [991-1000] 1% chance
22
+ def prize_win_major
23
+ end
24
+
25
+ # Check every 10 mins for bot balance, if less than 0.1mBTC then pause all payouts and print out message
26
+ # this can also be run from plugin.rb on a set timer rather than duplicating here
27
+ def prize_win_balance_check
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ module Bitbot::Ticker
2
+ def on_ticker(m, curr)
3
+ # 'curr' can be any of GBP|EUR|USD
4
+ @curr = curr
5
+ if curr == GBP
6
+ # GBP ticker
7
+ m.reply "Current BTC➜GBP Exchange Rate from blockchain.info is #{satoshi_to_gbp}
8
+ elsif curr == EUR
9
+ # EUR ticker
10
+ m.reply "Current BTC➜EUR Exchange Rate from blockchain.info is #{satoshi_to_eur}
11
+ else
12
+ # USD ticker
13
+ m.reply "Current BTC➜USD Exchange Rate from blockchain.info is #{satoshi_to_usd}
14
+ end
15
+ end
@@ -0,0 +1,61 @@
1
+ # coding: utf-8
2
+
3
+ module Bitbot::Tip
4
+ def on_tip(m, recipient, amount, message)
5
+ # Look up sender
6
+ user_id = db.get_or_create_user_id_for_username(m.user.user)
7
+
8
+ # Look up recipient
9
+ recipient_ircuser = m.channel.users.keys.find {|u| u.name == recipient }
10
+ unless recipient_ircuser
11
+ m.user.msg("Could not find #{recipient} in the channel list.")
12
+ return
13
+ end
14
+ recipient_user_id = db.get_or_create_user_id_for_username(recipient_ircuser.user)
15
+
16
+ # Convert amount to satoshi
17
+ satoshi = str_to_satoshi(amount)
18
+ if satoshi <= 0
19
+ m.user.msg("Cannot send a negative amount.")
20
+ return
21
+ end
22
+
23
+ # Attempt the transaction (will raise on InsufficientFunds)
24
+ begin
25
+ db.create_transaction_from_tip(user_id, recipient_user_id, satoshi, message)
26
+ rescue Bitbot::InsufficientFundsError
27
+ m.reply "Insufficient funds! It's the thought that counts though :).", true
28
+ return
29
+ end
30
+
31
+ # Success! Let the room know...
32
+ m.reply "[✔] Verified: ".irc(:grey).irc(:bold) +
33
+ m.user.user.irc(:bold) +
34
+ " ➜ ".irc(:grey) +
35
+ satoshi_with_usd(satoshi) +
36
+ " ➜ ".irc(:grey) +
37
+ recipient_ircuser.user.irc(:bold)
38
+
39
+ # ... and let the sender know privately ...
40
+ m.user.msg "You just sent " +
41
+ recipient_ircuser.user.irc(:bold) + " " +
42
+ satoshi_with_usd(satoshi) +
43
+ " in " +
44
+ m.channel.name.irc(:bold) +
45
+ " bringing your balance to " +
46
+ satoshi_with_usd(db.get_balance_for_user_id(user_id)) +
47
+ "."
48
+
49
+ # ... and let the recipient know privately.
50
+ recipient_ircuser.msg m.user.user.irc(:bold) +
51
+ " just sent you " +
52
+ satoshi_with_usd(satoshi) +
53
+ " in " +
54
+ m.channel.name.irc(:bold) +
55
+ " bringing your balance to " +
56
+ satoshi_with_usd(db.get_balance_for_user_id(recipient_user_id)) +
57
+ ". Type 'help' to list TipJar's commands."
58
+ end
59
+ end
60
+
61
+
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+
3
+ module Bitbot::TipStats
4
+ def on_tipstats(m)
5
+ stats = db.get_tipping_stats
6
+
7
+ str = "Stats: ".irc(:grey) +
8
+ "tips today: " +
9
+ satoshi_with_usd(0 - stats[:total_tipped]) + " " +
10
+ "(#{stats[:total_tips]} tips) "
11
+
12
+ if stats[:tippers].length > 0
13
+ str += "biggest tipper: ".irc(:black) +
14
+ stats[:tippers][0][0].irc(:bold) +
15
+ " (#{satoshi_with_usd(0 - stats[:tippers][0][1])}) "
16
+ end
17
+
18
+ if stats[:tippees].length > 0
19
+ str += "biggest recipient: ".irc(:black) +
20
+ stats[:tippees][0][0].irc(:bold) +
21
+ " (#{satoshi_with_usd(stats[:tippees][0][1])}) "
22
+ end
23
+
24
+ m.reply str
25
+ end
26
+ end
27
+
28
+
29
+
@@ -0,0 +1,6 @@
1
+ module Bitbot::Txfee
2
+ def on_txfee(m)
3
+ m.user.msg "The transaction fee is set at #{satoshi_to_str(withdrawal_fee)} BTC. This will also be added to any withdrawal request."
4
+ m.user.msg "This will allow your transaction to be relayed by miners much faster and reduce the possibility of it being returned or rejected."
5
+ end
6
+ end
@@ -0,0 +1,112 @@
1
+ module Bitbot::UpdateAddresses
2
+ def cache_file_path
3
+ File.join(config['data']['path'], "cached_addresses.yml")
4
+ end
5
+
6
+ def on_update_addresses(event = nil)
7
+ if cached_addresses.nil?
8
+ # Load from the cache, if available, on first load
9
+ self.cached_addresses = YAML.load(File.read(cache_file_path)) rescue nil
10
+ end
11
+
12
+ # Updates the cached map of depositing addresses.
13
+ new_addresses = {}
14
+ all_addresses = []
15
+
16
+ addresses = blockchain.get_addresses_in_wallet()
17
+ addresses.each do |address|
18
+ all_addresses << address["address"]
19
+ next unless address["label"] =~ /^\d+$/
20
+
21
+ user_id = address["label"].to_i
22
+
23
+ new_addresses[user_id] = address
24
+
25
+ # We set a flag on the address saying we need to get the
26
+ # confirmed balance IF the previous entry has the flag, OR
27
+ # the address is new OR if the balance does not equal the
28
+ # previous balance. We only clear the field when the balance
29
+ # equals the confirmed balance.
30
+ address["need_confirmed_balance"] = @cached_addresses[user_id]["need_confirmed_balance"] rescue true
31
+ if address["balance"] != (@cached_addresses[user_id]["balance"] rescue nil)
32
+ address["need_confirmed_balance"] = true
33
+ end
34
+ end
35
+
36
+ # Now go through new addresses, performing any confirmation checks
37
+ # for flagged ones.
38
+ new_addresses.each do |user_id, address|
39
+ if address["need_confirmed_balance"]
40
+ balance = blockchain.get_balance_for_address(address["address"])
41
+ address["confirmed_balance"] = balance
42
+
43
+ if address["confirmed_balance"] == address["balance"]
44
+ address["need_confirmed_balance"] = false
45
+ end
46
+
47
+ # Process any transactions for this address
48
+ process_new_transactions_for_address(address, user_id, all_addresses)
49
+ end
50
+ end
51
+
52
+ # Thread-safe? Sure, why not.
53
+ self.cached_addresses = new_addresses
54
+
55
+ # Cache them on disk for faster startups
56
+ File.write(cache_file_path, YAML.dump(new_addresses))
57
+ end
58
+
59
+ def process_new_transactions_for_address(address, user_id, all_addresses)
60
+ existing_transactions = {}
61
+ db.get_incoming_transaction_ids.each do |txid|
62
+ existing_transactions[txid] = true
63
+ end
64
+
65
+ response = blockchain.get_details_for_address(address["address"])
66
+
67
+ username = db.get_username_for_user_id(user_id)
68
+
69
+ response["txs"].each do |tx|
70
+ # Skip ones we already have in the database
71
+ next if existing_transactions[tx["hash"]]
72
+
73
+ # Skip any transactions that have an existing bitbot address
74
+ # as an input
75
+ if tx["inputs"].any? {|input| all_addresses.include? input["prev_out"]["addr"] }
76
+ debug "Skipping tx with bitbot input address: #{tx["hash"]}"
77
+ next
78
+ end
79
+
80
+ # find the total amount for this address
81
+ amount = 0
82
+ tx["out"].each do |out|
83
+ if out["addr"] == address["address"]
84
+ amount += out["value"]
85
+ end
86
+ end
87
+
88
+ # Skip unless it's in a block (>=1 confirmation)
89
+ if !tx["block_height"] || tx["block_height"] == 0
90
+ # TODO: only tell them this one time.
91
+ if ircuser = user_with_username(username)
92
+ ircuser.msg "Waiting for confirmation of transaction of " +
93
+ satoshi_with_usd(amount) +
94
+ " in transaction #{tx["hash"].irc(:grey)}"
95
+ end
96
+ next
97
+ end
98
+
99
+ # There is a unique constraint on incoming_transaction, so this
100
+ # will fail if for some reason we try to add it again.
101
+ if db.create_transaction_from_deposit(user_id, amount, tx["hash"])
102
+ # Notify the depositor, if they're around
103
+ if ircuser = user_with_username(username)
104
+ ircuser.msg "Received deposit of " +
105
+ satoshi_with_usd(amount) + ". Current balance is " +
106
+ satoshi_with_usd(db.get_balance_for_user_id(user_id)) + "."
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+
@@ -0,0 +1,5 @@
1
+ module Bitbot::UpdateExchangeRates
2
+ def on_update_exchange_rates(event = nil)
3
+ self.exchange_rates = blockchain.get_exchange_rates()
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Bitbot::Version
2
+ def on_version
3
+ m.user.msg "I am version 0.0.5 BETA. I am owned and operated by WeirdThall."
4
+ end
5
+ end
@@ -0,0 +1,35 @@
1
+ module Bitbot::Withdraw
2
+ def on_withdraw(m, args)
3
+ if args =~ /\s+([\d.]+)\s+([13][0-9a-zA-Z]{26,35})/
4
+ satoshi = str_to_satoshi($1)
5
+ address = $2
6
+
7
+ user_id = db.get_or_create_user_id_for_username(m.user.user)
8
+
9
+ # Perform the local transaction in the database. Note that we
10
+ # don't do the blockchain update in the transaction, because we
11
+ # don't want to roll back the transaction if the blockchain update
12
+ # *appears* to fail. It might look like it failed, but really
13
+ # succeed, letting someone withdraw money twice.
14
+ begin
15
+ db.create_transaction_from_withdrawal(user_id, satoshi, withdrawal_fee, address)
16
+ rescue Bitbot::InsufficientFundsError
17
+ m.reply "You don't have enough to withdraw #{satoshi_to_str(satoshi)} + 0.0005 tx fee"
18
+ return
19
+ end
20
+
21
+ response = blockchain.create_payment(address, satoshi, withdrawal_fee)
22
+ if response["tx_hash"]
23
+ m.reply "Sent #{satoshi_with_usd(satoshi)} to #{address.irc(:bold)} " +
24
+ "in transaction #{response["tx_hash"].irc(:grey)}."
25
+ else
26
+ m.reply "Something may have gone wrong with your withdrawal. Please contact " +
27
+ "your friendly TipJar admin to investigate where your money is."
28
+ end
29
+ else
30
+ m.reply "Usage: withdraw <amount in BTC> <address>"
31
+ m.reply "#{satoshi_to_str(withdrawal_fee)} BTC will also be withdrawn for the transaction fee."
32
+ end
33
+ end
34
+ end
35
+
data/lib/ircstring.rb ADDED
@@ -0,0 +1,55 @@
1
+ module StyledIrcString
2
+ CODES = {
3
+ :color => "\x03",
4
+ :bold => "\x02",
5
+ :underline => "\x1f",
6
+ :inverse => "\x16",
7
+ :clear => "\x0f",
8
+ }
9
+
10
+ COLORS = {
11
+ 0 => %w(white),
12
+ 1 => %w(black),
13
+ 2 => %w(blue navy),
14
+ 3 => %w(green),
15
+ 4 => %w(red),
16
+ 5 => %w(brown maroon),
17
+ 6 => %w(purple),
18
+ 7 => %w(orange olive),
19
+ 8 => %w(yellow),
20
+ 9 => %w(light_green lime),
21
+ 10 => %w(teal a_green blue_cyan),
22
+ 11 => %w(light_cyan cyan aqua),
23
+ 12 => %w(light_blue royal),
24
+ 13 => %w(pink light_purple fuchsia),
25
+ 14 => %w(grey),
26
+ 15 => %w(light_grey silver),
27
+ }
28
+
29
+ def code_for_color(color)
30
+ COLORS.each do |code, colors|
31
+ if colors.include? color.to_s
32
+ return "%02d" % code
33
+ end
34
+ end
35
+
36
+ nil
37
+ end
38
+
39
+ def irc(attr1, attr2 = nil)
40
+ if CODES[attr1]
41
+ return "#{CODES[attr1]}#{self}#{CODES[:clear]}"
42
+ elsif fg_color = code_for_color(attr1)
43
+ bg_color = code_for_color(attr2)
44
+ bg_string = bg_color ? ",#{bg_color}" : ""
45
+
46
+ return "#{CODES[:color]}#{fg_color}#{bg_string}#{self}#{CODES[:clear]}"
47
+ end
48
+
49
+ self
50
+ end
51
+ end
52
+
53
+ class String
54
+ include StyledIrcString
55
+ end
data/tipjar.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{tipjar}
5
+ s.version = "0.1.16"
6
+ s.platform = Gem::Platform::RUBY
7
+ s.authors = ["WeirdThall", "Zach Wily"]
8
+ s.email = ["weirdthall@gmail.com", "zach@zwily.com"]
9
+ s.homepage = %q{http://github.com/zwily/bitbot}
10
+ s.summary = %q{Bitcoin IRC Tip Bot}
11
+ s.description = ["A Bitcoin IRC Tip Bot on freenode"]
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.default_executable = %q{bitbot}
17
+ s.require_paths = ["lib"]
18
+
19
+
20
+ s.add_dependency "cinch"
21
+ s.add_dependency "daemons"
22
+ s.add_dependency "sqlite3"
23
+ s.add_dependency "httparty"
24
+
25
+ s.add_development_dependency "rspec", "~> 2.5"
26
+ s.add_development_dependency "yard"
27
+ end
28
+
metadata ADDED
@@ -0,0 +1,159 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tipjar
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.16
5
+ platform: ruby
6
+ authors:
7
+ - WeirdThall
8
+ - Zach Wily
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-11-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: cinch
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: daemons
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: sqlite3
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: httparty
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rspec
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: '2.5'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ~>
82
+ - !ruby/object:Gem::Version
83
+ version: '2.5'
84
+ - !ruby/object:Gem::Dependency
85
+ name: yard
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ description: '["A Bitcoin IRC Tip Bot on freenode"]'
99
+ email:
100
+ - weirdthall@gmail.com
101
+ - zach@zwily.com
102
+ executables:
103
+ - bitbot
104
+ extensions: []
105
+ extra_rdoc_files: []
106
+ files:
107
+ - .gitignore
108
+ - Gemfile
109
+ - README.md
110
+ - README_old.md
111
+ - Rakefile
112
+ - bin/bitbot
113
+ - bitbot.gemspec
114
+ - lib/bitbot/blockchain.rb
115
+ - lib/bitbot/database.rb
116
+ - lib/bitbot/plugin.rb
117
+ - lib/bitbot/plugin/balance.rb
118
+ - lib/bitbot/plugin/common.rb
119
+ - lib/bitbot/plugin/deposit.rb
120
+ - lib/bitbot/plugin/doc.rb
121
+ - lib/bitbot/plugin/help.rb
122
+ - lib/bitbot/plugin/history.rb
123
+ - lib/bitbot/plugin/online.rb
124
+ - lib/bitbot/plugin/ping.rb
125
+ - lib/bitbot/plugin/prize.rb
126
+ - lib/bitbot/plugin/ticker.rb
127
+ - lib/bitbot/plugin/tip.rb
128
+ - lib/bitbot/plugin/tipstats.rb
129
+ - lib/bitbot/plugin/txfee.rb
130
+ - lib/bitbot/plugin/update_addresses.rb
131
+ - lib/bitbot/plugin/update_exchange_rates.rb
132
+ - lib/bitbot/plugin/version.rb
133
+ - lib/bitbot/plugin/withdraw.rb
134
+ - lib/ircstring.rb
135
+ - tipjar.gemspec
136
+ homepage: http://github.com/zwily/bitbot
137
+ licenses: []
138
+ metadata: {}
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - '>='
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubyforge_project:
155
+ rubygems_version: 2.1.10
156
+ signing_key:
157
+ specification_version: 4
158
+ summary: Bitcoin IRC Tip Bot
159
+ test_files: []