bitcoin-atm
bitcoin atm for pyc inc.
git clone https://9o.is/git/bitcoin-atm.git
Wallet.scala
(2450B)
1 package inc.pyc.chimera
2 package minions
3
4 import inc.pyc._
5 import bitcoin._
6 import service._
7 import BitcoinJsonRPC._
8 import akka.actor._
9 import akka.pattern._
10 import scala.concurrent.Future
11
12 /**
13 * Minion that has access to bitcoin wallet
14 * @param service bitcoin wallet service
15 */
16 class WalletMinion(service: BitcoinService.Value)
17 extends Actor
18 with ActorLogging
19 with Minion
20 with MinionWorker
21 with HttpMinion {
22
23 import context.dispatcher
24
25 def name: String = "Wallet_"+util.Random.nextInt
26 def props: Props = BitcoinService.props(service)
27
28 val tasks: Receive = {
29 case GetBalance => getBalance
30 case qr: QrCode => validateQr(qr)
31 case tx: IncompleteTx => sell(tx)
32 }
33
34 /**
35 * Validates bitcoin address in the QR code.
36 * @param code scanned QR code
37 */
38 def validateQr(code: QrCode) {
39 val future = validateAddress(code.qr) map {
40 validation =>
41 if (!validation.isvalid) InvalidBitcoinAddress
42 else BitcoinAddress(validation.address)
43 }
44 pipe (future) to sender
45 }
46
47 /**
48 * Sells bitcoins to the user.
49 */
50 def sell(tx: IncompleteTx) = workout {
51 worker =>
52 // TODO sell bitcoins
53 // listen for the confirmation from the network,
54 // reply when available
55 log info "SELLING BITCOINS!"
56 val txid = scala.util.Random.nextLong.toString
57 sender ! CompleteTx(tx, txid)
58 }
59
60 /**
61 * Gets the balance in the wallet.
62 */
63 def getBalance = workout {
64 worker =>
65 val future = ask(worker, GetBalance).mapTo[String] map {
66 s => Balance(s.toDouble)
67 }
68 pipe (future) to sender
69 }
70
71 /**
72 * Validates the bitcoin address with the wallet service.
73 * @param address bitcoin address
74 */
75 def validateAddress(data: String) = workout_ {
76 val address = extractFromBitcoinUri(data)
77 ask(_, ValidateAddress(address)).mapTo[AddressValidation]
78 }
79
80 /**
81 * Extracts bitcoin address from URI.
82 *
83 * Note the regex is not what the bitcoin address should exactly be,
84 * but it works for extraction.
85 */
86 def extractFromBitcoinUri(uri: String) = {
87 val r = "(bitcoin:)?([a-zA-Z0-9]{1,60})(/*?.*)?".r
88 uri match {
89 case r(_, address, _) => address
90 case _ => ""
91 }
92 }
93 }
94
95
96 /**
97 * Balance remaining in bitcoin wallet.
98 * @param remaining balance remaining in bitcoin
99 */
100 case class Balance(remaining: Double) {
101 def satoshis: Int = (remaining * 100000000) toInt
102 }