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

Update TokenTransfer #420

Merged
merged 3 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 29 additions & 60 deletions sdk/main/include/TokenTransfer.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,15 @@
#include "AccountId.h"
#include "TokenId.h"

#include <memory>
#include <vector>

namespace proto
{
class AccountAmount;
class TokenTransferList;
}

namespace Hedera
{
/**
Expand All @@ -32,83 +41,43 @@ namespace Hedera
class TokenTransfer
{
public:
/**
* Set the ID of the token being transferred.
*
* @param tokenId The ID of the token that is being transferred.
* @return A reference to this TokenTransfer object with the newly-set token ID.
*/
TokenTransfer& setTokenId(const TokenId& tokenId);

/**
* Set the ID of the account sending/receiving the token.
*
* @param accountId The ID of the account that is sending/receiving the token.
* @return A reference to this TokenTransfer object with the newly-set account ID.
*/
TokenTransfer& setAccountId(const AccountId& accountId);

/**
* Set the amount of the token being transferred.
*
* @param amount The amount of the token to transfer.
* @return A reference to this TokenTransfer object with the newly-set amount.
*/
TokenTransfer& setAmount(const int64_t& amount);

/**
* Set the number of decimals of the transfer amount. (e.g. amount of 10,055 with decimals of 2 means 100.55 of the
* token gets transferred).
*
* @param decimals The number of decimals in the transfer amount.
* @return A reference to this TokenTransfer object with the newly-set number of decimals.
*/
TokenTransfer& setExpectedDecimals(uint32_t decimals);

/**
* Set the approval status of this transfer.
*
* @param approval \c TRUE if this is an approved transfer, otherwise \c FALSE.
* @return A reference to this TokenTransfer object with the newly-set approval.
*/
TokenTransfer& setApproval(bool approval);

/**
* Get the token ID.
*
* @return The token ID.
*/
[[nodiscard]] inline TokenId getTokenId() const { return mTokenId; }
TokenTransfer() = default;

/**
* Get the account ID.
* Construct with a token ID, account ID, amount, and approval.
*
* @return The account ID.
* @param tokenId The ID of the token involved with this TokenTransfer.
* @param accountId The ID of the account to/from which the token is being transferred.
* @param amount The amount of the token being transferred.
* @param isApproved \c TRUE if this transfer is approved, otherwise \c FALSE.
*/
[[nodiscard]] inline AccountId getAccountId() const { return mAccountId; }
TokenTransfer(const TokenId& tokenId, AccountId accountId, int64_t amount, bool isApproved);

/**
* Get the amount of token to be transferred.
* Construct with a token ID, account ID, amount, expected decimals of the token, and approval.
*
* @return The amount of token to be transferred.
* @param tokenId The ID of the token involved with this TokenTransfer.
* @param accountId The ID of the account to/from which the token is being transferred.
* @param amount The amount of the token being transferred.
* @param isApproved \c TRUE if this transfer is approved, otherwise \c FALSE.
*/
[[nodiscard]] inline int64_t getAmount() const { return mAmount; }
TokenTransfer(const TokenId& tokenId, AccountId accountId, int64_t amount, uint32_t decimals, bool isApproved);

/**
* Get the expected decimals of the transfer amount.
* Construct a list of TokenTransfers objects from a TokenTransferList protobuf object.
*
* @return The expected decimals of the transfer amount.
* @param proto The TokenTransferList protobuf object from which to construct the list of TokenTransfer objects.
* @return The list of TokenTransfer objects.
*/
[[nodiscard]] inline uint32_t getExpectedDecimals() const { return mExpectedDecimals; }
[[nodiscard]] static std::vector<TokenTransfer> fromProtobuf(const proto::TokenTransferList& proto);

/**
* Determine if this transfer is approved or not.
* Construct an AccountAmount protobuf object from this TokenTransfer object.
*
* @return \c TRUE if this is an approved transfer, otherwise \c FALSE.
* @return A pointer to the constructed AccountAmount protobuf object.
*/
[[nodiscard]] inline bool getApproval() const { return mIsApproval; }
[[nodiscard]] std::unique_ptr<proto::AccountAmount> toProtobuf() const;

private:
/**
* The ID of the token being transferred.
*/
Expand Down
55 changes: 37 additions & 18 deletions sdk/main/src/TokenTransfer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,41 +19,60 @@
*/
#include "TokenTransfer.h"

#include <proto/basic_types.pb.h>

namespace Hedera
{
//-----
TokenTransfer& TokenTransfer::setTokenId(const TokenId& tokenId)
TokenTransfer::TokenTransfer(const TokenId& tokenId, AccountId accountId, int64_t amount, bool isApproved)
: mTokenId(tokenId)
, mAccountId(std::move(accountId))
, mAmount(amount)
, mIsApproval(isApproved)
{
mTokenId = tokenId;
return *this;
}

//-----
TokenTransfer& TokenTransfer::setAccountId(const AccountId& accountId)
TokenTransfer::TokenTransfer(const TokenId& tokenId,
AccountId accountId,
int64_t amount,
uint32_t decimals,
bool isApproved)
: mTokenId(tokenId)
, mAccountId(std::move(accountId))
, mAmount(amount)
, mExpectedDecimals(decimals)
, mIsApproval(isApproved)
{
mAccountId = accountId;
return *this;
}

//-----
TokenTransfer& TokenTransfer::setAmount(const int64_t& amount)
std::vector<TokenTransfer> TokenTransfer::fromProtobuf(const proto::TokenTransferList& proto)
{
mAmount = amount;
return *this;
}
std::vector<TokenTransfer> transfers;
const TokenId tokenId = TokenId::fromProtobuf(proto.token());

//-----
TokenTransfer& TokenTransfer::setExpectedDecimals(uint32_t decimals)
{
mExpectedDecimals = decimals;
return *this;
for (int i = 0; i < proto.transfers_size(); ++i)
{
const proto::AccountAmount& amount = proto.transfers(i);
transfers.emplace_back(tokenId,
AccountId::fromProtobuf(amount.accountid()),
amount.amount(),
proto.has_expected_decimals() ? proto.expected_decimals().value() : 0U,
amount.is_approval());
}

return transfers;
}

//-----
TokenTransfer& TokenTransfer::setApproval(bool approval)
std::unique_ptr<proto::AccountAmount> TokenTransfer::toProtobuf() const
{
mIsApproval = approval;
return *this;
auto accountAmount = std::make_unique<proto::AccountAmount>();
accountAmount->set_allocated_accountid(mAccountId.toProtobuf().release());
accountAmount->set_amount(mAmount);
accountAmount->set_is_approval(mIsApproval);
return accountAmount;
}

} // namespace Hedera
16 changes: 3 additions & 13 deletions sdk/main/src/TransactionRecord.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,9 @@ TransactionRecord TransactionRecord::fromProtobuf(const proto::TransactionRecord
const TokenId tokenId = TokenId::fromProtobuf(list.token());

// Fungible token
for (int j = 0; j < list.transfers_size(); ++j)
{
const proto::AccountAmount& accountAmount = list.transfers(j);

TokenTransfer transfer;
transfer.setTokenId(tokenId);
transfer.setAccountId(AccountId::fromProtobuf(accountAmount.accountid()));
transfer.setAmount(accountAmount.amount());
transfer.setApproval(accountAmount.is_approval());
transfer.setExpectedDecimals(list.expected_decimals().value());

transactionRecord.mTokenTransferList.push_back(transfer);
}
const std::vector<TokenTransfer> fungibleTransfers = TokenTransfer::fromProtobuf(list);
transactionRecord.mTokenTransferList.insert(
transactionRecord.mTokenTransferList.cend(), fungibleTransfers.cbegin(), fungibleTransfers.cend());

// NFT
for (int j = 0; j < list.nfttransfers_size(); ++j)
Expand Down
58 changes: 23 additions & 35 deletions sdk/main/src/TransferTransaction.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,11 @@ TransferTransaction::TransferTransaction(const proto::TransactionBody& transacti
for (int j = 0; j < transfer.transfers_size(); ++j)
{
const proto::AccountAmount& accountAmount = transfer.transfers(j);
mTokenTransfers.push_back(TokenTransfer()
.setTokenId(tokenId)
.setAccountId(AccountId::fromProtobuf(accountAmount.accountid()))
.setAmount(accountAmount.amount())
.setApproval(accountAmount.is_approval())
.setExpectedDecimals(transfer.expected_decimals().value()));
mTokenTransfers.emplace_back(tokenId,
AccountId::fromProtobuf(accountAmount.accountid()),
accountAmount.amount(),
transfer.expected_decimals().value(),
accountAmount.is_approval());
}

for (int j = 0; j < transfer.nfttransfers_size(); ++j)
Expand Down Expand Up @@ -92,7 +91,7 @@ TransferTransaction& TransferTransaction::addTokenTransfer(const TokenId& tokenI
{
requireNotFrozen();

doTokenTransfer(TokenTransfer().setTokenId(tokenId).setAccountId(accountId).setAmount(amount).setApproval(false));
doTokenTransfer(TokenTransfer(tokenId, accountId, amount, false));
return *this;
}

Expand All @@ -119,12 +118,7 @@ TransferTransaction& TransferTransaction::addTokenTransferWithDecimals(const Tok
{
requireNotFrozen();

doTokenTransfer(TokenTransfer()
.setTokenId(tokenId)
.setAccountId(accountId)
.setAmount(amount)
.setExpectedDecimals(decimals)
.setApproval(false));
doTokenTransfer(TokenTransfer(tokenId, accountId, amount, decimals, false));
return *this;
}

Expand All @@ -144,7 +138,7 @@ TransferTransaction& TransferTransaction::addApprovedTokenTransfer(const TokenId
{
requireNotFrozen();

doTokenTransfer(TokenTransfer().setTokenId(tokenId).setAccountId(accountId).setAmount(amount).setApproval(true));
doTokenTransfer(TokenTransfer(tokenId, accountId, amount, true));
return *this;
}

Expand All @@ -171,12 +165,7 @@ TransferTransaction& TransferTransaction::addApprovedTokenTransferWithDecimals(c
{
requireNotFrozen();

doTokenTransfer(TokenTransfer()
.setTokenId(tokenId)
.setAccountId(accountId)
.setAmount(amount)
.setExpectedDecimals(decimals)
.setApproval(true));
doTokenTransfer(TokenTransfer(tokenId, accountId, amount, decimals, true));
return *this;
}

Expand All @@ -200,7 +189,7 @@ std::unordered_map<TokenId, std::unordered_map<AccountId, int64_t>> TransferTran

for (const TokenTransfer& transfer : mTokenTransfers)
{
tokenTransfers[transfer.getTokenId()][transfer.getAccountId()] += transfer.getAmount();
tokenTransfers[transfer.mTokenId][transfer.mAccountId] += transfer.mAmount;
}

return tokenTransfers;
Expand All @@ -226,9 +215,9 @@ std::unordered_map<TokenId, uint32_t> TransferTransaction::getTokenIdDecimals()

for (const TokenTransfer& transfer : mTokenTransfers)
{
if (transfer.getExpectedDecimals() != 0)
if (transfer.mExpectedDecimals != 0U)
{
decimals[transfer.getTokenId()] = transfer.getExpectedDecimals();
decimals[transfer.mTokenId] = transfer.mExpectedDecimals;
}
}

Expand Down Expand Up @@ -270,7 +259,7 @@ proto::CryptoTransferTransactionBody* TransferTransaction::build() const
proto::TokenTransferList* list = nullptr;
for (int i = 0; i < body->mutable_tokentransfers()->size(); ++i)
{
if (TokenId::fromProtobuf(body->mutable_tokentransfers(i)->token()) == transfer.getTokenId())
if (TokenId::fromProtobuf(body->mutable_tokentransfers(i)->token()) == transfer.mTokenId)
{
list = body->mutable_tokentransfers(i);
}
Expand All @@ -279,17 +268,17 @@ proto::CryptoTransferTransactionBody* TransferTransaction::build() const
if (!list)
{
list = body->add_tokentransfers();
list->set_allocated_token(transfer.getTokenId().toProtobuf().release());
list->set_allocated_token(transfer.mTokenId.toProtobuf().release());
}

proto::AccountAmount* amount = list->add_transfers();
amount->set_allocated_accountid(transfer.getAccountId().toProtobuf().release());
amount->set_amount(transfer.getAmount());
amount->set_is_approval(transfer.getApproval());
amount->set_allocated_accountid(transfer.mAccountId.toProtobuf().release());
amount->set_amount(transfer.mAmount);
amount->set_is_approval(transfer.mIsApproval);

// Shouldn't ever overwrite a different value here because it is checked when the transfer is added to this
// TransferTransaction.
list->mutable_expected_decimals()->set_value(transfer.getExpectedDecimals());
list->mutable_expected_decimals()->set_value(transfer.mExpectedDecimals);
}

for (const TokenNftTransfer& transfer : mNftTransfers)
Expand Down Expand Up @@ -348,21 +337,20 @@ void TransferTransaction::doTokenTransfer(const TokenTransfer& transfer)
{
for (auto transferIter = mTokenTransfers.begin(); transferIter != mTokenTransfers.end(); ++transferIter)
{
if (transferIter->getTokenId() == transfer.getTokenId() &&
transferIter->getAccountId() == transfer.getAccountId() &&
transferIter->getApproval() == transfer.getApproval())
if (transferIter->mTokenId == transfer.mTokenId && transferIter->mAccountId == transfer.mAccountId &&
transferIter->mIsApproval == transfer.mIsApproval)
{
if (transferIter->getExpectedDecimals() != transfer.getExpectedDecimals())
if (transferIter->mExpectedDecimals != transfer.mExpectedDecimals)
{
throw std::invalid_argument("Expected decimals for token do not match previously set decimals");
}
else if (const int64_t newAmount = transferIter->getAmount() + transfer.getAmount(); newAmount == 0LL)
else if (const int64_t newAmount = transferIter->mAmount + transfer.mAmount; newAmount == 0LL)
{
mTokenTransfers.erase(transferIter);
}
else
{
transferIter->setAmount(newAmount);
transferIter->mAmount = newAmount;
}

return;
Expand Down
Loading
Loading