glueby 0.4.4 → 0.6.0

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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +477 -387
  3. data/glueby.gemspec +33 -33
  4. data/lib/generators/glueby/contract/templates/initializer.rb.erb +8 -8
  5. data/lib/generators/glueby/contract/templates/key_table.rb.erb +16 -16
  6. data/lib/generators/glueby/contract/templates/timestamp_table.rb.erb +4 -1
  7. data/lib/generators/glueby/contract/templates/utxo_table.rb.erb +16 -16
  8. data/lib/glueby/block_syncer.rb +97 -97
  9. data/lib/glueby/configuration.rb +32 -2
  10. data/lib/glueby/contract/active_record/timestamp.rb +3 -1
  11. data/lib/glueby/contract/errors.rb +1 -0
  12. data/lib/glueby/contract/fee_estimator.rb +5 -1
  13. data/lib/glueby/contract/timestamp/syncer.rb +13 -13
  14. data/lib/glueby/contract/timestamp.rb +153 -102
  15. data/lib/glueby/contract/token.rb +270 -244
  16. data/lib/glueby/contract/tx_builder.rb +97 -30
  17. data/lib/glueby/fee_provider/tasks.rb +140 -140
  18. data/lib/glueby/fee_provider.rb +11 -0
  19. data/lib/glueby/internal/wallet/abstract_wallet_adapter.rb +153 -151
  20. data/lib/glueby/internal/wallet/active_record/utxo.rb +51 -51
  21. data/lib/glueby/internal/wallet/active_record_wallet_adapter/syncer.rb +13 -13
  22. data/lib/glueby/internal/wallet/active_record_wallet_adapter.rb +159 -151
  23. data/lib/glueby/internal/wallet/tapyrus_core_wallet_adapter.rb +194 -186
  24. data/lib/glueby/internal/wallet.rb +164 -162
  25. data/lib/glueby/railtie.rb +10 -9
  26. data/lib/glueby/utxo_provider/tasks.rb +135 -0
  27. data/lib/glueby/utxo_provider.rb +85 -0
  28. data/lib/glueby/version.rb +3 -3
  29. data/lib/glueby.rb +40 -39
  30. data/lib/tasks/glueby/block_syncer.rake +28 -28
  31. data/lib/tasks/glueby/contract/timestamp.rake +46 -39
  32. data/lib/tasks/glueby/fee_provider.rake +18 -18
  33. data/lib/tasks/glueby/utxo_provider.rake +18 -0
  34. metadata +5 -2
