Transaction builder for transfers: EGLD / ESDTs / NFTs. Sender & receiver usernames.#1845
Conversation
…elds on transaction message: sender & receiver usernames.
|
@andreibancioiu , nice extensive work across all layers. |
|
@catenocrypt, thanks for the input! I will come back with the changes - define messages in the .proto file, drop the new |
hewigovens
left a comment
There was a problem hiding this comment.
I converted it to draft status, feel free to mark it ready to review when you make those changes
hewigovens
left a comment
There was a problem hiding this comment.
Left some comments, overall looks good
|
|
||
| void normalizeHexStringTopLevel(std::string& value); | ||
|
|
||
| std::string Codec::encodeStringTopLevel(const std::string& value) { |
There was a problem hiding this comment.
maybe we can remove suffix like TopLevel from all methods?
There was a problem hiding this comment.
We have two distinct types of encoding (top level vs. nested) - however, indeed, the suffix was redundant in this case, I've removed it. In the future, if needed (most probably not), we might define two distinct classes: TopLevelCodec and NestedCodec.
|
|
||
| // A transaction, typical balance transfer | ||
| // Generic / general-purpose transaction. Using one of the more specific messages (below) is recommended. | ||
| // TODO: Ideally, we should rename this to "Transaction" or "GenericTransaction". The renaming is temporarily postponed (as of December 2021) |
There was a problem hiding this comment.
There are many common fields in EGLDTransfer, ESDTTransfer and ESDTNFTTransfer ( nonce/value/sender/receiver/gas/chain id), please take a look at Cosmos.proto, we can add a nested Transaction message to represent different transfer types
It's ok to do breaking changes as long as we have good test coverage (and mention it in the pr)
There was a problem hiding this comment.
Indeed.
Would the structure below be all right on your side (with breaking change on SigningInput)?
Also, do you think it would be OK if we postpone this breaking change to the next PR? If not, let me know, and I will include the change in this PR.
SigningInput:
bytes private_key
string chain_id
Gas gas
oneof:
- GenericTransaction
- EGLDTransfer
- ESDTTransfer
- ESDTNFTTransfer
Gas:
uint64 gas_limit
uint64 gas_price
GenericTransaction:
Accounts accounts
string value
string data
uint32 version
uint32 options
EGLDTransfer:
Accounts accounts
string amount
ESDTTransfer:
Accounts accounts
string amount
string token_identifier
ESDTNFTTransfer:
Accounts accounts
string amount
string token_collection
uint64 token_nonce
Accounts (nested in transfers / generic transaction, not nested in SigningInput):
uint64 sender_nonce
string receiver
string sender
string sender_username
string receiver_username
There was a problem hiding this comment.
LGTM, no need to add Gas and just use gas_limit and gas_price
There was a problem hiding this comment.
I've updated the Elrond.proto file and made the necessary changes - mostly in TransactionFactory.cpp and in the test files. A new class has been defined, as well: Transaction.
Thanks for the .proto refactor idea!
Perhaps it would make sense to merge the file Serialization.cpp into the new Transaction.cpp, in a future PR. Another (unrelated) idea for a future PR would be to move Transaction construction logic (currently in TransactionFactory) and gas estimation logic (currently in GasEstimator) into subclasses of the (abstract) Transaction class, such as: GenericActionTransaction, EGLDTransferTransaction, ESDTTransferTransaction etc.
hewigovens
left a comment
There was a problem hiding this comment.
👍,just to confirm senderUsername and receiverUsername are optional, correct?
Yes, they are optional. |
| uint64_t forEGLDTransfer(size_t dataLength); | ||
| uint64_t forESDTTransfer(size_t dataLength); | ||
| uint64_t forESDTNFTTransfer(size_t dataLength); |
There was a problem hiding this comment.
Consider const for these methods.
There was a problem hiding this comment.
Added const qualifier.
| public: | ||
| NetworkConfig(); | ||
|
|
||
| const std::string& getChainId(); |
There was a problem hiding this comment.
| const std::string& getChainId(); | |
| const std::string& getChainId() const; |
There was a problem hiding this comment.
Added const qualifier.
| // Example for ... | ||
| // if (timestamp > ...) { | ||
| // networkConfig.setPerDataByte(...) | ||
| // networkConfig.setMinGasPrice(...) | ||
| // } |
There was a problem hiding this comment.
I've removed the example.
| auto valueAsData = Data(); | ||
| encode256BE(valueAsData, value, 256); | ||
|
|
||
| std::string encoded = normalizeHex(hex(valueAsData)); |
There was a problem hiding this comment.
I suggest using hex(store(value, 0)), that will have no leading 0s
There was a problem hiding this comment.
Applied the suggestion - I've called store() without the second & optional parameter (the second parameter is newly introduced in master and would only be available after rebase - I've skipped the rebase, which could possibly break the diff of the PR on github's code review interface).
There was a problem hiding this comment.
Rigth, the parameter was just added, 0 is the default which is the same as the previous behaviour (no padding), so it should not cause issue in merge.
| } | ||
|
|
||
| std::string Codec::encodeUint64(uint64_t value) { | ||
| std::string encoded = normalizeHex(hex(value)); |
There was a problem hiding this comment.
I suggest using hex(store(uint256_t(value), 0)), that will have no leading 0s
There was a problem hiding this comment.
Applied the suggestion - I've called store() without the second & optional parameter (the second parameter is newly introduced in master and would only be available after rebase - I've skipped the rebase, which could possibly break the diff of the PR on github's code review interface).
| return parse_hex(string.begin(), string.end()); | ||
| } | ||
|
|
||
| /// "Normalizes" a hexadecimal string (redundant leading zeros are removed, even length is ensured). |
There was a problem hiding this comment.
- hex(Data) will always return even digits, and the same number of bytes as the input.
- hex(uint64_t) will always return 8 bytes (16 hex digits), possibly with leading zeroes.
- odd-length check is not needed
- I prefer dropping this method, and using alternative, as suggested in the two places where it is used
There was a problem hiding this comment.
Thanks for the suggestion of using store(). I've dropped this method (and its tests).
|
Thanks for the rework. |
|
Signing is not working using the new strategy, even your tests are failing, fix please |
|
@noahNewton Can you elaborate the issue? your sample code, error messages and expected result |
|
The issue is the signing is broken, I input all the required variables, receive a signature, and then when I try to POST the signature to the endpoint: https://devnet-api.elrond.com/transactions with the payload of {data: signature you gave me}, it responds with a 400 status code "Bad Request" error with the message "Sender must be provided", we have been checking very carefully and we are inputting a sender 100%, even when we take the "expectedSignature" variable from your test file (https://github.com/trustwallet/wallet-core/blob/master/android/app/src/androidTest/java/com/trustwallet/core/app/blockchains/elrond/TestElrondSigner.kt) and send this as a payload the POSt request returns the exact same error, so I think either the devnet API is broken or you're not incorporating the "sender" on your end when constructing the transaction signature |
|
Will try it on our side |
…iver usernames. (trustwallet#1845) * Add transaction builder for transfers: EGLD / ESDT / NFTs. Add new fields on transaction message: sender & receiver usernames. * Fix after review: less C exports, added proto structures. Refactoring & better tests. * Fix after review: remove not used files. * Fix after review (renaming, refactoring, cleanup). * Fix after review - redesign .proto structures. * Fix Android / IOS tests. * Fix after review: add missing "const" qualifiers, drop function normalizeHex().
Description
TransactionFactory. This one depends on aNetworkConfigobject, initialized with proper (Mainnet) defaults.Elrond.protohas been redesigned to accommodate the new features, and thus the construction ofSigningInputobjects has to be adjusted by clients of wallet-core, as well. Before the change - Kotlin, Swift. After the change - Kotlin, Swift.Testing instructions
Types of changes
Checklist
[WIP]if necessary.