Class: Zold::Wallet

Inherits:
Object
  • Object
show all
Defined in:
lib/zold/wallet.rb

Overview

A single wallet

Constant Summary collapse

MAINET =

The name of the main production network. All other networks must have different names.

'zold'
EXT =

The extension of the wallet files

'.z'

Instance Method Summary collapse

Constructor Details

#initialize(file) ⇒ Wallet

Returns a new instance of Wallet.



57
58
59
60
61
62
63
64
# File 'lib/zold/wallet.rb', line 57

def initialize(file)
  unless file.end_with?(Wallet::EXT, Copies::EXT)
    raise "Wallet file must end with #{Wallet::EXT} or #{Copies::EXT}: #{file}"
  end
  @file = File.absolute_path(file)
  @txns = CachedTxns.new(Txns.new(@file))
  @head = CachedHead.new(Head.new(@file))
end

Instance Method Details

#==(other) ⇒ Object



66
67
68
# File 'lib/zold/wallet.rb', line 66

def ==(other)
  to_s == other.to_s
end

#add(txn) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/zold/wallet.rb', line 144

def add(txn)
  raise 'The txn has to be of type Txn' unless txn.is_a?(Txn)
  raise "Wallet #{id} can't pay itself: #{txn}" if txn.bnf == id
  raise "The amount can't be zero in #{id}: #{txn}" if txn.amount.zero?
  if txn.amount.negative? && includes_negative?(txn.id)
    raise "Negative transaction with the same ID #{txn.id} already exists in #{id}"
  end
  if txn.amount.positive? && includes_positive?(txn.id, txn.bnf)
    raise "Positive transaction with the same ID #{txn.id} and BNF #{txn.bnf} already exists in #{id}"
  end
  raise "The tax payment already exists in #{id}: #{txn}" if Tax.new(self).exists?(txn.details)
  File.open(@file, 'a') { |f| f.print "#{txn}\n" }
  @txns.flush
end

#ageObject

Age of wallet in hours



193
194
195
196
# File 'lib/zold/wallet.rb', line 193

def age
  list = txns
  list.empty? ? 0 : (Time.now - list.min_by(&:date).date) / (60 * 60)
end

#balanceObject



119
120
121
# File 'lib/zold/wallet.rb', line 119

def balance
  txns.inject(Amount::ZERO) { |sum, t| sum + t.amount }
end

#digestObject



188
189
190
# File 'lib/zold/wallet.rb', line 188

def digest
  OpenSSL::Digest::SHA256.file(@file).hexdigest
end

#exists?Boolean

Returns:

  • (Boolean)


94
95
96
# File 'lib/zold/wallet.rb', line 94

def exists?
  File.exist?(@file)
end

#flushObject



215
216
217
218
# File 'lib/zold/wallet.rb', line 215

def flush
  @head.flush
  @txns.flush
end

#idObject



115
116
117
# File 'lib/zold/wallet.rb', line 115

def id
  Id.new(@head.fetch[2].strip)
end

#includes_negative?(id, bnf = nil) ⇒ Boolean

Returns:

  • (Boolean)


159
160
161
162
# File 'lib/zold/wallet.rb', line 159

def includes_negative?(id, bnf = nil)
  raise 'The txn ID has to be of type Integer' unless id.is_a?(Integer)
  !txns.find { |t| t.id == id && (bnf.nil? || t.bnf == bnf) && t.amount.negative? }.nil?
end

#includes_positive?(id, bnf) ⇒ Boolean

Returns:

  • (Boolean)


164
165
166
167
168
# File 'lib/zold/wallet.rb', line 164

def includes_positive?(id, bnf)
  raise 'The txn ID has to be of type Integer' unless id.is_a?(Integer)
  raise 'The bnf has to be of type Id' unless bnf.is_a?(Id)
  !txns.find { |t| t.id == id && t.bnf == bnf && !t.amount.negative? }.nil?
end

#incomeObject



178
179
180
181
182
# File 'lib/zold/wallet.rb', line 178