@@ -1,151 +1,159 @@
1
- # frozen_string_literal: true
2
-
3
- require 'securerandom'
4
-
5
- module Glueby
6
- module Internal
7
- class Wallet
8
- # ActiveRecordWalletAdapter
9
- #
10
- # This class represents a wallet adapter that use Active Record to manage wallet and utxos.
11
- # To use this wallet adapter, you should do the following steps:
12
- #
13
- # (1) Generate migrations for wallets, keys, utxos tables.
14
- # The generator `glueby:contract:wallet_adapter` is available for migration.
15
- # ```
16
- # rails g glueby:contract:wallet_adapter
17
- # ```
18
- # this generator generates 3 files to create tables used by ActiveRecordWalletAdatper.
19
- # then, migrate them
20
- # ```
21
- # $ rails db:migrate
22
- # ```
23
- #
24
- # (2) Add configuration for activerecord
25
- # ```
26
- # config = {adapter: 'activerecord', schema: 'http', host: '127.0.0.1', port: 12381, user: 'user', password: 'pass'}
27
- # Glueby::Wallet.configure(config)
28
- # ```
29
- #
30
- # (3) Generate wallet and receive address
31
- # ```
32
- # alice_wallet = Glueby::Wallet.create
33
- # address = alice_wallet.internal_wallet.receive_address
34
- # ```
35
- # `Glueby::Internal::Wallet#receive_address` returns Base58 encoded Tapyrus address like '1CY6TSSARn8rAFD9chCghX5B7j4PKR8S1a'.
36
- #
37
- # (4) Send TPC to created address and import into wallet.
38
- # In general, ActiveRecordWalletAdapter handle only utxos generated by glueby.
39
- # So, to start to use wallet, some external utxo should be imported into the wallet first.
40
- # This step should be done by external transaction without Glueby::Wallet, such as 'sendtoaddress' or 'generatetoaddress' RPC command of Tapyrus Core
41
- # ```
42
- # $ tapyrus-cli sendtoaddress 1CY6TSSARn8rAFD9chCghX5B7j4PKR8S1a 1
43
- # 1740af9f65ffd8537bdd06ccfa911bf1f4d6833222807d29c99d72b47838917d
44
- # ```
45
- #
46
- # then, import into wallet by rake task `glueby:contract:wallet_adapter:import_tx` or `glueby:contract:wallet_adapter:import_block`
47
- # ```
48
- # $ rails "glueby:contract:wallet_adapter:import_tx[1740af9f65ffd8537bdd06ccfa911bf1f4d6833222807d29c99d72b47838917d]""
49
- # ```
50
- #
51
- # (5) You are ready to use ActiveRecordWalletAdatper, check `Glueby::Internal::Wallet#list_unspent` or `Glueby::Wallet#balances`
52
- # ```
53
- # alice_wallet = Glueby::Wallet.create
54
- # alice_wallet.balances
55
- # ```
56
- class ActiveRecordWalletAdapter < AbstractWalletAdapter
57
-
58
- autoload :Syncer, 'glueby/internal/wallet/active_record_wallet_adapter/syncer'
59
-
60
- def create_wallet(wallet_id = nil)
61
- wallet_id = SecureRandom.hex(16) unless wallet_id
62
- begin
63
- AR::Wallet.create!(wallet_id: wallet_id)
64
- rescue ActiveRecord::RecordInvalid => _
65
- raise Errors::WalletAlreadyCreated, "wallet_id '#{wallet_id}' is already exists"
66
- end
67
- wallet_id
68
- end
69
-
70
- def delete_wallet(wallet_id)
71
- AR::Wallet.destroy_by(wallet_id: wallet_id)
72
- end
73
-
74
- def load_wallet(wallet_id)
75
- raise Errors::WalletNotFound, "Wallet #{wallet_id} does not found" unless AR::Wallet.where(wallet_id: wallet_id).exists?
76
- end
77
-
78
- def unload_wallet(wallet_id)
79
- end
80
-
81
- def wallets
82
- AR::Wallet.all.map(&:wallet_id).sort
83
- end
84
-
85
- def balance(wallet_id, only_finalized = true)
86
- wallet = AR::Wallet.find_by(wallet_id: wallet_id)
87
- utxos = wallet.utxos
88
- utxos = utxos.where(status: :finalized) if only_finalized
89
- utxos.sum(&:value)
90
- end
91
-
92
- def list_unspent(wallet_id, only_finalized = true, label = nil)
93
- wallet = AR::Wallet.find_by(wallet_id: wallet_id)
94
- utxos = wallet.utxos
95
- utxos = utxos.where(status: :finalized) if only_finalized
96
- utxos = utxos.where(label: label) if label && (label != :unlabeled)
97
- utxos = utxos.where(label: nil) if label == :unlabeled
98
- utxos.map do |utxo|
99
- {
100
- txid: utxo.txid,
101
- vout: utxo.index,
102
- script_pubkey: utxo.script_pubkey,
103
- color_id: utxo.color_id,
104
- amount: utxo.value,
105
- finalized: utxo.status == 'finalized'
106
- }
107
- end
108
- end
109
-
110
- def sign_tx(wallet_id, tx, prevtxs = [], sighashtype: Tapyrus::SIGHASH_TYPE[:all])
111
- wallet = AR::Wallet.find_by(wallet_id: wallet_id)
112
- wallet.sign(tx, prevtxs, sighashtype: sighashtype)
113
- end
114
-
115
- def broadcast(wallet_id, tx, &block)
116
- ::ActiveRecord::Base.transaction do
117
- AR::Utxo.destroy_for_inputs(tx)
118
- AR::Utxo.create_or_update_for_outputs(tx, status: :broadcasted)
119
- block.call(tx) if block
120
- Glueby::Internal::RPC.client.sendrawtransaction(tx.to_hex)
121
- end
122
- end
123
-
124
- def receive_address(wallet_id, label = nil)
125
- wallet = AR::Wallet.find_by(wallet_id: wallet_id)
126
- key = wallet.keys.create(purpose: :receive, label: label)
127
- key.address
128
- end
129
-
130
- def change_address(wallet_id)
131
- wallet = AR::Wallet.find_by(wallet_id: wallet_id)
132
- key = wallet.keys.create(purpose: :change)
133
- key.address
134
- end
135
-
136
- def create_pubkey(wallet_id)
137
- wallet = AR::Wallet.find_by(wallet_id: wallet_id)
138
- key = wallet.keys.create(purpose: :receive)
139
- Tapyrus::Key.new(pubkey: key.public_key)
140
- end
141
-
142
- def get_addresses(wallet_id, label = nil)
143
- wallet = AR::Wallet.find_by(wallet_id: wallet_id)
144
- keys = wallet.keys
145
- keys = keys.where(label: label) if label
146
- keys.map(&:address)
147
- end
148
- end
149
- end
150
- end
151
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Glueby
6
+ module Internal
7
+ class Wallet
8
+ # ActiveRecordWalletAdapter
9
+ #
10
+ # This class represents a wallet adapter that use Active Record to manage wallet and utxos.
11
+ # To use this wallet adapter, you should do the following steps:
12
+ #
13
+ # (1) Generate migrations for wallets, keys, utxos tables.
14
+ # The generator `glueby:contract:wallet_adapter` is available for migration.
15
+ # ```
16
+ # rails g glueby:contract:wallet_adapter
17
+ # ```
18
+ # this generator generates 3 files to create tables used by ActiveRecordWalletAdatper.
19
+ # then, migrate them
20
+ # ```
21
+ # $ rails db:migrate
22
+ # ```
23
+ #
24
+ # (2) Add configuration for activerecord
25
+ # ```
26
+ # config = {adapter: 'activerecord', schema: 'http', host: '127.0.0.1', port: 12381, user: 'user', password: 'pass'}
27
+ # Glueby::Wallet.configure(config)
28
+ # ```
29
+ #
30
+ # (3) Generate wallet and receive address
31
+ # ```
32
+ # alice_wallet = Glueby::Wallet.create
33
+ # address = alice_wallet.internal_wallet.receive_address
34
+ # ```
35
+ # `Glueby::Internal::Wallet#receive_address` returns Base58 encoded Tapyrus address like '1CY6TSSARn8rAFD9chCghX5B7j4PKR8S1a'.
36
+ #
37
+ # (4) Send TPC to created address and import into wallet.
38
+ # In general, ActiveRecordWalletAdapter handle only utxos generated by glueby.
39
+ # So, to start to use wallet, some external utxo should be imported into the wallet first.
40
+ # This step should be done by external transaction without Glueby::Wallet, such as 'sendtoaddress' or 'generatetoaddress' RPC command of Tapyrus Core
41
+ # ```
42
+ # $ tapyrus-cli sendtoaddress 1CY6TSSARn8rAFD9chCghX5B7j4PKR8S1a 1
43
+ # 1740af9f65ffd8537bdd06ccfa911bf1f4d6833222807d29c99d72b47838917d
44
+ # ```
45
+ #
46
+ # then, import into wallet by rake task `glueby:contract:wallet_adapter:import_tx` or `glueby:contract:wallet_adapter:import_block`
47
+ # ```
48
+ # $ rails "glueby:contract:wallet_adapter:import_tx[1740af9f65ffd8537bdd06ccfa911bf1f4d6833222807d29c99d72b47838917d]""
49
+ # ```
50
+ #
51
+ # (5) You are ready to use ActiveRecordWalletAdatper, check `Glueby::Internal::Wallet#list_unspent` or `Glueby::Wallet#balances`
52
+ # ```
53
+ # alice_wallet = Glueby::Wallet.create
54
+ # alice_wallet.balances
55
+ # ```
56
+ class ActiveRecordWalletAdapter < AbstractWalletAdapter
57
+
58
+ autoload :Syncer, 'glueby/internal/wallet/active_record_wallet_adapter/syncer'
59
+
60
+ def create_wallet(wallet_id = nil)
61
+ wallet_id = SecureRandom.hex(16) unless wallet_id
62
+ begin
63
+ AR::Wallet.create!(wallet_id: wallet_id)
64
+ rescue ActiveRecord::RecordInvalid => _
65
+ raise Errors::WalletAlreadyCreated, "wallet_id '#{wallet_id}' is already exists"
66
+ end
67
+ wallet_id
68
+ end
69
+
70
+ def delete_wallet(wallet_id)
71
+ AR::Wallet.destroy_by(wallet_id: wallet_id)
72
+ end
73
+
74
+ def load_wallet(wallet_id)
75
+ raise Errors::WalletNotFound, "Wallet #{wallet_id} does not found" unless AR::Wallet.where(wallet_id: wallet_id).exists?
76
+ end
77
+
78
+ def unload_wallet(wallet_id)
79
+ end
80
+
81
+ def wallets
82
+ AR::Wallet.all.map(&:wallet_id).sort
83
+ end
84
+
85
+ def balance(wallet_id, only_finalized = true)
86
+ wallet = AR::Wallet.find_by(wallet_id: wallet_id)
87
+ utxos = wallet.utxos
88
+ utxos = utxos.where(status: :finalized) if only_finalized
89
+ utxos.sum(&:value)
90
+ end
91
+
92
+ def list_unspent(wallet_id, only_finalized = true, label = nil)
93
+ wallet = AR::Wallet.find_by(wallet_id: wallet_id)
94
+ utxos = wallet.utxos
95
+ utxos = utxos.where(status: :finalized) if only_finalized
96
+
97
+ if [:unlabeled, nil].include?(label)
98
+ utxos = utxos.where(label: nil)
99
+ elsif label && (label != :all)
100
+ utxos = utxos.where(label: label)
101
+ else
102
+ utxos
103
+ end
104
+
105
+ utxos.map do |utxo|
106
+ {
107
+ txid: utxo.txid,
108
+ vout: utxo.index,
109
+ script_pubkey: utxo.script_pubkey,
110
+ color_id: utxo.color_id,
111
+ amount: utxo.value,
112
+ finalized: utxo.status == 'finalized',
113
+ label: utxo.label
114
+ }
115
+ end
116
+ end
117
+
118
+ def sign_tx(wallet_id, tx, prevtxs = [], sighashtype: Tapyrus::SIGHASH_TYPE[:all])
119
+ wallet = AR::Wallet.find_by(wallet_id: wallet_id)
120
+ wallet.sign(tx, prevtxs, sighashtype: sighashtype)
121
+ end
122
+
123
+ def broadcast(wallet_id, tx, &block)
124
+ ::ActiveRecord::Base.transaction do
125
+ AR::Utxo.destroy_for_inputs(tx)
126
+ AR::Utxo.create_or_update_for_outputs(tx, status: :broadcasted)
127
+ block.call(tx) if block
128
+ Glueby::Internal::RPC.client.sendrawtransaction(tx.to_hex)
129
+ end
130
+ end
131
+
132
+ def receive_address(wallet_id, label = nil)
133
+ wallet = AR::Wallet.find_by(wallet_id: wallet_id)
134
+ key = wallet.keys.create(purpose: :receive, label: label)
135
+ key.address
136
+ end
137
+
138
+ def change_address(wallet_id)
139
+ wallet = AR::Wallet.find_by(wallet_id: wallet_id)
140
+ key = wallet.keys.create(purpose: :change)
141
+ key.address
142
+ end
143
+
144
+ def create_pubkey(wallet_id)
145
+ wallet = AR::Wallet.find_by(wallet_id: wallet_id)
146
+ key = wallet.keys.create(purpose: :receive)
147
+ Tapyrus::Key.new(pubkey: key.public_key)
148
+ end
149
+
150
+ def get_addresses(wallet_id, label = nil)
151
+ wallet = AR::Wallet.find_by(wallet_id: wallet_id)
152
+ keys = wallet.keys
153
+ keys = keys.where(label: label) if label
154
+ keys.map(&:address)
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end