Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resend txn & Handle dropped txns #70 #72

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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'
bshevchenko marked this conversation as resolved.
Show resolved Hide resolved

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
bshevchenko marked this conversation as resolved.
Show resolved Hide resolved
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