partner_api 0.11.2
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/.github/workflows/release.yml +18 -0
- data/.github/workflows/ruby.yml +28 -0
- data/.gitignore +18 -0
- data/.rspec +4 -0
- data/CHANGELOG.md +105 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +85 -0
- data/Rakefile +6 -0
- data/bin/console +17 -0
- data/bin/setup +8 -0
- data/docs/anz_api.md +67 -0
- data/docs/bnz_api.md +103 -0
- data/docs/fab_api.md +206 -0
- data/docs/gemini_api.md +184 -0
- data/docs/vma_api.md +167 -0
- data/docs/westpac_api.md +106 -0
- data/lib/anz_api/client.rb +24 -0
- data/lib/anz_api/endpoint.rb +29 -0
- data/lib/anz_api/endpoints/fetch_jwk.rb +35 -0
- data/lib/anz_api/failure_response.rb +33 -0
- data/lib/anz_api.rb +15 -0
- data/lib/bnz_api/client.rb +45 -0
- data/lib/bnz_api/configuration.rb +21 -0
- data/lib/bnz_api/endpoint.rb +56 -0
- data/lib/bnz_api/endpoints/fetch_id_token.rb +73 -0
- data/lib/bnz_api/endpoints/fetch_jwk.rb +35 -0
- data/lib/bnz_api/failure_response.rb +33 -0
- data/lib/bnz_api/httpx.rb +75 -0
- data/lib/bnz_api.rb +18 -0
- data/lib/fab_api/client.rb +36 -0
- data/lib/fab_api/configuration.rb +26 -0
- data/lib/fab_api/endpoint.rb +70 -0
- data/lib/fab_api/endpoints/deliver_email.rb +56 -0
- data/lib/fab_api/endpoints/deliver_sms.rb +51 -0
- data/lib/fab_api/endpoints/exchange_token.rb +49 -0
- data/lib/fab_api/endpoints/invalidate_token.rb +53 -0
- data/lib/fab_api/endpoints/refresh_token.rb +60 -0
- data/lib/fab_api/failure_response.rb +39 -0
- data/lib/fab_api/utils/id.rb +13 -0
- data/lib/fab_api.rb +18 -0
- data/lib/gemini_api/address.rb +23 -0
- data/lib/gemini_api/balance.rb +24 -0
- data/lib/gemini_api/client.rb +37 -0
- data/lib/gemini_api/endpoint.rb +62 -0
- data/lib/gemini_api/endpoints/create_address_request.rb +39 -0
- data/lib/gemini_api/endpoints/get_available_balances.rb +39 -0
- data/lib/gemini_api/endpoints/view_approved_addresses.rb +40 -0
- data/lib/gemini_api/endpoints/view_transfers.rb +49 -0
- data/lib/gemini_api/endpoints/withdraw_crypto_fund.rb +49 -0
- data/lib/gemini_api/failure_response.rb +47 -0
- data/lib/gemini_api/transaction.rb +14 -0
- data/lib/gemini_api/transfer.rb +44 -0
- data/lib/gemini_api.rb +16 -0
- data/lib/partner_api/endpoints/base.rb +152 -0
- data/lib/partner_api/errors.rb +18 -0
- data/lib/partner_api/utils/hash.rb +21 -0
- data/lib/partner_api/utils/read_cert.rb +38 -0
- data/lib/vma_api/client.rb +33 -0
- data/lib/vma_api/configuration.rb +24 -0
- data/lib/vma_api/endpoint.rb +29 -0
- data/lib/vma_api/endpoints/access_token.rb +60 -0
- data/lib/vma_api/endpoints/client_credentials.rb +60 -0
- data/lib/vma_api/endpoints/refresh_token.rb +60 -0
- data/lib/vma_api/endpoints/revoke_token.rb +55 -0
- data/lib/vma_api/failure_response.rb +42 -0
- data/lib/vma_api.rb +20 -0
- data/lib/westpac_api/client.rb +29 -0
- data/lib/westpac_api/configuration.rb +28 -0
- data/lib/westpac_api/endpoint.rb +26 -0
- data/lib/westpac_api/endpoints/fetch_jwk.rb +33 -0
- data/lib/westpac_api/endpoints/fetch_user.rb +96 -0
- data/lib/westpac_api/failure_response.rb +33 -0
- data/lib/westpac_api.rb +28 -0
- data/partner_api.gemspec +31 -0
- metadata +191 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'fab_api/endpoint'
|
2
|
+
require 'fab_api/utils/id'
|
3
|
+
|
4
|
+
module FabApi
|
5
|
+
module Endpoints
|
6
|
+
class ExchangeToken < Endpoint
|
7
|
+
prepend PartnerApi::Endpoints::Initializer
|
8
|
+
|
9
|
+
def initialize(access_token:, system:, transaction_id: Utils::Id.generate)
|
10
|
+
@access_token = access_token
|
11
|
+
@system = system
|
12
|
+
@transaction_id = transaction_id
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_reader :access_token, :system, :transaction_id
|
18
|
+
|
19
|
+
def method
|
20
|
+
"POST"
|
21
|
+
end
|
22
|
+
|
23
|
+
def path
|
24
|
+
"/security/v1/verifytoken"
|
25
|
+
end
|
26
|
+
|
27
|
+
def parameters
|
28
|
+
{
|
29
|
+
"applicationArea": {
|
30
|
+
"transactionId": transaction_id,
|
31
|
+
},
|
32
|
+
"dataArea": {
|
33
|
+
system: system,
|
34
|
+
accessCode: access_token,
|
35
|
+
grantType: 'authorization_code'
|
36
|
+
}
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def decode(response)
|
41
|
+
response.parse.dig('dataArea', 'token')
|
42
|
+
end
|
43
|
+
|
44
|
+
def logging_params
|
45
|
+
{ transaction_id: transaction_id }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'fab_api/endpoint'
|
2
|
+
require 'fab_api/utils/id'
|
3
|
+
|
4
|
+
module FabApi
|
5
|
+
module Endpoints
|
6
|
+
class InvalidateToken < Endpoint
|
7
|
+
prepend PartnerApi::Endpoints::Initializer
|
8
|
+
|
9
|
+
def initialize(
|
10
|
+
partner_user_id:,
|
11
|
+
access_token:,
|
12
|
+
system:,
|
13
|
+
transaction_id: Utils::Id.generate
|
14
|
+
)
|
15
|
+
@partner_user_id = partner_user_id
|
16
|
+
@access_token = access_token
|
17
|
+
@system = system
|
18
|
+
@transaction_id = transaction_id
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :partner_user_id, :access_token, :system, :transaction_id
|
24
|
+
|
25
|
+
def method
|
26
|
+
"POST"
|
27
|
+
end
|
28
|
+
|
29
|
+
def path
|
30
|
+
"/security/v1/invalidatetoken"
|
31
|
+
end
|
32
|
+
|
33
|
+
def parameters
|
34
|
+
{
|
35
|
+
"applicationArea": {
|
36
|
+
"transactionId": transaction_id,
|
37
|
+
},
|
38
|
+
"dataArea": {
|
39
|
+
system: system,
|
40
|
+
accessCode: access_token,
|
41
|
+
userId: partner_user_id
|
42
|
+
}
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def decode(_response); end
|
47
|
+
|
48
|
+
def logging_params
|
49
|
+
{ transaction_id: transaction_id, user_id: partner_user_id }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'fab_api/endpoint'
|
2
|
+
require 'fab_api/utils/id'
|
3
|
+
|
4
|
+
module FabApi
|
5
|
+
module Endpoints
|
6
|
+
class RefreshToken < Endpoint
|
7
|
+
prepend PartnerApi::Endpoints::Initializer
|
8
|
+
|
9
|
+
def initialize(
|
10
|
+
access_token:,
|
11
|
+
refresh_token:,
|
12
|
+
system:,
|
13
|
+
transaction_id: Utils::Id.generate,
|
14
|
+
new_token_flag: true
|
15
|
+
)
|
16
|
+
@access_token = access_token
|
17
|
+
@refresh_token = refresh_token
|
18
|
+
@system = system
|
19
|
+
@transaction_id = transaction_id
|
20
|
+
@new_token_flag = new_token_flag
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :access_token, :refresh_token, :system, :transaction_id,
|
26
|
+
:new_token_flag
|
27
|
+
|
28
|
+
def method
|
29
|
+
"POST"
|
30
|
+
end
|
31
|
+
|
32
|
+
def path
|
33
|
+
"/security/v1/verifytoken"
|
34
|
+
end
|
35
|
+
|
36
|
+
def parameters
|
37
|
+
{
|
38
|
+
"applicationArea": {
|
39
|
+
"transactionId": transaction_id,
|
40
|
+
},
|
41
|
+
"dataArea": {
|
42
|
+
system: system,
|
43
|
+
accessCode: access_token,
|
44
|
+
refreshCode: refresh_token,
|
45
|
+
grantType: 'refresh_token',
|
46
|
+
newTokenRequired: new_token_flag
|
47
|
+
}
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def decode(response)
|
52
|
+
response.parse.dig('dataArea', 'token')
|
53
|
+
end
|
54
|
+
|
55
|
+
def logging_params
|
56
|
+
{ transaction_id: transaction_id }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'partner_api/errors'
|
2
|
+
|
3
|
+
module FabApi
|
4
|
+
class FailureResponse
|
5
|
+
def initialize(response)
|
6
|
+
@response = response
|
7
|
+
end
|
8
|
+
|
9
|
+
def errors
|
10
|
+
if response.status.success?
|
11
|
+
response.parse['responseStatus']['errorDetails'].map do |error|
|
12
|
+
PartnerApi::Errors::RequestError.new(code: error['errorCode'], message: error['errorDesc'])
|
13
|
+
end
|
14
|
+
else
|
15
|
+
[PartnerApi::Errors::RequestError.new(message: "Invalid Response: #{body}")]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def error
|
20
|
+
errors.first
|
21
|
+
end
|
22
|
+
|
23
|
+
def status
|
24
|
+
response.status
|
25
|
+
end
|
26
|
+
|
27
|
+
def body
|
28
|
+
response.body
|
29
|
+
end
|
30
|
+
|
31
|
+
def headers
|
32
|
+
response.headers.to_h
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
attr_reader :response
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module FabApi
|
4
|
+
module Utils
|
5
|
+
module Id
|
6
|
+
# Make sure identifier start with AS,
|
7
|
+
# followed by any unique characters and max length of 24 characters.
|
8
|
+
def self.generate
|
9
|
+
"AS#{SecureRandom.hex(11)}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/fab_api.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'concurrent-ruby'
|
3
|
+
|
4
|
+
require 'fab_api/client'
|
5
|
+
require 'fab_api/configuration'
|
6
|
+
|
7
|
+
module FabApi
|
8
|
+
extend self
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
@configuration = Concurrent::Hash.new
|
12
|
+
|
13
|
+
def_delegators 'configuration(:default)', :config, :configure
|
14
|
+
|
15
|
+
def configuration(key)
|
16
|
+
@configuration[key] ||= Configuration.new
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module GeminiApi
|
2
|
+
Address = Struct.new(
|
3
|
+
:network,
|
4
|
+
:scope,
|
5
|
+
:label,
|
6
|
+
:status,
|
7
|
+
:created_at,
|
8
|
+
:address,
|
9
|
+
:raw_data,
|
10
|
+
keyword_init: true
|
11
|
+
) do
|
12
|
+
def self.build(raw_data)
|
13
|
+
new(
|
14
|
+
network: raw_data['network'],
|
15
|
+
scope: raw_data['scope'],
|
16
|
+
label: raw_data['label'],
|
17
|
+
status: raw_data['status'],
|
18
|
+
created_at: Time.at(raw_data['createdAt'].to_f / 1000),
|
19
|
+
address: raw_data['address']
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
|
3
|
+
module GeminiApi
|
4
|
+
Balance = Struct.new(
|
5
|
+
:type,
|
6
|
+
:currency,
|
7
|
+
:amount,
|
8
|
+
:available,
|
9
|
+
:available_for_withdrawal,
|
10
|
+
:raw_data,
|
11
|
+
keyword_init: true
|
12
|
+
) do
|
13
|
+
def self.build(raw_data)
|
14
|
+
new(
|
15
|
+
type: raw_data['type'],
|
16
|
+
currency: raw_data['currency'],
|
17
|
+
amount: BigDecimal(raw_data['amount']),
|
18
|
+
available: BigDecimal(raw_data['available']),
|
19
|
+
available_for_withdrawal: BigDecimal(raw_data['availableForWithdrawal']),
|
20
|
+
raw_data: raw_data
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hanami/utils/string'
|
4
|
+
require 'hanami/utils/class'
|
5
|
+
|
6
|
+
require 'gemini_api/endpoints/create_address_request'
|
7
|
+
require 'gemini_api/endpoints/view_approved_addresses'
|
8
|
+
require 'gemini_api/endpoints/withdraw_crypto_fund'
|
9
|
+
require 'gemini_api/endpoints/get_available_balances'
|
10
|
+
require 'gemini_api/endpoints/view_transfers'
|
11
|
+
|
12
|
+
module GeminiApi
|
13
|
+
class Client
|
14
|
+
def self.endpoint(name)
|
15
|
+
define_method(name) do |**args|
|
16
|
+
klass_name = Hanami::Utils::String.classify(name)
|
17
|
+
endpoint_klass = Hanami::Utils::Class.load!("GeminiApi::Endpoints::#{klass_name}")
|
18
|
+
|
19
|
+
endpoint_klass.(config, **args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
endpoint :create_address_request
|
24
|
+
endpoint :view_approved_addresses
|
25
|
+
endpoint :withdraw_crypto_fund
|
26
|
+
endpoint :get_available_balances
|
27
|
+
endpoint :view_transfers
|
28
|
+
|
29
|
+
def initialize(config: GeminiApi.config)
|
30
|
+
@config = config
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_reader :config
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'partner_api/endpoints/base'
|
4
|
+
require 'gemini_api/failure_response'
|
5
|
+
|
6
|
+
module GeminiApi
|
7
|
+
class Endpoint < PartnerApi::Endpoints::Base
|
8
|
+
HMAC_ALGORITHM = 'SHA384'
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def request_options
|
13
|
+
{ headers: combined_headers }
|
14
|
+
end
|
15
|
+
|
16
|
+
def connection_options
|
17
|
+
{}
|
18
|
+
end
|
19
|
+
|
20
|
+
def default_headers
|
21
|
+
{
|
22
|
+
'Content-Type' => 'text/plain',
|
23
|
+
'Content-Length' => '0',
|
24
|
+
'Cache-Control' => 'no-cache',
|
25
|
+
'X-GEMINI-APIKEY' => config.api_key,
|
26
|
+
'X-GEMINI-PAYLOAD' => base64_payload,
|
27
|
+
'X-GEMINI-SIGNATURE' => signature
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def default_parameters
|
32
|
+
{
|
33
|
+
'request' => path,
|
34
|
+
'nonce' => Time.now.to_i
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def base64_payload
|
39
|
+
Base64.urlsafe_encode64(combined_payload.to_json)
|
40
|
+
end
|
41
|
+
|
42
|
+
def signature
|
43
|
+
OpenSSL::HMAC.hexdigest(HMAC_ALGORITHM, config.api_secret, base64_payload)
|
44
|
+
end
|
45
|
+
|
46
|
+
def successful?(response)
|
47
|
+
response.status.success?
|
48
|
+
end
|
49
|
+
|
50
|
+
def decode(response)
|
51
|
+
response.parse
|
52
|
+
end
|
53
|
+
|
54
|
+
def decode_error(response)
|
55
|
+
FailureResponse.new(response)
|
56
|
+
end
|
57
|
+
|
58
|
+
def logging_params
|
59
|
+
{}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gemini_api/endpoint'
|
4
|
+
|
5
|
+
module GeminiApi
|
6
|
+
module Endpoints
|
7
|
+
class CreateAddressRequest < Endpoint
|
8
|
+
prepend PartnerApi::Endpoints::Initializer
|
9
|
+
|
10
|
+
# See https://docs.gemini.com/rest-api/#create-an-address-request
|
11
|
+
def initialize(network:, address:, label:, account: nil)
|
12
|
+
@network = network
|
13
|
+
@address = address
|
14
|
+
@label = label
|
15
|
+
@account = account
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :network, :address, :label, :account
|
21
|
+
|
22
|
+
def method
|
23
|
+
'POST'
|
24
|
+
end
|
25
|
+
|
26
|
+
def path
|
27
|
+
"/v1/approvedAddresses/#{network}/request"
|
28
|
+
end
|
29
|
+
|
30
|
+
def parameters
|
31
|
+
{
|
32
|
+
address: address,
|
33
|
+
label: label,
|
34
|
+
account: account
|
35
|
+
}.compact
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gemini_api/endpoint'
|
4
|
+
require 'gemini_api/balance'
|
5
|
+
|
6
|
+
module GeminiApi
|
7
|
+
module Endpoints
|
8
|
+
class GetAvailableBalances < Endpoint
|
9
|
+
prepend PartnerApi::Endpoints::Initializer
|
10
|
+
|
11
|
+
# See https://docs.gemini.com/rest-api/#get-available-balances
|
12
|
+
def initialize(account: nil)
|
13
|
+
@account = account
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_reader :account
|
19
|
+
|
20
|
+
def method
|
21
|
+
'POST'
|
22
|
+
end
|
23
|
+
|
24
|
+
def path
|
25
|
+
"/v1/balances"
|
26
|
+
end
|
27
|
+
|
28
|
+
def parameters
|
29
|
+
{ account: account }.compact
|
30
|
+
end
|
31
|
+
|
32
|
+
def decode(response)
|
33
|
+
response.parse.map do |balance|
|
34
|
+
Balance.build(balance)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gemini_api/endpoint'
|
4
|
+
require 'gemini_api/address'
|
5
|
+
|
6
|
+
module GeminiApi
|
7
|
+
module Endpoints
|
8
|
+
class ViewApprovedAddresses < Endpoint
|
9
|
+
prepend PartnerApi::Endpoints::Initializer
|
10
|
+
|
11
|
+
# See https://docs.gemini.com/rest-api/#view-approved-addresses
|
12
|
+
def initialize(network: :gusd, account: nil)
|
13
|
+
@network = network
|
14
|
+
@account = account
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :network, :account
|
20
|
+
|
21
|
+
def method
|
22
|
+
'POST'
|
23
|
+
end
|
24
|
+
|
25
|
+
def path
|
26
|
+
"/v1/approvedAddresses/account/#{network}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def parameters
|
30
|
+
{ account: account }.compact
|
31
|
+
end
|
32
|
+
|
33
|
+
def decode(response)
|
34
|
+
response.parse['approvedAddresses'].map do |address|
|
35
|
+
Address.build(address)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gemini_api/endpoint'
|
4
|
+
require 'gemini_api/transfer'
|
5
|
+
|
6
|
+
module GeminiApi
|
7
|
+
module Endpoints
|
8
|
+
class ViewTransfers < Endpoint
|
9
|
+
prepend PartnerApi::Endpoints::Initializer
|
10
|
+
|
11
|
+
# See: https://docs.gemini.com/rest-api/#transfers
|
12
|
+
def initialize(currency:, timestamp:, limit_transfers: 50, account: nil, show_completed_deposit_advances: false)
|
13
|
+
@currency = currency
|
14
|
+
@timestamp = timestamp
|
15
|
+
@limit_transfers = limit_transfers
|
16
|
+
@account = account
|
17
|
+
@show_completed_deposit_advances = show_completed_deposit_advances
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
attr_reader :currency, :timestamp, :limit_transfers, :account, :show_completed_deposit_advances
|
23
|
+
|
24
|
+
def method
|
25
|
+
'POST'
|
26
|
+
end
|
27
|
+
|
28
|
+
def path
|
29
|
+
'/v1/transfers'
|
30
|
+
end
|
31
|
+
|
32
|
+
def parameters
|
33
|
+
{
|
34
|
+
currency: currency,
|
35
|
+
timestamp: timestamp,
|
36
|
+
limit_transfers: limit_transfers,
|
37
|
+
account: account,
|
38
|
+
show_completed_deposit_advances: show_completed_deposit_advances
|
39
|
+
}.compact
|
40
|
+
end
|
41
|
+
|
42
|
+
def decode(response)
|
43
|
+
response.parse.map do |transfer|
|
44
|
+
Transfer.build(transfer)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'gemini_api/endpoint'
|
4
|
+
require 'gemini_api/transaction'
|
5
|
+
|
6
|
+
module GeminiApi
|
7
|
+
module Endpoints
|
8
|
+
class WithdrawCryptoFund < Endpoint
|
9
|
+
prepend PartnerApi::Endpoints::Initializer
|
10
|
+
|
11
|
+
# By default, we allow withdrawing USD as GUSD
|
12
|
+
# See: https://docs.gemini.com/rest-api/#withdraw-usd-as-gusd
|
13
|
+
# For other currency, see
|
14
|
+
# https://docs.gemini.com/rest-api/#withdraw-crypto-funds
|
15
|
+
def initialize(address:, amount:, currency: :usd, account: nil, client_transfer_id: nil)
|
16
|
+
@currency = currency.to_sym
|
17
|
+
@address = address
|
18
|
+
@amount = amount
|
19
|
+
@account = account
|
20
|
+
@client_transfer_id = client_transfer_id
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :address, :amount, :account, :currency, :client_transfer_id
|
26
|
+
|
27
|
+
def method
|
28
|
+
'POST'
|
29
|
+
end
|
30
|
+
|
31
|
+
def path
|
32
|
+
"/v1/withdraw/#{currency}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def parameters
|
36
|
+
{
|
37
|
+
address: address,
|
38
|
+
amount: amount,
|
39
|
+
account: account,
|
40
|
+
clientTransferId: client_transfer_id
|
41
|
+
}.compact
|
42
|
+
end
|
43
|
+
|
44
|
+
def decode(response)
|
45
|
+
Transaction.build(response.parse)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GeminiApi
|
4
|
+
class FailureResponse
|
5
|
+
def initialize(response)
|
6
|
+
@response = response
|
7
|
+
end
|
8
|
+
|
9
|
+
def errors
|
10
|
+
if json?
|
11
|
+
parsed_response = response.parse
|
12
|
+
[
|
13
|
+
PartnerApi::Errors::RequestError.new(
|
14
|
+
code: parsed_response['reason'],
|
15
|
+
message: parsed_response['message']
|
16
|
+
)
|
17
|
+
]
|
18
|
+
else
|
19
|
+
[PartnerApi::Errors::RequestError.new(message: "Invalid Response: #{body}")]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def error
|
24
|
+
errors.first
|
25
|
+
end
|
26
|
+
|
27
|
+
def status
|
28
|
+
response.status
|
29
|
+
end
|
30
|
+
|
31
|
+
def body
|
32
|
+
response.body
|
33
|
+
end
|
34
|
+
|
35
|
+
def headers
|
36
|
+
response.headers.to_h
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
attr_reader :response
|
42
|
+
|
43
|
+
def json?
|
44
|
+
response.content_type.mime_type == 'application/json'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GeminiApi
|
4
|
+
Transaction = Struct.new(:address, :amount, :withdrawal_id, :raw_data, keyword_init: true) do
|
5
|
+
def self.build(raw_data)
|
6
|
+
new(
|
7
|
+
address: raw_data['address'],
|
8
|
+
amount: raw_data['amount'].to_f,
|
9
|
+
withdrawal_id: raw_data['withdrawalId'],
|
10
|
+
raw_data: raw_data
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|