chain-sdk 1.0.0.pre

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.
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