pinetwork 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/pi_network.rb +202 -0
- metadata +71 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1943d6bdfac24dbd81680d389d742a9c6229c2cb22a57efe0bb5d45fc2b7265c
|
4
|
+
data.tar.gz: 83498c391acf04457cd2816e76c4972f147b6774906170f6cbac45d8f324fd7f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: '05395f7554e9eaf8bbd3abb653ea078f2e5849046e861f971ef920b415498e9d04cbe402821fc76a1ccdc429b5ad865b682d3aaf4bc0af1d81452d8b961698f5'
|
7
|
+
data.tar.gz: 685cf11f2c3c9e7c0e944459157efff6290bbf381ad67b564fae4eba34f60a24d0c9557530877a3d523c2983e20a673067807d278f70a9b55b6e7831f7eec9e2
|
data/lib/pi_network.rb
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
gem_dir = Gem::Specification.find_by_name("pi_network").gem_dir
|
2
|
+
require "#{gem_dir}/lib/errors"
|
3
|
+
|
4
|
+
class PiNetwork
|
5
|
+
require 'faraday'
|
6
|
+
require 'json'
|
7
|
+
require 'stellar-sdk'
|
8
|
+
|
9
|
+
attr_reader :api_key
|
10
|
+
attr_reader :client
|
11
|
+
attr_reader :account
|
12
|
+
attr_reader :base_url
|
13
|
+
attr_reader :from_address
|
14
|
+
|
15
|
+
def initialize(api_key, wallet_private_key, options = {})
|
16
|
+
validate_private_seed_format!(wallet_private_key)
|
17
|
+
@api_key = api_key
|
18
|
+
@account = load_account(wallet_private_key)
|
19
|
+
@base_url = options[:base_url] || "https://api.minepi.com"
|
20
|
+
|
21
|
+
@open_payments = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_payment(payment_id)
|
25
|
+
response = Faraday.get(
|
26
|
+
base_url + "/v2/payments/#{payment_id}",
|
27
|
+
{},
|
28
|
+
http_headers,
|
29
|
+
)
|
30
|
+
|
31
|
+
if response.status == 404
|
32
|
+
raise Errors::PaymentNotFoundError.new("Payment not found", payment_id)
|
33
|
+
end
|
34
|
+
|
35
|
+
handle_http_response(response, "An unknown error occurred while fetching the payment")
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_payment(payment_data)
|
39
|
+
validate_payment_data!(payment_data, {amount: true, memo: true, metadata: true, uid: true})
|
40
|
+
|
41
|
+
request_body = {
|
42
|
+
payment: payment_data,
|
43
|
+
}
|
44
|
+
|
45
|
+
response = Faraday.post(
|
46
|
+
base_url + "/v2/payments",
|
47
|
+
request_body.to_json,
|
48
|
+
http_headers,
|
49
|
+
)
|
50
|
+
|
51
|
+
parsed_response = handle_http_response(response, "An unknown error occurred while creating a payment")
|
52
|
+
|
53
|
+
identifier = parsed_response["identifier"]
|
54
|
+
@open_payments[identifier] = parsed_response
|
55
|
+
|
56
|
+
return identifier
|
57
|
+
end
|
58
|
+
|
59
|
+
def submit_payment(payment_id)
|
60
|
+
payment = @open_payments[payment_id]
|
61
|
+
|
62
|
+
if payment.nil?
|
63
|
+
payment = get_payment(payment_id)
|
64
|
+
end
|
65
|
+
|
66
|
+
set_horizon_client(payment["network"])
|
67
|
+
@from_address = payment["from_address"]
|
68
|
+
|
69
|
+
transaction_data = {
|
70
|
+
amount: payment["amount"],
|
71
|
+
identifier: payment["identifier"],
|
72
|
+
recipient: payment["to_address"]
|
73
|
+
}
|
74
|
+
|
75
|
+
transaction = build_a2u_transaction(transaction_data)
|
76
|
+
txid = submit_transaction(transaction)
|
77
|
+
|
78
|
+
@open_payments.delete(payment_id)
|
79
|
+
|
80
|
+
return txid
|
81
|
+
end
|
82
|
+
|
83
|
+
def complete_payment(identifier, txid)
|
84
|
+
body = {"txid": txid}
|
85
|
+
|
86
|
+
response = Faraday.post(
|
87
|
+
base_url + "/v2/payments/#{identifier}/complete",
|
88
|
+
body.to_json,
|
89
|
+
http_headers
|
90
|
+
)
|
91
|
+
|
92
|
+
handle_http_response(response, "An unknown error occurred while completing the payment")
|
93
|
+
end
|
94
|
+
|
95
|
+
def cancel_payment(identifier)
|
96
|
+
response = Faraday.post(
|
97
|
+
base_url + "/v2/payments/#{identifier}/cancel",
|
98
|
+
{}.to_json,
|
99
|
+
http_headers,
|
100
|
+
)
|
101
|
+
|
102
|
+
handle_http_response(response, "An unknown error occurred while cancelling the payment")
|
103
|
+
end
|
104
|
+
|
105
|
+
def get_incomplete_server_payments
|
106
|
+
response = Faraday.get(
|
107
|
+
base_url + "/v2/payments/incomplete_server_payments",
|
108
|
+
{},
|
109
|
+
http_headers,
|
110
|
+
)
|
111
|
+
|
112
|
+
res = handle_http_response(response, "An unknown error occurred while fetching incomplete payments")
|
113
|
+
res["incomplete_server_payments"]
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def http_headers
|
119
|
+
return nil if @api_key.nil?
|
120
|
+
|
121
|
+
{
|
122
|
+
"Authorization": "Key #{@api_key}",
|
123
|
+
"Content-Type": "application/json"
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
def handle_http_response(response, unknown_error_message = "An unknown error occurred while making an API request")
|
128
|
+
unless response.status == 200
|
129
|
+
error_message = JSON.parse(response.body).dig("error_message") rescue unknown_err_message
|
130
|
+
raise Errors::APIRequestError.new(error_message, response.status, response.body)
|
131
|
+
end
|
132
|
+
|
133
|
+
begin
|
134
|
+
parsed_response = JSON.parse(response.body)
|
135
|
+
return parsed_response
|
136
|
+
rescue StandardError => err
|
137
|
+
error_message = "Failed to parse response body"
|
138
|
+
raise Errors::APIRequestError.new(error_message, response.status, response.body)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def set_horizon_client(network)
|
143
|
+
host = network == "Pi Network" ? "api.mainnet.minepi.com" : "api.staging-testnet.socialchainapp.com"
|
144
|
+
horizon = network == "Pi Network" ? "https://api.mainnet.minepi.com" : "https://api.staging-testnet.socialchainapp.com"
|
145
|
+
client = Stellar::Client.new(host: host, horizon: horizon)
|
146
|
+
Stellar::default_network = network
|
147
|
+
|
148
|
+
@client = client
|
149
|
+
end
|
150
|
+
|
151
|
+
def load_account(private_seed)
|
152
|
+
account = Stellar::Account.from_seed(private_seed)
|
153
|
+
end
|
154
|
+
|
155
|
+
def build_a2u_transaction(transaction_data)
|
156
|
+
raise StandardError.new("You should use a private seed of your app wallet!") if self.from_address != self.account.address
|
157
|
+
|
158
|
+
validate_payment_data!(transaction_data, {amount: true, identifier: true, recipient: true})
|
159
|
+
|
160
|
+
amount = Stellar::Amount.new(transaction_data[:amount])
|
161
|
+
# TODO: get this from horizon
|
162
|
+
fee = 100000 # 0.01π
|
163
|
+
recipient = Stellar::KeyPair.from_address(transaction_data[:recipient])
|
164
|
+
memo = Stellar::Memo.new(:memo_text, transaction_data[:identifier])
|
165
|
+
|
166
|
+
payment_operation = Stellar::Operation.payment({
|
167
|
+
destination: recipient,
|
168
|
+
amount: amount.to_payment
|
169
|
+
})
|
170
|
+
|
171
|
+
my_public_key = self.account.address
|
172
|
+
sequence_number = self.client.account_info(my_public_key).sequence.to_i
|
173
|
+
transaction_builder = Stellar::TransactionBuilder.new(
|
174
|
+
source_account: self.account.keypair,
|
175
|
+
sequence_number: sequence_number + 1,
|
176
|
+
base_fee: fee,
|
177
|
+
memo: memo
|
178
|
+
)
|
179
|
+
|
180
|
+
transaction = transaction_builder.add_operation(payment_operation).set_timeout(180000).build
|
181
|
+
end
|
182
|
+
|
183
|
+
def submit_transaction(transaction)
|
184
|
+
envelope = transaction.to_envelope(self.account.keypair)
|
185
|
+
response = self.client.submit_transaction(tx_envelope: envelope)
|
186
|
+
txid = response._response.body["id"]
|
187
|
+
end
|
188
|
+
|
189
|
+
def validate_payment_data!(data, options = {})
|
190
|
+
raise ArgumentError.new("Missing amount") if options[:amount] && !data[:amount].present?
|
191
|
+
raise ArgumentError.new("Missing memo") if options[:memo] && !data[:memo].present?
|
192
|
+
raise ArgumentError.new("Missing metadata") if options[:metadata] && !data[:metadata].present?
|
193
|
+
raise ArgumentError.new("Missing uid") if options[:uid] && !data[:uid].present?
|
194
|
+
raise ArgumentError.new("Missing identifier") if options[:identifier] && !data[:identifier].present?
|
195
|
+
raise ArgumentError.new("Missing recipient") if options[:recipient] && !data[:recipient].present?
|
196
|
+
end
|
197
|
+
|
198
|
+
def validate_private_seed_format!(seed)
|
199
|
+
raise StandardError.new("Private Seed should start with \"S\"") unless seed.upcase.starts_with?("S")
|
200
|
+
raise StandardError.new("Private Seed should be 56 characters") unless seed.length == 56
|
201
|
+
end
|
202
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pinetwork
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pi Core Team
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-01-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: stellar-sdk
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.29.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.29.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: faraday
|
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
|
+
description: Pi Network backend library for Ruby-based webservers.
|
42
|
+
email: support@minepi.com
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- lib/pi_network.rb
|
48
|
+
homepage: https://rubygems.org/gems/pi_network
|
49
|
+
licenses:
|
50
|
+
- PiOS
|
51
|
+
metadata: {}
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubygems_version: 3.0.3.1
|
68
|
+
signing_key:
|
69
|
+
specification_version: 4
|
70
|
+
summary: Pi Network Ruby
|
71
|
+
test_files: []
|