ic_agent 0.1.1

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,125 @@
1
+ require 'digest'
2
+ require 'json'
3
+ require 'ecdsa'
4
+ require 'bitcoin/trezor/mnemonic'
5
+ require 'ed25519'
6
+ require 'rbsecp256k1'
7
+ require 'ctf_party'
8
+ require 'base64'
9
+
10
+ module IcAgent
11
+ class Identity
12
+ attr_reader :privkey, :pubkey, :der_pubkey, :sk, :vk, :key_type
13
+
14
+ def initialize(privkey = '', type = 'ed25519', anonymous = false)
15
+ privkey = [privkey].pack('H*')
16
+ @anonymous = anonymous
17
+ if @anonymous
18
+ return
19
+ end
20
+ @key_type = type
21
+ if type == 'secp256k1'
22
+ data = privkey.length > 0 ? privkey : Random.new.bytes(32)
23
+ @sk = Secp256k1::PrivateKey.from_data(data)
24
+ @privkey = @sk.data.str2hex
25
+ context = Secp256k1::Context.create
26
+ @vk = context.key_pair_from_private_key(data)
27
+ @pubkey = @vk.public_key.uncompressed.str2hex
28
+ @der_pubkey = "#{IcAgent::IC_PUBKEY_SECP_DER_HERD}#{@pubkey}".hex2str
29
+ elsif type == 'ed25519'
30
+ @sk = privkey.length > 0 ? Ed25519::SigningKey.new(privkey) : Ed25519::SigningKey.generate
31
+ @privkey = @sk.keypair.unpack1('H*')[0..63]
32
+ @vk = @sk.verify_key
33
+ @pubkey = @vk.to_bytes.unpack1('H*')
34
+ @der_pubkey = "#{IcAgent::IC_PUBKEY_ED_DER_HEAD}#{@vk.to_bytes.unpack1('H*')}".hex2str
35
+ else
36
+ raise 'unsupported identity type'
37
+ end
38
+ end
39
+
40
+ def self.from_seed(mnemonic)
41
+ seed = Bitcoin::Trezor::Mnemonic.to_seed(mnemonic)
42
+ privkey = seed[0..63]
43
+ key_type = 'ed25519'
44
+ Identity.new(privkey = privkey, type = key_type)
45
+ end
46
+
47
+ def sender
48
+ if @anonymous
49
+ IcAgent::Principal.anonymous
50
+ else
51
+ IcAgent::Principal.self_authenticating(@der_pubkey)
52
+ end
53
+ end
54
+
55
+ def sign(msg)
56
+ if @anonymous
57
+ [nil, nil]
58
+ elsif @key_type == 'ed25519'
59
+ sig = @sk.sign(msg)
60
+ [@der_pubkey, sig]
61
+ elsif @key_type == 'secp256k1'
62
+ context = Secp256k1::Context.create
63
+ sig = context.sign(@sk, Digest::SHA256.digest(msg)).compact
64
+ [@der_pubkey, sig]
65
+ end
66
+ end
67
+
68
+ def verify(msg, sig)
69
+ if @anonymous
70
+ false
71
+ else
72
+ @vk.verify(sig, msg)
73
+ end
74
+ end
75
+
76
+ def to_pem
77
+ der = @key_type == 'secp256k1' ? "#{IcAgent::IC_PUBKEY_SECP_DER_HERD}#{@sk.data.unpack1('H*')}".hex2str : "#{IcAgent::IC_PUBKEY_ED_DER_HEAD}#{@sk.to_bytes.unpack1('H*')}".hex2str
78
+ b64 = Base64.strict_encode64(der)
79
+ lines = ["-----BEGIN PRIVATE KEY-----\n"]
80
+ lines.concat(b64.chars.each_slice(64).map(&:join).map { |line| "#{line}\n" })
81
+ lines << "-----END PRIVATE KEY-----\n"
82
+ lines.join
83
+ end
84
+
85
+ def to_s
86
+ "(#{@key_type}, #{@privkey}, #{@pubkey})"
87
+ end
88
+
89
+ alias inspect to_s
90
+ end
91
+
92
+ class DelegateIdentity
93
+ attr_reader :identity, :delegations, :der_pubkey
94
+
95
+ def initialize(identity, delegation)
96
+ @identity = identity
97
+ @delegations = delegation['delegations'].map { |d| d }
98
+ @der_pubkey = [delegation['publicKey']].pack('H*')
99
+ end
100
+
101
+ def sign(msg)
102
+ @identity.sign(msg)
103
+ end
104
+
105
+ def sender
106
+ Principal.self_authenticating(@der_pubkey)
107
+ end
108
+
109
+ def self.from_json(ic_identity, ic_delegation)
110
+ parsed_ic_identity = JSON.parse(ic_identity)
111
+ parsed_ic_delegation = JSON.parse(ic_delegation)
112
+
113
+ DelegateIdentity.new(
114
+ Identity.new(parsed_ic_identity[1][0...64]),
115
+ parsed_ic_delegation
116
+ )
117
+ end
118
+
119
+ def to_s
120
+ "(#{@identity.to_s},\n#{@delegations.to_s})"
121
+ end
122
+
123
+ alias inspect to_s
124
+ end
125
+ end
@@ -0,0 +1,112 @@
1
+ require 'zlib'
2
+ require 'base32'
3
+
4
+ module IcAgent
5
+ CRC_LENGTH_IN_BYTES = 4
6
+ HASH_LENGTH_IN_BYTES = 28
7
+ MAX_LENGTH_IN_BYTES = 29
8
+
9
+ class PrincipalSort
10
+ OpaqueId = 1
11
+ SelfAuthenticating = 2
12
+ DerivedId = 3
13
+ Anonymous = 4
14
+ # Unassigned
15
+ end
16
+
17
+ class Principal
18
+ attr_reader :len, :bytes, :is_principal, :hex
19
+
20
+ def initialize(bytes: ''.b)
21
+ @len = bytes.length
22
+ @bytes = bytes
23
+ @hex = @bytes.unpack1('H*').upcase
24
+ @is_principal = true
25
+ end
26
+
27
+ def self.management_canister
28
+ Principal.new
29
+ end
30
+
31
+ def self.self_authenticating(pubkey)
32
+ # check pubkey.size for is ed25519 or secp256k1
33
+ pubkey = [pubkey].pack('H*') if pubkey.size != 44 && pubkey.size != 88
34
+
35
+ hash_ = OpenSSL::Digest::SHA224.digest(pubkey)
36
+ hash_ += [PrincipalSort::SelfAuthenticating].pack('C')
37
+ Principal.new(bytes: hash_)
38
+ end
39
+
40
+ def self.anonymous
41
+ Principal.new(bytes: "\x04".b)
42
+ end
43
+
44
+ def self.from_str(s)
45
+ s1 = s.delete('-')
46
+ pad_len = ((s1.length / 8.0).ceil * 8) - s1.length
47
+ b = Base32.decode(s1.upcase + ('=' * pad_len))
48
+ raise 'principal length error' if b.length < CRC_LENGTH_IN_BYTES
49
+
50
+ p = Principal.new(bytes: b[CRC_LENGTH_IN_BYTES..-1])
51
+ raise 'principal format error' unless p.to_str == s
52
+
53
+ p
54
+ end
55
+
56
+ def self.from_hex(s)
57
+ Principal.new(bytes: [s].pack('H*'))
58
+ end
59
+
60
+ def to_str
61
+ checksum = Zlib.crc32(@bytes) & 0xFFFFFFFF
62
+ b = ''
63
+ b += [checksum].pack('N')
64
+ b += @bytes
65
+ s = Base32.encode(b).downcase.delete('=')
66
+ ret = ''
67
+ while s.length > 5
68
+ ret += s[0..4] + '-'
69
+ s = s[5..-1]
70
+ end
71
+ ret + s
72
+ end
73
+
74
+ def to_account_id(sub_account = 0)
75
+ AccountIdentifier.new(self, sub_account)
76
+ end
77
+
78
+ def to_s
79
+ to_str
80
+ end
81
+ end
82
+
83
+ class AccountIdentifier
84
+ attr_reader :bytes
85
+
86
+ def initialize(hash)
87
+ raise 'Invalid hash length' unless hash.length == 32
88
+
89
+ @bytes = hash
90
+ end
91
+
92
+ def to_str
93
+ '0x' + @bytes.unpack1('H*')
94
+ end
95
+
96
+ def to_s
97
+ to_str
98
+ end
99
+
100
+ def self.new(principal, sub_account = 0)
101
+ sha224 = Digest::SHA224.new
102
+ sha224 << "\naccount-id"
103
+ sha224 << principal.bytes
104
+ sub_account = [sub_account].pack('N')
105
+ sha224 << sub_account
106
+ hash = sha224.digest
107
+ checksum = Zlib.crc32(hash) & 0xFFFFFFFF
108
+ account = [checksum].pack('N') + hash
109
+ AccountIdentifier.new(account)
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,43 @@
1
+ require_relative 'principal'
2
+ require_relative 'certificate'
3
+ require 'leb128'
4
+ require 'cbor'
5
+
6
+ module IcAgent
7
+ class SyetemState
8
+ def self.time(agent, canister_id)
9
+ cert = agent.read_state_raw(canister_id, [['time']])
10
+ timestamp = Certificate.lookup(['time'], cert)
11
+ str_io = StringIO.new(timestamp)
12
+ LEB128.decode_signed(str_io)
13
+ end
14
+
15
+ def self.subnet_public_key(agent, canister_id, subnet_id)
16
+ path = ['subnet', Principal.from_str(subnet_id).bytes, 'public_key']
17
+ cert = agent.read_state_raw(canister_id, [path])
18
+ pubkey = Certificate.lookup(path, cert)
19
+ pubkey.str2hex
20
+ end
21
+
22
+ def self.subnet_canister_ranges(agent, canister_id, subnet_id)
23
+ path = ['subnet', Principal.from_str(subnet_id).bytes, 'canister_ranges']
24
+ cert = agent.read_state_raw(canister_id, [path])
25
+ ranges = Certificate.lookup(path, cert)
26
+ CBOR.decode(ranges).value.map { |range| range.map { |item| Principal.new(bytes: item) } }
27
+ end
28
+
29
+ def self.canister_module_hash(agent, canister_id)
30
+ path = ['canister', Principal.from_str(canister_id).bytes, 'module_hash']
31
+ cert = agent.read_state_raw(canister_id, [path])
32
+ module_hash = Certificate.lookup(path, cert)
33
+ module_hash.str2hex
34
+ end
35
+
36
+ def self.canister_controllers(agent, canister_id)
37
+ path = ['canister', Principal.from_str(canister_id).bytes, 'controllers']
38
+ cert = agent.read_state_raw(canister_id, [path])
39
+ controllers = Certificate.lookup(path, cert)
40
+ CBOR.decode(controllers).value.map { |item| Principal.new(bytes: item) }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,71 @@
1
+ require 'digest/sha2'
2
+ require 'leb128'
3
+
4
+ module IcAgent
5
+ module Utils
6
+ def self.encode_list(l)
7
+ ret = ''
8
+ l.each do |item|
9
+ v = item
10
+ if item.is_a?(Array)
11
+ v = encode_list(item)
12
+ end
13
+ if item.is_a?(Integer)
14
+ v = LEB128.encode_signed(v)
15
+ end
16
+ if item.is_a?(String)
17
+ v = item
18
+ end
19
+ ret += Digest::SHA256.digest(v)
20
+ end
21
+ ret
22
+ end
23
+
24
+ # used for sort record by key
25
+ def self.label_hash(s)
26
+ if s =~ /(^_\d+_$)|(^_0x[0-9a-fA-F]+_$)/
27
+ num = s[1..-2]
28
+ begin
29
+ if num.start_with?("0x")
30
+ num = num.to_i(16)
31
+ else
32
+ num = num.to_i
33
+ end
34
+ rescue
35
+ # fallback
36
+ end
37
+ if num.is_a?(Integer) && num >= 0 && num < 2**32
38
+ return num
39
+ end
40
+ end
41
+ idl_hash(s)
42
+ end
43
+
44
+ def self.idl_hash(s)
45
+ h = 0
46
+ s.bytes.each do |c|
47
+ h = (h * 223 + c) % 2**32
48
+ end
49
+ h
50
+ end
51
+
52
+ def self.to_request_id(d)
53
+ return nil unless d.is_a?(Hash)
54
+
55
+ vec = []
56
+
57
+ d.each do |k, v|
58
+ v = encode_list(v) if v.is_a?(Array)
59
+ v = LEB128.encode_signed(v).string if v.is_a?(Integer)
60
+ k = k.hex unless k.is_a?(String)
61
+ v = v.str2hex unless v.is_a?(String)
62
+ h_k = Digest::SHA256.digest(k)
63
+ h_v = Digest::SHA256.digest(v)
64
+ vec << h_k + h_v
65
+ end
66
+ s = vec.sort.join
67
+ Digest::SHA256.digest(s)
68
+ end
69
+ end
70
+ end
71
+
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IcAgent
4
+ VERSION = '0.1.1'
5
+ end
data/lib/ic_agent.rb ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'treetop'
4
+
5
+ require_relative 'ic_agent/version'
6
+ require_relative 'ic_agent/principal'
7
+ require_relative 'ic_agent/identity'
8
+ require_relative 'ic_agent/client'
9
+ require_relative 'ic_agent/utils'
10
+ require_relative 'ic_agent/candid'
11
+ require_relative 'ic_agent/agent'
12
+ require_relative 'ic_agent/certificate'
13
+ require_relative 'ic_agent/system_state'
14
+ require_relative 'ic_agent/canister'
15
+
16
+ require_relative 'ic_agent/ast/nodes/named_nodes'
17
+ require_relative 'ic_agent/ast/nodes/string_literal'
18
+ require_relative 'ic_agent/ast/parser'
19
+ require_relative 'ic_agent/ast/writer'
20
+ require_relative 'ic_agent/ast/assembler'
21
+
22
+ require_relative 'ic_agent/common/ledger'
23
+ require_relative 'ic_agent/common/cycles_wallet'
24
+ require_relative 'ic_agent/common/governance'
25
+ require_relative 'ic_agent/common/management'
26
+
27
+ module IcAgent
28
+ class Error < StandardError; end
29
+ class ValueError < StandardError; end
30
+ class TypeError < StandardError; end
31
+
32
+ IC_REQUEST_DOMAIN_SEPARATOR = "\x0Aic-request".freeze
33
+ IC_ROOT_KEY = "\x4E\x9A\xF9\x9F\x06\x13\x26\x81\xE7\xD2\x55\x2A\x26\x17\x98\x51\xE9\xC3\x79\xB3\xC7\xBE\x88\x27\xB8\x35\x17\xFC\x84\x4E\x4C\x4F".freeze
34
+ IC_PUBKEY_ED_DER_HEAD = '302a300506032b6570032100'
35
+ IC_PUBKEY_SECP_DER_HERD = '3056301006072a8648ce3d020106052b8104000a034200'
36
+ DEFAULT_POLL_TIMEOUT_SECS = 60
37
+ end
data/sig/ic_agent.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module IcAgent
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,288 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ic_agent
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Terry.Tu
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-06-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: base32
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.3.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.3.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: bitcoin-ruby
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.20
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.0.20
41
+ - !ruby/object:Gem::Dependency
42
+ name: cbor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.5.9.6
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.5.9.6
55
+ - !ruby/object:Gem::Dependency
56
+ name: ctf-party
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: ecdsa
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: ed25519
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: faraday
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.7'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.7'
111
+ - !ruby/object:Gem::Dependency
112
+ name: leb128
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rbsecp256k1
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '6.0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '6.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: ruby-enum
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 0.9.0
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 0.9.0
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubytree
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '2.0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '2.0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: treetop
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '1.6'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '1.6'
181
+ - !ruby/object:Gem::Dependency
182
+ name: byebug
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '11.1'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '11.1'
195
+ - !ruby/object:Gem::Dependency
196
+ name: pry
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: rspec
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - "~>"
214
+ - !ruby/object:Gem::Version
215
+ version: '3.2'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: '3.2'
223
+ description: ICP Agent.
224
+ email:
225
+ - tuminfei1981@gmail.com
226
+ executables: []
227
+ extensions: []
228
+ extra_rdoc_files: []
229
+ files:
230
+ - ".ruby-version"
231
+ - CODE_OF_CONDUCT.md
232
+ - Dockerfile
233
+ - Gemfile
234
+ - Gemfile.lock
235
+ - LICENSE.txt
236
+ - README.md
237
+ - Rakefile
238
+ - ic_agent.gemspec
239
+ - lib/ic_agent.rb
240
+ - lib/ic_agent/agent.rb
241
+ - lib/ic_agent/ast/assembler.rb
242
+ - lib/ic_agent/ast/did_grammar.treetop
243
+ - lib/ic_agent/ast/did_grammar_v1.treetop
244
+ - lib/ic_agent/ast/nodes/named_nodes.rb
245
+ - lib/ic_agent/ast/nodes/string_literal.rb
246
+ - lib/ic_agent/ast/parser.rb
247
+ - lib/ic_agent/ast/writer.rb
248
+ - lib/ic_agent/candid.rb
249
+ - lib/ic_agent/canister.rb
250
+ - lib/ic_agent/certificate.rb
251
+ - lib/ic_agent/client.rb
252
+ - lib/ic_agent/common/cycles_wallet.rb
253
+ - lib/ic_agent/common/governance.rb
254
+ - lib/ic_agent/common/ledger.rb
255
+ - lib/ic_agent/common/management.rb
256
+ - lib/ic_agent/identity.rb
257
+ - lib/ic_agent/principal.rb
258
+ - lib/ic_agent/system_state.rb
259
+ - lib/ic_agent/utils.rb
260
+ - lib/ic_agent/version.rb
261
+ - sig/ic_agent.rbs
262
+ homepage: https://github.com/tuminfei/ic_agent
263
+ licenses:
264
+ - MIT
265
+ metadata:
266
+ homepage_uri: https://github.com/tuminfei/ic_agent
267
+ source_code_uri: https://github.com/tuminfei/ic_agent
268
+ changelog_uri: https://github.com/tuminfei/ic_agent
269
+ post_install_message:
270
+ rdoc_options: []
271
+ require_paths:
272
+ - lib
273
+ required_ruby_version: !ruby/object:Gem::Requirement
274
+ requirements:
275
+ - - ">="
276
+ - !ruby/object:Gem::Version
277
+ version: 2.6.0
278
+ required_rubygems_version: !ruby/object:Gem::Requirement
279
+ requirements:
280
+ - - ">="
281
+ - !ruby/object:Gem::Version
282
+ version: '0'
283
+ requirements: []
284
+ rubygems_version: 3.1.6
285
+ signing_key:
286
+ specification_version: 4
287
+ summary: ICP Agent
288
+ test_files: []