Skip to content
This repository has been archived by the owner on Apr 23, 2024. It is now read-only.

Implement validation for Stellar deposits #86

Merged
merged 6 commits into from
Jul 7, 2022
Merged

Implement validation for Stellar deposits #86

merged 6 commits into from
Jul 7, 2022

Conversation

tamirms
Copy link
Contributor

@tamirms tamirms commented Jul 5, 2022

This PR implements getStellarDeposit() which is a helper function to extract and validate a deposit to the Stellar bridge account from an http request. getStellarDeposit() will be used by the HTTP handlers for the Stellar -> Ethereum withdrawal and refund endpoints.

A stellar deposit is valid if:

  • the transaction is successful
  • the transaction contains only one operation which is a payment to the bridge account

Note that we do not validate the Stellar asset or the ethereum address of the recipient (which is encoded in the transaction memo). Validation of those fields should only be implemented in the HTTP handler for the withdrawal endpoint. If a user does not set the memo correctly on their payment to the bridge then the withdrawal should fail, however, it should still be possible to refund the payment.

Copy link
Contributor

@bartekn bartekn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Going to approve after discussing storing deposits in a DB.

store/stellar.go Show resolved Hide resolved
// contract
Amount string `db:"amount"`
// LedgerTime is the unix timestamp of the deposit
LedgerTime int64 `db:"ledger_time"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not time.Time?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had some issues storing time.Time values in the db in the integration tests which is why I decided to just store the unix timestamp instead

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used it starting at https://github.com/stellar/starbridge/tree/d0314d3e51b7205ec8aaae278825765dc943d46c for outgoing_stellar_transactions.expiration. The type was timestamp without time zone and it was working fine.

Comment on lines 28 to 52
StellarTxNotSuccessful = problem.P{
Type: "stellar_tx_not_successful",
Title: "Stellar Transaction Not Successful",
Status: http.StatusUnprocessableEntity,
Detail: "The stellar transaction was not successful.",
}
StellarTxHasMultipleOperations = problem.P{
Type: "stellar_tx_has_multiple_operations",
Title: "Stellar Transaction Has Multiple Operations",
Status: http.StatusUnprocessableEntity,
Detail: "The stellar deposit transaction is invalid because it has multiple operations.",
}
StellarTxIsNotPayment = problem.P{
Type: "stellar_tx_is_not_payment",
Title: "Stellar Transaction Is Not Payment",
Status: http.StatusUnprocessableEntity,
Detail: "The stellar deposit transaction is invalid because it is not a payment.",
}
StellarTxIsNotPaymentToBridge = problem.P{
Type: "stellar_tx_is_not_payment_to_bridge",
Title: "Stellar Transaction Is Not Payment To Bridge",
Status: http.StatusUnprocessableEntity,
Detail: "The stellar deposit transaction is invalid because it " +
"is not a payment to the bridge account.",
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can merge all these errors into stellar_tx_invalid and put details in Detail field. Unless we need to be able to check the code somewhere other than frontend it would make sense.

return store.StellarDeposit{}, err
}

ops, err := client.Operations(horizonclient.OperationRequest{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it can be a problem for Horizons with partial history. Maybe we should store the incoming payments in a DB (as we do for withdrawals in stellar.Observer)? I guess we'd need to introduce a minimum deposit amount to prevent spamming the account with stroop payments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that makes sense since we are already processing incoming payments

@tamirms
Copy link
Contributor Author

tamirms commented Jul 6, 2022

@bartekn I implemented your suggestion of ingesting both incoming and outgoing payments to the bridge, PTAL

Copy link
Contributor

@bartekn bartekn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

stellar/txobserver/main.go Outdated Show resolved Hide resolved
stellar/txobserver/main.go Show resolved Hide resolved
}
// Skip inserting transactions with multiple ops. Currently Starbridge
// does not create such transactions but it can change in the future.
return len(tx.Operations()) == 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because ingestIncomingPayment also should have a memo validation, maybe we could move:

payment.Transaction.MemoType != "hash" || payment.Transaction.Memo == ""

check here from ingestOutgoingPayment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I chose to not validate the transaction memo for incoming payments is that validation of those fields should only be implemented in the HTTP handler for the withdrawal endpoint. If a user does not set the memo correctly on their payment to the bridge then the withdrawal should fail, however, it should still be possible to refund the payment. This will allow people who didn't set the memo properly to still be able to recover their deposit via refunds.

assetString = "native"
} else {
assetString = payment.Asset.Code + ":" + payment.Asset.Issuer
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also validate memo here. Check the previous comment.

stellar/txobserver/main.go Outdated Show resolved Hide resolved
LedgerTime: payment.LedgerCloseTime.Unix(),
Sender: payment.From,
Destination: payment.Transaction.Memo,
Amount: payment.Amount,
Copy link
Contributor

@bartekn bartekn Jul 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be done later (after MVP) but we should probably add a config value for minimum deposit. Otherwise it's possible to add thousands of rows in Starbridge DB quite easily. EDIT: created #88.

tamirms and others added 2 commits July 7, 2022 09:35
Co-authored-by: Bartek Nowotarski <bartek@nowotarski.info>
@tamirms tamirms merged commit 0b812a1 into main Jul 7, 2022
@tamirms tamirms deleted the stellar-deposit branch July 7, 2022 14:00
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants