chain-sdk 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f0aa5bb32b142eae9a8ccad181ddfa907e75215b
4
+ data.tar.gz: dd2f336ad6c531de0cee5bf0ceb525b4b4c3f750
5
+ SHA512:
6
+ metadata.gz: 7a888f2ff7604a2edb0d5ec4713e07e6086a774cad048e529073be20630e0339450b73d3fb238cea744b8cd3c2540282cc8d10e4851880c05668009de3108527
7
+ data.tar.gz: 7f8c2c45ae8ed6fc39914df1c34f803ab128eea95b36d1c4008497aa8eb43341171a3d28e07d5cc120424248291402a81e523c92850e569fb2e2180caa06620c
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # Chain Ruby SDK
2
+
3
+ ## Usage
4
+
5
+ ### Installing the library
6
+
7
+ #### Via Rubygems
8
+
9
+ TBA
10
+
11
+ #### Via downloaded .gem
12
+
13
+ Install the gem into your gem library:
14
+
15
+ ```
16
+ gem install --local chain-sdk-<VERSION>.gem
17
+ ```
18
+
19
+ ### In your code
20
+
21
+ ```
22
+ require 'chain'
23
+
24
+ chain = Chain::Client.new
25
+ ```
26
+
27
+ ## Testing
28
+
29
+ To run integration tests, run a configured, empty Chain Core on http://localhost:1999. Then run:
30
+
31
+ ```
32
+ bundle exec rspec
33
+ ```
@@ -0,0 +1,66 @@
1
+ require_relative './client_module'
2
+ require_relative './query'
3
+ require_relative './response_object'
4
+
5
+ module Chain
6
+ class AccessToken < ResponseObject
7
+
8
+ # @!attribute [r] id
9
+ # User specified, unique identifier.
10
+ # @return [String]
11
+ attrib :id
12
+
13
+ # @!attribute [r] token
14
+ # Only returned in the response from {ClientModule.create}.
15
+ # @return [String]
16
+ attrib :token
17
+
18
+ # @!attribute [r] type
19
+ # Either 'client' or 'network'.
20
+ # @return [String]
21
+ attrib :type
22
+
23
+ # @!attribute [r] created_at
24
+ # Timestamp of token creation.
25
+ # @return [Time]
26
+ attrib(:created_at) { |raw| Time.parse(raw) }
27
+
28
+ class ClientModule < Chain::ClientModule
29
+
30
+ # @return [AccessToken]
31
+ def create(type:, id:)
32
+ AccessToken.new(client.conn.request(
33
+ 'create-access-token',
34
+ {type: type, id: id}
35
+ ))
36
+ end
37
+
38
+ # @param [Hash] opts
39
+ # @return [Query]
40
+ def query(opts = {})
41
+ Query.new(client, opts)
42
+ end
43
+
44
+ # Delete the access token specified.
45
+ # @param [String] id access token ID
46
+ # @raise [APIError]
47
+ # @return [void]
48
+ def delete(id)
49
+ client.conn.request('delete-access-token', {id: id})
50
+ return
51
+ end
52
+
53
+ class Query < Chain::Query
54
+ def fetch(query)
55
+ client.conn.request('list-access-tokens', query)
56
+ end
57
+
58
+ def translate(raw)
59
+ AccessToken.new(raw)
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,101 @@
1
+ require_relative './client_module'
2
+ require_relative './control_program'
3
+ require_relative './errors'
4
+ require_relative './query'
5
+ require_relative './response_object'
6
+
7
+ module Chain
8
+ class Account < ResponseObject
9
+
10
+ # @!attribute [r] id
11
+ # Unique account identifier.
12
+ # @return [String]
13
+ attrib :id
14
+
15
+ # @!attribute [r] alias
16
+ # User specified, unique identifier.
17
+ # @return [String]
18
+ attrib :alias
19
+
20
+ # @!attribute [r] keys
21
+ # The list of keys used to create control programs under the account.
22
+ # Signatures from these keys are required for spending funds held in the account.
23
+ # @return [Array<Key>]
24
+ attrib(:keys) { |raw| raw.map { |v| Key.new(v) } }
25
+
26
+ # @!attribute [r] quorum
27
+ # The number of keys required to sign transactions for the account.
28
+ # @return [Integer]
29
+ attrib :quorum
30
+
31
+ # @!attribute [r] tags
32
+ # User-specified tag structure for the account.
33
+ # @return [Hash]
34
+ attrib :tags
35
+
36
+ class ClientModule < Chain::ClientModule
37
+ # @param [Hash] opts
38
+ # @return [Account]
39
+ def create(opts)
40
+ opts = {client_token: SecureRandom.uuid}.merge(opts)
41
+ client.conn.singleton_batch_request('create-account', [opts]) { |item| Account.new(item) }
42
+ end
43
+
44
+ # @param [Array<Hash>] opts
45
+ # @return [Array<Account>]
46
+ def create_batch(opts)
47
+ opts = opts.map { |i| {client_token: SecureRandom.uuid}.merge(i) }
48
+ client.conn.batch_request('create-account', opts) { |item| Account.new(item) }
49
+ end
50
+
51
+ # @param [Hash] opts
52
+ # @return [ControlProgram]
53
+ def create_control_program(opts = {})
54
+ # We don't use keyword params here because 'alias' is a Ruby reserverd
55
+ # word.
56
+ params = {}
57
+ params[:account_alias] = opts[:alias] if opts.key?(:alias)
58
+ params[:account_id] = opts[:id] if opts.key?(:id)
59
+
60
+ client.conn.singleton_batch_request(
61
+ 'create-control-program',
62
+ [{type: :account, params: params}]
63
+ ) { |item| ControlProgram.new(item) }
64
+ end
65
+
66
+ # @param [Hash] query
67
+ # @return [Query]
68
+ def query(query = {})
69
+ Query.new(client, query)
70
+ end
71
+ end
72
+
73
+ class Query < Chain::Query
74
+ def fetch(query)
75
+ client.conn.request('list-accounts', query)
76
+ end
77
+
78
+ def translate(raw)
79
+ Account.new(raw)
80
+ end
81
+ end
82
+
83
+ class Key < ResponseObject
84
+ # @!attribute [r] root_xpub
85
+ # Hex-encoded representation of the root extended public key.
86
+ # @return [String]
87
+ attrib :root_xpub
88
+
89
+ # @!attribute [r] account_xpub
90
+ # The extended public key used to create control programs for the account.
91
+ # @return [String]
92
+ attrib :account_xpub
93
+
94
+ # @!attribute [r] account_derivation_path
95
+ # The derivation path of the extended key.
96
+ # @return [String]
97
+ attrib :account_derivation_path
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,103 @@
1
+ require 'securerandom'
2
+
3
+ require_relative './client_module'
4
+ require_relative './errors'
5
+ require_relative './query'
6
+ require_relative './response_object'
7
+
8
+ module Chain
9
+ class Asset < ResponseObject
10
+
11
+ # @!attribute [r] id
12
+ # Globally unique identifier of the asset.
13
+ # Asset version 1 specifies the asset id as the hash of:
14
+ # - the asset version
15
+ # - the asset's issuance program
16
+ # - the core's VM version
17
+ # - the hash of the network's initial block
18
+ # @return [String]
19
+ attrib :id
20
+
21
+ # @!attribute [r] alias
22
+ # User specified, unique identifier.
23
+ # @return [String]
24
+ attrib :alias
25
+
26
+ # @!attribute [r] issuance_program
27
+ # @return [String]
28
+ attrib :issuance_program
29
+
30
+ # @!attribute [r] keys
31
+ # @return [Array<Key>]
32
+ attrib(:keys) { |raw| raw.map { |v| Key.new(v) } }
33
+
34
+ # @!attribute [r] quorum
35
+ # @return [Integer]
36
+ attrib :quorum
37
+
38
+ # @!attribute [r] definition
39
+ # User-specified, arbitrary/unstructured data visible across
40
+ # blockchain networks. Version 1 assets specify the definition in their
41
+ # issuance programs, rendering the definition immutable.
42
+ # @return [Hash]
43
+ attrib :definition
44
+
45
+ # @!attribute [r] tags
46
+ # @return [Hash]
47
+ attrib :tags
48
+
49
+ # @!attribute [r] is_local
50
+ # @return [Boolean]
51
+ attrib :is_local
52
+
53
+ class ClientModule < Chain::ClientModule
54
+ # @param [Hash] opts
55
+ # @return [Asset]
56
+ def create(opts)
57
+ opts = {client_token: SecureRandom.uuid}.merge(opts)
58
+ client.conn.singleton_batch_request('create-asset', [opts]) { |item| Asset.new(item) }
59
+ end
60
+
61
+ # @param [Hash] opts
62
+ # @return [Array<Asset>]
63
+ def create_batch(opts)
64
+ opts = opts.map { |i| {client_token: SecureRandom.uuid}.merge(i) }
65
+ client.conn.batch_request('create-asset', opts) { |item| Asset.new(item) }
66
+ end
67
+
68
+ # @param [Hash] query
69
+ # @return [Query]
70
+ def query(query = {})
71
+ Query.new(client, query)
72
+ end
73
+ end
74
+
75
+ class Query < Chain::Query
76
+ def fetch(query)
77
+ client.conn.request('list-assets', query)
78
+ end
79
+
80
+ def translate(raw)
81
+ Asset.new(raw)
82
+ end
83
+ end
84
+
85
+ class Key < ResponseObject
86
+ # @!attribute [r] root_xpub
87
+ # Hex-encoded representation of the root extended public key.
88
+ # @return [String]
89
+ attrib :root_xpub
90
+
91
+ # @!attribute [r] asset_pubkey
92
+ # The derived public key, used in the asset's issuance program.
93
+ # @return [String]
94
+ attrib :asset_pubkey
95
+
96
+ # @!attribute [r] asset_derivation_path
97
+ # The derivation path of the extended key.
98
+ # @return [String]
99
+ attrib :asset_derivation_path
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,36 @@
1
+ require_relative './client_module'
2
+ require_relative './response_object'
3
+ require_relative './query'
4
+
5
+ module Chain
6
+ class Balance < ResponseObject
7
+
8
+ # @!attribute [r] amount
9
+ # Sum of the unspent outputs.
10
+ # @return [Integer]
11
+ attrib :amount
12
+
13
+ # @!attribute [r] sum_by
14
+ # List of parameters on which to sum unspent outputs.
15
+ # @return [Hash<String => String>]
16
+ attrib :sum_by
17
+
18
+ class ClientModule < Chain::ClientModule
19
+ # @param [Hash] query
20
+ # @return [Query]
21
+ def query(query = {})
22
+ Query.new(client, query)
23
+ end
24
+ end
25
+
26
+ class Query < Chain::Query
27
+ def fetch(query)
28
+ client.conn.request('list-balances', query)
29
+ end
30
+
31
+ def translate(raw)
32
+ Balance.new(raw)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,21 @@
1
+ def ensure_key_sorting(h)
2
+ sorted = h.keys.sort
3
+ return h if sorted == h.keys
4
+ sorted.reduce({}) { |memo, k| memo[k] = h[k]; memo }
5
+ end
6
+
7
+ module Chain
8
+ class BatchResponse
9
+ def initialize(successes: {}, errors: {}, response: nil)
10
+ @successes = ensure_key_sorting(successes)
11
+ @errors = ensure_key_sorting(errors)
12
+ @response = response
13
+ end
14
+
15
+ def size
16
+ successes.size + errors.size
17
+ end
18
+
19
+ attr_reader :successes, :errors, :response
20
+ end
21
+ end
@@ -0,0 +1,75 @@
1
+ require_relative './access_token'
2
+ require_relative './account'
3
+ require_relative './asset'
4
+ require_relative './balance'
5
+ require_relative './config'
6
+ require_relative './constants'
7
+ require_relative './hsm_signer'
8
+ require_relative './mock_hsm'
9
+ require_relative './transaction'
10
+ require_relative './transaction_feed'
11
+ require_relative './unspent_output'
12
+
13
+ module Chain
14
+ class Client
15
+
16
+ def initialize(opts = {})
17
+ @opts = {url: DEFAULT_API_HOST}.merge(opts)
18
+ end
19
+
20
+ def opts
21
+ @opts.dup
22
+ end
23
+
24
+ # @return [Connection]
25
+ def conn
26
+ @conn ||= Connection.new(@opts)
27
+ end
28
+
29
+ # @return [AccessToken::ClientModule]
30
+ def access_tokens
31
+ @access_tokens ||= AccessToken::ClientModule.new(self)
32
+ end
33
+
34
+ # @return [Account::ClientModule]
35
+ def accounts
36
+ @accounts ||= Account::ClientModule.new(self)
37
+ end
38
+
39
+ # @return [Asset::ClientModule]
40
+ def assets
41
+ @assets ||= Asset::ClientModule.new(self)
42
+ end
43
+
44
+ # @return [Balance::ClientModule]
45
+ def balances
46
+ @balances ||= Balance::ClientModule.new(self)
47
+ end
48
+
49
+ # @return [Config::ClientModule]
50
+ def config
51
+ @config ||= Config::ClientModule.new(self)
52
+ end
53
+
54
+ # @return [MockHSM::ClientModule]
55
+ def mock_hsm
56
+ @mock_hsm ||= MockHSM::ClientModule.new(self)
57
+ end
58
+
59
+ # @return [Transaction::ClientModule]
60
+ def transactions
61
+ @transactions ||= Transaction::ClientModule.new(self)
62
+ end
63
+
64
+ # @return [TransactionFeed::ClientModule]
65
+ def transaction_feeds
66
+ @transaction_feeds ||= TransactionFeed::ClientModule.new(self)
67
+ end
68
+
69
+ # @return [UnspentOutput::ClientModule]
70
+ def unspent_outputs
71
+ @unspent_outputs ||= UnspentOutput::ClientModule.new(self)
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,11 @@
1
+ module Chain
2
+ class ClientModule
3
+
4
+ attr_reader :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,121 @@
1
+ require_relative './client_module'
2
+ require_relative './response_object'
3
+
4
+ module Chain
5
+ module Config
6
+
7
+ class Info < ResponseObject
8
+ class Snapshot < ResponseObject
9
+ # @!attribute [r] attempt
10
+ # @return [Integer]
11
+ attrib :attempt
12
+
13
+ # @!attribute [r] height
14
+ # @return [Integer]
15
+ attrib :height
16
+
17
+ # @!attribute [r] size
18
+ # @return [Integer]
19
+ attrib :size
20
+
21
+ # @!attribute [r] downloaded
22
+ # @return [Integer]
23
+ attrib :downloaded
24
+
25
+ # @!attribute [r] in_progress
26
+ # @return [Boolean]
27
+ attrib :in_progress
28
+ end
29
+
30
+ # @!attribute [r] is_configured
31
+ # @return [Boolean]
32
+ attrib :is_configured
33
+
34
+ # @!attribute [r] configured_at
35
+ # @return [Time]
36
+ attrib(:configured_at) { |raw| Time.parse(raw) }
37
+
38
+ # @!attribute [r] is_signer
39
+ # @return [Boolean]
40
+ attrib :is_signer
41
+
42
+ # @!attribute [r] is_generator
43
+ # @return [Boolean]
44
+ attrib :is_generator
45
+
46
+ # @!attribute [r] is_generator
47
+ # @return [String]
48
+ attrib :generator_url
49
+
50
+ # @!attribute [r] generator_access_token
51
+ # @return [String]
52
+ attrib :generator_access_token
53
+
54
+ # @!attribute [r] blockchain_id
55
+ # @return [String]
56
+ attrib :blockchain_id
57
+
58
+ # @!attribute [r] block_height
59
+ # @return [Integer]
60
+ attrib :block_height
61
+
62
+ # @!attribute [r] generator_block_height
63
+ # @return [Integer]
64
+ attrib :generator_block_height
65
+
66
+ # @!attribute [r] generator_block_height_fetched_at
67
+ # @return [Time]
68
+ attrib(:generator_block_height_fetched_at) { |raw| Time.parse(raw) }
69
+
70
+ # @!attribute [r] is_production
71
+ # @return [Boolean]
72
+ attrib :is_production
73
+
74
+ # @!attribute [r] network_rpc_version
75
+ # @return [Integer]
76
+ attrib :network_rpc_version
77
+
78
+ # @!attribute [r] core_id
79
+ # @return [String]
80
+ attrib :core_id
81
+
82
+ # @!attribute [r] build_commit
83
+ # @return [String]
84
+ attrib :build_commit
85
+
86
+ # @!attribute [r] build_date
87
+ # Date when the core binary was compiled.
88
+ #
89
+ # The API may not return this field as an RFC3399 timestamp,
90
+ # so it is not converted into a Time object.
91
+ # @return [String]
92
+ attrib :build_date
93
+
94
+ # @!attribute [r] health
95
+ # @return [Hash]
96
+ attrib :health
97
+
98
+ # @!attribute [r] snapshot
99
+ # @return [Snapshot]
100
+ attrib(:snapshot) { |raw| Snapshot.new(raw) }
101
+ end
102
+
103
+ class ClientModule < Chain::ClientModule
104
+ # @return [void]
105
+ def reset(everything: false)
106
+ client.conn.request('reset', {everything: everything})
107
+ end
108
+
109
+ # @return [void]
110
+ def configure(opts)
111
+ client.conn.request('configure', opts)
112
+ end
113
+
114
+ # @return [Info]
115
+ def info
116
+ Info.new(client.conn.request('info'))
117
+ end
118
+ end
119
+
120
+ end
121
+ end