pinetwork 0.1.0
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 +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: []
|