tipjar 0.1.16

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []