near_api 0.1.0 → 0.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d9a8146bb7d005f8f833531892e9ba17f44545dd30da6b15d86f2343cc1f9d5
4
- data.tar.gz: d7e51a87f8f3a9c36fa45c85327985c0fd56cc6c1df32dab18cac84dad3f9ded
3
+ metadata.gz: 1c8844d644d14d1d32fa4d27ef9247f0e5de59019dd195272a457b531935a416
4
+ data.tar.gz: 3196cdfe44e96d18f997a67d8d55ec159c24158f3afdac7c3b30656a946bab34
5
5
  SHA512:
6
- metadata.gz: 7f6030857da43b0b2b039d6f2f82155a57d5743e0287e376ce7d30181812f885b925282429c2afe3595dca6505e89f97128790dc4a974263a2b65c1f14f2b297
7
- data.tar.gz: f0b7b6d68bd0038ccc90635f935d804fcb19de534a00dc9275e9aa920c2e7516a7f89d02af2f6b15f75454b83b3c8cfaeade9edb0dc500f5e61f77dda2f9e10b
6
+ metadata.gz: 6d6d9e682ce1392ed9314d62340ea56e68fe81a48ed00bb8e981b950380613ea5f79b9df6c4ab3da7dd5a3e1cf5fe0c847ae6c6dcf7fd485b3a3e508a114ad76
7
+ data.tar.gz: f89dfa4956871b176517e52cc868a26a9115aa6ae0beb1efbe634807f0e2d538e13d9cfbc56c81958bf948c1ce19b9ed3593da22439507950a1870004f4a7d26
data/Gemfile CHANGED
@@ -6,5 +6,3 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  gem "rake", "~> 13.0"
9
-
10
- gem "rspec", "~> 3.0"
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ class NearApi::Action::FunctionCall
4
+ include Borsh
5
+
6
+ borsh action_code: :u8,
7
+ method_name: :string,
8
+ args: :string,
9
+ gas: :u64,
10
+ amount: :u128
11
+
12
+ def initialize(method_name, args, gas: 100000000000000, amount: 0)
13
+ @method_name = method_name
14
+ @args = args
15
+ @gas = gas
16
+ @amount = amount
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :method_name, :args, :gas, :amount
22
+
23
+ def action_code
24
+ 2
25
+ end
26
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ class NearApi::Action
4
+ include Borsh
5
+
6
+ borsh signer_id: :string,
7
+ key: { key_type: :u8, public_key: 32 },
8
+ nonce: :u64,
9
+ receiver_id: :string,
10
+ block_hash: 32,
11
+ actions: [:borsh]
12
+
13
+ def self.call(*args)
14
+ new(*args).call
15
+ end
16
+
17
+ def self.async(*args)
18
+ new(*args).async
19
+ end
20
+
21
+ def initialize(receiver_id, actions, config: NearApi.config, key: NearApi.key)
22
+ @key = key
23
+ @receiver_id = receiver_id
24
+ @actions = Array(actions)
25
+ @config = config
26
+ @api = NearApi::Api.new(config)
27
+ end
28
+
29
+ def call
30
+ signature = key.sign(message.digest)
31
+ call_api('broadcast_tx_commit', message.message, signature)
32
+ end
33
+
34
+ def async
35
+ signature = key.sign(message.digest)
36
+ call_api('broadcast_tx_async', message.message, signature)
37
+ end
38
+
39
+ def message
40
+ @message ||= begin
41
+ message = to_borsh
42
+ Struct.new(:message, :digest).new(message, Digest::SHA256.digest(message))
43
+ end
44
+ end
45
+
46
+ def call_api(method, message, signature)
47
+ signed_transaction = message + Borsh::Integer.new(key.key_type, :u8).to_borsh + signature
48
+ api.json_rpc(method, [Base64.strict_encode64(signed_transaction)])
49
+ end
50
+
51
+ private
52
+
53
+ def signer_id
54
+ key.signer_id
55
+ end
56
+
57
+ def nonce
58
+ api.nonce(key) + 1
59
+ end
60
+
61
+ def block_hash
62
+ api.block_hash
63
+ end
64
+
65
+ attr_reader :receiver_id, :actions, :key, :config, :api
66
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ class NearApi::Api
4
+ def initialize(config = NearApi.config)
5
+ @config = config
6
+ end
7
+
8
+ def call(method, payload)
9
+ json_rpc(method, payload)
10
+ end
11
+
12
+ def status
13
+ uri = URI("#{config.node_url}/status")
14
+ JSON.parse(Net::HTTP.get(uri))
15
+ end
16
+
17
+ def view_access_key(key)
18
+ call(
19
+ 'query',
20
+ {
21
+ "request_type": "view_access_key",
22
+ "account_id": key.signer_id,
23
+ "public_key": NearApi::Base58.encode(key.public_key),
24
+ "finality": 'optimistic'
25
+ }
26
+ )
27
+ end
28
+
29
+ def nonce(key)
30
+ view_access_key(key)['result']['nonce']
31
+ end
32
+
33
+ def block_hash
34
+ NearApi::Base58.decode(status['sync_info']['latest_block_hash'])
35
+ end
36
+
37
+ def json_rpc(method, payload)
38
+ json_rpc_payload = {
39
+ id: 'dontcare',
40
+ jsonrpc: "2.0",
41
+ method: method,
42
+ params: payload
43
+ }
44
+
45
+ uri = URI.parse(config.node_url)
46
+ req = Net::HTTP::Post.new(uri.to_s)
47
+ req.body = json_rpc_payload.to_json
48
+ req['Content-Type'] = 'application/json'
49
+ response = Net::HTTP.new(uri.host, uri.port).tap { |http| http.use_ssl = true }.request(req)
50
+
51
+ JSON.parse(response.body)
52
+ end
53
+
54
+ private
55
+
56
+ attr_reader :config
57
+ end
58
+
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ class NearApi::Base58
4
+ BASE = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
5
+
6
+ def self.encode(bytestring)
7
+ number = bytestring.unpack("C*").reverse.each_with_index.inject(0) do |sum, (byte, index)|
8
+ sum + byte * (256 ** index)
9
+ end
10
+ tos number
11
+ end
12
+
13
+ def self.decode(encoded_string)
14
+ integer = toi encoded_string
15
+ to_bytestring(integer)
16
+ end
17
+
18
+ def self.toi(string=to_s, base=58, digits=BASE)
19
+ return nil if string.empty?
20
+
21
+ integer = 0
22
+ string.each_char do |c|
23
+ index = digits.index(c)
24
+ integer = integer * base + index
25
+ end
26
+ integer
27
+ end
28
+
29
+ def self.tos(integer=to_i, base=58, digits=BASE)
30
+ return '' if integer.nil?
31
+ return digits[0] if integer == 0
32
+ string = ''
33
+ while integer > 0
34
+ integer, index = integer.divmod(base)
35
+ string = digits[index] + string
36
+ end
37
+ string
38
+ end
39
+
40
+ def self.to_bytestring(number)
41
+ integer = number
42
+ result = ''
43
+ while integer > 0
44
+ integer, remain = integer.divmod(256)
45
+ result = remain.chr + result
46
+ end
47
+ result
48
+ end
49
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class NearApi::Config
4
+ def initialize(node_url: ENV.fetch('NEAR_NODE_URL'))
5
+ @node_url = node_url
6
+ end
7
+
8
+ attr_reader :node_url
9
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ require 'ed25519'
3
+
4
+ class NearApi::Key
5
+ attr_reader :signer_id, :public_key
6
+
7
+ def initialize(signer_id = ENV.fetch('NEAR_SIGNER_ID'),
8
+ key_pair: ENV.fetch('NEAR_KEYPAIR', nil),
9
+ public_key: ENV.fetch('NEAR_PUBLIC_KEY', nil))
10
+ @signer_id = signer_id
11
+ if (!key_pair.nil? && !public_key.nil?) || (key_pair.nil? && public_key.nil?)
12
+ raise ArgumentError, "please specify one of: key_pair or public_key"
13
+ end
14
+
15
+ unless key_pair.nil?
16
+ key_value = if key_pair.include?(':')
17
+ key_pair.split(':').last
18
+ else
19
+ key_pair
20
+ end
21
+ bytestring = NearApi::Base58.decode(key_value)
22
+ @key_pair = Ed25519::SigningKey.from_keypair(bytestring)
23
+ @public_key = @key_pair.verify_key.to_bytes
24
+ end
25
+
26
+ unless public_key.nil?
27
+ key_value = if public_key.include?(':')
28
+ public_key.split(':').last
29
+ else
30
+ public_key
31
+ end
32
+ bytestring = NearApi::Base58.decode(key_value)
33
+ @public_key = Ed25519::VerifyKey.new(bytestring).to_bytes
34
+ end
35
+ end
36
+
37
+ def key_type
38
+ 0
39
+ end
40
+
41
+ def sign(msg)
42
+ key_pair.sign(msg)
43
+ end
44
+
45
+ private
46
+
47
+ attr_reader :key_pair
48
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ class NearApi::Query
4
+ def initialize(config = NearApi.config)
5
+ @api = NearApi::Api.new(config)
6
+ end
7
+
8
+ def function(account_id, method_name, args, finality: 'final')
9
+ params = {
10
+ request_type: 'call_function',
11
+ finality: finality,
12
+ account_id: account_id,
13
+ method_name: method_name,
14
+ args_base64: Base64.strict_encode64(args.to_json)
15
+ }
16
+ call_api(params)
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :api
22
+
23
+ def call_api(params)
24
+ api.json_rpc('query', params)
25
+ end
26
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NearApi
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.4"
5
5
  end
data/lib/near_api.rb CHANGED
@@ -1,8 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'uri'
4
+ require 'net/https'
5
+ require 'json'
6
+ require "base64"
7
+ require 'borsh'
3
8
  require_relative "near_api/version"
9
+ require_relative "near_api/key"
10
+ require_relative "near_api/action"
11
+ require_relative 'near_api/query'
12
+ require_relative "near_api/action/function_call"
13
+ require_relative "near_api/config"
14
+ require_relative 'near_api/api'
15
+ require_relative "near_api/base58"
4
16
 
5
17
  module NearApi
6
18
  class Error < StandardError; end
7
- # Your code goes here...
19
+
20
+ def self.config
21
+ @config ||= Config.new
22
+ end
23
+
24
+ def config=(config)
25
+ @config = config
26
+ end
27
+
28
+ def self.key
29
+ @key ||= Key.new
30
+ end
31
+
32
+ def key=(key)
33
+ @key = key
34
+ end
8
35
  end
data/near_api.gemspec CHANGED
@@ -26,6 +26,12 @@ Gem::Specification.new do |spec|
26
26
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
27
27
  spec.require_paths = ["lib"]
28
28
 
29
+ spec.add_dependency "borsh-rb"
30
+ spec.add_dependency "ed25519"
31
+
32
+ spec.add_development_dependency "rspec", "~> 3.10"
33
+ spec.add_development_dependency "pry"
34
+
29
35
  # Uncomment to register a new dependency of your gem
30
36
  # spec.add_dependency "example-gem", "~> 1.0"
31
37
 
metadata CHANGED
@@ -1,15 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: near_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Serg Tyatin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-13 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2021-12-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: borsh-rb
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ed25519
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.10'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
13
69
  description:
14
70
  email:
15
71
  - 700@2rba.com
@@ -26,6 +82,13 @@ files:
26
82
  - bin/console
27
83
  - bin/setup
28
84
  - lib/near_api.rb
85
+ - lib/near_api/action.rb
86
+ - lib/near_api/action/function_call.rb
87
+ - lib/near_api/api.rb
88
+ - lib/near_api/base58.rb
89
+ - lib/near_api/config.rb
90
+ - lib/near_api/key.rb
91
+ - lib/near_api/query.rb
29
92
  - lib/near_api/version.rb
30
93
  - near_api.gemspec
31
94
  homepage: https://github.com/2rba/near_api