Skip to content

Commit

Permalink
#70 watching transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
bshevchenko committed Sep 12, 2019
1 parent 3d44bb6 commit 0b61e36
Show file tree
Hide file tree
Showing 20 changed files with 1,106 additions and 204 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Expand Up @@ -23,7 +23,7 @@ gem 'devise_token_auth'
gem 'discard', '>= 1.0.0'
gem 'faker', '>= 1.9.1', require: false
gem 'graphiql-rails', '>= 1.5.0'
gem 'graphql', '1.9.2'
gem 'graphql', '1.9.5'
gem 'graphql-guard', '~> 1.2.1'
gem 'kaminari', '>= 1.1.1'
gem 'loofah', '>= 2.2.3'
Expand Down
6 changes: 3 additions & 3 deletions Gemfile.lock
Expand Up @@ -148,7 +148,7 @@ GEM
graphiql-rails (1.7.0)
railties
sprockets-rails
graphql (1.9.2)
graphql (1.9.5)
graphql-guard (1.2.2)
graphql (>= 1.6.0, < 2)
hashdiff (0.4.0)
Expand Down Expand Up @@ -351,7 +351,7 @@ DEPENDENCIES
factory_bot_rails (>= 4.0.0)
faker (>= 1.9.1)
graphiql-rails (>= 1.5.0)
graphql (= 1.9.2)
graphql (= 1.9.5)
graphql-guard (~> 1.2.1)
kaminari (>= 1.1.1)
listen (>= 3.0.5, < 3.2)
Expand Down Expand Up @@ -380,4 +380,4 @@ RUBY VERSION
ruby 2.6.0p0

BUNDLED WITH
1.17.2
1.17.3
69 changes: 69 additions & 0 deletions app/graphql/mutations/resend_transaction_mutation.rb
@@ -0,0 +1,69 @@
# frozen_string_literal: true

module Mutations
class ResendTransactionMutation < Types::Base::BaseMutation
description 'Given an old transaction, resend it with new parameters or gas prices'

argument :id, ID,
required: true,
description: 'ID of the transaction to be resent'
argument :transaction_hash, String,
required: true,
description: 'Transaction hash'
argument :transaction_object, Types::Scalar::JSONObject,
required: true,
description: 'The JSONified transaction data object'
argument :signed_transaction, String,
required: true,
description: 'Signed transaction in HEX format'

field :watched_transaction, Types::WatchedTransaction::WatchedTransactionType,
null: true,
description: 'Newly created transaction'
field :errors, [UserErrorType],
null: false,
description: <<~EOS
Mutation errors
Operation Errors:
- Previous transaction not found
- Unauthorized action
- Nonce is not the same as the previous
EOS

def resolve(id:, transaction_hash:, transaction_object:, signed_transaction:)
key = :watched_transaction

unless (old = WatchingTransaction.find_by(id: id))
return form_error(key, 'transaction_object', 'Previous transaction not found')
end

attrs = {
txhash: transaction_hash,
transaction_object: transaction_object,
signed_transaction: signed_transaction
}

result, tx_or_errors = WatchingTransaction.resend(
context.fetch(:current_user, nil),
old,
attrs
)

case result
when :unauthorized_action
form_error(key, 'id', 'Unauthorized action')
when :invalid_nonce
form_error(key, 'transaction_object', 'Nonce is not the same as the previous')
when :invalid_data
model_errors(key, tx_or_errors)
when :ok
model_result(key, tx_or_errors)
end
end

def self.authorized?(object, context)
super && context.fetch(:current_user, nil)
end
end
end
55 changes: 55 additions & 0 deletions app/graphql/mutations/watch_transaction_mutation.rb
@@ -0,0 +1,55 @@
# frozen_string_literal: true

module Mutations
class WatchTransactionMutation < Types::Base::BaseMutation
description 'Given a transaction, save it to the database to be resent'

argument :transaction_hash, String,
required: true,
description: 'Transaction hash'
argument :transaction_object, Types::Scalar::JSONObject,
required: true,
description: 'The JSONified transaction data object'
argument :signed_transaction, String,
required: true,
description: 'Signed transaction in HEX format'

field :watched_transaction, Types::WatchedTransaction::WatchedTransactionType,
null: true,
description: 'Newly created transaction'
field :errors, [UserErrorType],
null: false,
description: <<~EOS
Mutation errors
Operation Errors:
- Invalid transaction object
EOS

def resolve(transaction_hash:, transaction_object:, signed_transaction:)
key = :watched_transaction

attrs = {
txhash: transaction_hash,
transaction_object: transaction_object,
signed_transaction: signed_transaction
}

result, tx_or_errors = WatchingTransaction.watch(
context.fetch(:current_user),
attrs
)

case result
when :invalid_data
model_errors(key, tx_or_errors)
when :ok
model_result(key, tx_or_errors)
end
end

def self.authorized?(object, context)
super && context.fetch(:current_user, nil)
end
end
end
23 changes: 23 additions & 0 deletions app/graphql/resolvers/watched_transaction_resolver.rb
@@ -0,0 +1,23 @@
# frozen_string_literal: true

module Resolvers
class WatchedTransactionResolver < Resolvers::Base
type Types::WatchedTransaction::WatchedTransactionType, null: true

argument :txhash, String,
required: true,
description: 'Find the last watched transaction in the group with that txhash'

def resolve(txhash:)
unless (tx = WatchingTransaction.find_by(txhash: txhash))
return nil
end

WatchingTransaction.where(group_id: tx.group_id).order('created_at ASC').last
end

def self.authorized?(object, context)
super && context.fetch(:current_user, nil)
end
end
end
153 changes: 153 additions & 0 deletions app/graphql/schema.graphql
Expand Up @@ -792,6 +792,16 @@ Industry for KYC submission
"""
scalar IndustryValue

"""
Represents untyped JSON
"""
scalar JSON

"""
The JSONified data object
"""
scalar JSONObject

"""
A customer's KYC submission
"""
Expand Down Expand Up @@ -1135,6 +1145,11 @@ type Mutation {
"""
rejectKyc(input: RejectKycMutationInput!): RejectKycMutationPayload

"""
Given an old transaction, resend it with new parameters or gas prices
"""
resendTransaction(input: ResendTransactionMutationInput!): ResendTransactionMutationPayload

"""
As the current user, submit a KYC to access more features of the app.
Expand Down Expand Up @@ -1171,6 +1186,11 @@ type Mutation {
Can only unpost a comment you posted.
"""
unpostComment(input: UnpostCommentMutationInput!): UnpostCommentMutationPayload

"""
Given a transaction, save it to the database to be resent
"""
watchTransaction(input: WatchTransactionMutationInput!): WatchTransactionMutationPayload
}

"""
Expand Down Expand Up @@ -1587,6 +1607,16 @@ type Query {
"""
id: String!
): AuthorizedUser

"""
Given a transaction txhash, find the last watched transaction in the group with that txhash.
"""
watchedTransaction(
"""
Find the last watched transaction in the group with that txhash
"""
txhash: String!
): WatchedTransaction
}

"""
Expand Down Expand Up @@ -1652,6 +1682,61 @@ A rejection rason represented by a string that comes form `RejectionReason.value
"""
scalar RejectionReasonValue

"""
Autogenerated input type of ResendTransactionMutation
"""
input ResendTransactionMutationInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String

"""
ID of the transaction to be resent
"""
id: ID!

"""
Signed transaction in HEX format
"""
signedTransaction: String!

"""
Transaction hash
"""
transactionHash: String!

"""
The JSONified transaction data object
"""
transactionObject: JSONObject!
}

"""
Autogenerated return type of ResendTransactionMutation
"""
type ResendTransactionMutationPayload {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String

"""
Mutation errors
Operation Errors:
- Previous transaction not found
- Unauthorized action
- Nonce is not the same as the previous
"""
errors: [UserError!]!

"""
Newly created transaction
"""
watchedTransaction: WatchedTransaction
}

"""
Customer residence proof for KYC submission
"""
Expand Down Expand Up @@ -2413,4 +2498,72 @@ enum VotingStageEnum {
Voters reveal their vote
"""
REVEAL
}

"""
Autogenerated input type of WatchTransactionMutation
"""
input WatchTransactionMutationInput {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String

"""
Signed transaction in HEX format
"""
signedTransaction: String!

"""
Transaction hash
"""
transactionHash: String!

"""
The JSONified transaction data object
"""
transactionObject: JSONObject!
}

"""
Autogenerated return type of WatchTransactionMutation
"""
type WatchTransactionMutationPayload {
"""
A unique identifier for the client performing the mutation.
"""
clientMutationId: String

"""
Mutation errors
Operation Errors:
- Invalid transaction object
"""
errors: [UserError!]!

"""
Newly created transaction
"""
watchedTransaction: WatchedTransaction
}

"""
Transactions that are being watched in the blockchain
"""
type WatchedTransaction {
"""
UUID of the watched transaction
"""
id: ID!

"""
The JSONified transaction data object
"""
transactionObject: JSON!

"""
Signer of the transaction
"""
user: User!
}
3 changes: 3 additions & 0 deletions app/graphql/types/mutation_type.rb
Expand Up @@ -18,5 +18,8 @@ class MutationType < Types::Base::BaseObject
field :unpost_comment, mutation: Mutations::UnpostCommentMutation
field :ban_comment, mutation: Mutations::BanCommentMutation
field :unban_comment, mutation: Mutations::UnbanCommentMutation

field :watch_transaction, mutation: Mutations::WatchTransactionMutation
field :resend_transaction, mutation: Mutations::ResendTransactionMutation
end
end
6 changes: 6 additions & 0 deletions app/graphql/types/query_type.rb
Expand Up @@ -74,6 +74,12 @@ def current_user
Search for the current user's transactions.
EOS

field :watched_transaction,
resolver: Resolvers::WatchedTransactionResolver,
description: <<~EOS
Given a transaction txhash, find the last watched transaction in the group with that txhash.
EOS

field :countries,
resolver: Resolvers::CountriesResolver,
description: 'List of countries to determine nationality for KYC'
Expand Down

0 comments on commit 0b61e36

Please sign in to comment.