def income
  txns.each do |t|
    yield t unless t.amount.negative?
  end
end

#init(id, pubkey, overwrite: false, network: 'test') ⇒ Object



102
103
104
105
106
107
108
109
# File 'lib/zold/wallet.rb', line 102

def init(id, pubkey, overwrite: false, network: 'test')
  raise "File '#{@file}' already exists" if File.exist?(@file) && !overwrite
  raise "Invalid network name '#{network}'" unless network =~ /^[a-z]{4,16}$/
  FileUtils.mkdir_p(File.dirname(@file))
  IO.write(@file, "#{network}\n#{PROTOCOL}\n#{id}\n#{pubkey.to_pub}\n\n")
  @txns.flush
  @head.flush
end

#keyObject



174
175
176
# File 'lib/zold/wallet.rb', line 174

def key
  Key.new(text: @head.fetch[3].strip)
end

#mnemoObject



74
75
76
# File 'lib/zold/wallet.rb', line 74

def mnemo
  "#{id}/#{balance.to_zld(4)}/#{txns.count}t/#{digest[0, 6]}/#{Size.new(size)}"
end

#mtimeObject



184
185
186
# File 'lib/zold/wallet.rb', line 184

def mtime
  File.mtime(@file)
end

#networkObject



82
83
84
85
86
# File 'lib/zold/wallet.rb', line 82

def network
  n = @head.fetch[0].strip
  raise "Invalid network name '#{n}'" unless n =~ /^[a-z]{4,16}$/
  n
end

#pathObject



98
99
100
# File 'lib/zold/wallet.rb', line 98

def path
  @file
end

#prefix?(prefix) ⇒ Boolean

Returns:

  • (Boolean)


170
171
172
# File 'lib/zold/wallet.rb', line 170

def prefix?(prefix)
  key.to_pub.include?(prefix)
end

#protocolObject



88
89
90
91
92
# File 'lib/zold/wallet.rb', line 88

def protocol
  v = @head.fetch[1].strip
  raise "Invalid protocol version name '#{v}'" unless v =~ /^[0-9]+$/
  v.to_i
end

#refurbishObject



207
208
209
210
211
212
213
# File 'lib/zold/wallet.rb', line 207

def refurbish
  IO.write(
    @file,
    "#{network}\n#{protocol}\n#{id}\n#{key.to_pub}\n\n#{txns.map { |t| t.to_s + "\n" }.join}"
  )
  @txns.flush
end

#root?Boolean

Returns:

  • (Boolean)


111
112
113
# File 'lib/zold/wallet.rb', line 111

def root?
  id == Id::ROOT
end

#sizeObject

Size of the wallet file in bytes



199
200
201
# File 'lib/zold/wallet.rb', line 199

def size
  File.size(path)
end

#sub(amount, invoice, pvt, details = '-', time: Time.now) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/zold/wallet.rb', line 123

def sub(amount, invoice, pvt, details = '-', time: Time.now)
  raise 'The amount has to be of type Amount' unless amount.is_a?(Amount)
  raise "The amount can't be negative: #{amount}" if amount.negative?
  raise 'The pvt has to be of type Key' unless pvt.is_a?(Key)
  prefix, target = invoice.split('@')
  tid = max + 1
  raise 'Too many transactions already, can\'t add more' if max > 0xffff
  txn = Txn.new(
    tid,
    time,
    amount * -1,
    prefix,
    Id.new(target),
    details
  )
  txn = txn.signed(pvt, id)
  raise "Invalid private key for the wallet #{id}" unless Signature.new(network).valid?(key, id, txn)
  add(txn)
  txn
end

#to_sObject



70
71
72
# File 'lib/zold/wallet.rb', line 70

def to_s
  id.to_s
end

#to_textObject



78
79
80
# File 'lib/zold/wallet.rb', line 78

def to_text
  (@head.fetch + [''] + @txns.fetch.map(&:to_text)).join("\n")
end

#txnsObject



203
204
205
# File 'lib/zold/wallet.rb', line 203

def txns
  @txns.fetch
end