All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hedera.hashgraph.sdk.AccountAllowanceApproveTransaction Maven / Gradle / Ivy

The newest version!
/*-
 *
 * Hedera Java SDK
 *
 * Copyright (C) 2020 - 2022 Hedera Hashgraph, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.hedera.hashgraph.sdk;

import com.google.protobuf.InvalidProtocolBufferException;
import com.hedera.hashgraph.sdk.proto.CryptoApproveAllowanceTransactionBody;
import com.hedera.hashgraph.sdk.proto.CryptoServiceGrpc;
import com.hedera.hashgraph.sdk.proto.SchedulableTransactionBody;
import com.hedera.hashgraph.sdk.proto.TransactionBody;
import com.hedera.hashgraph.sdk.proto.TransactionResponse;
import io.grpc.MethodDescriptor;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * This transaction type is for approving account allowance.
 */
public class AccountAllowanceApproveTransaction extends Transaction {
    private final List hbarAllowances = new ArrayList<>();
    private final List tokenAllowances =  new ArrayList<>();
    private final List nftAllowances = new ArrayList<>();
    // key is "{ownerId}:{spenderId}".  OwnerId may be "FEE_PAYER"
    // >
    private final Map> nftMap = new HashMap<>();

    /**
     * Constructor.
     */
    public AccountAllowanceApproveTransaction() {
    }

    /**
     * Constructor.
     *
     * @param txs                                   Compound list of transaction id's list of (AccountId, Transaction) records
     */
    AccountAllowanceApproveTransaction(
        LinkedHashMap> txs
    ) throws InvalidProtocolBufferException {
        super(txs);
        initFromTransactionBody();
    }

    /**
     * Constructor.
     *
     * @param txBody                    protobuf TransactionBody
     */
    AccountAllowanceApproveTransaction(com.hedera.hashgraph.sdk.proto.TransactionBody txBody) {
        super(txBody);
        initFromTransactionBody();
    }

    private void initFromTransactionBody() {
        var body = sourceTransactionBody.getCryptoApproveAllowance();
        for (var allowanceProto : body.getCryptoAllowancesList()) {
            hbarAllowances.add(HbarAllowance.fromProtobuf(allowanceProto));
        }
        for (var allowanceProto : body.getTokenAllowancesList()) {
            tokenAllowances.add(TokenAllowance.fromProtobuf(allowanceProto));
        }
        for (var allowanceProto : body.getNftAllowancesList()) {
            if (allowanceProto.hasApprovedForAll() && allowanceProto.getApprovedForAll().getValue()) {
                nftAllowances.add(TokenNftAllowance.fromProtobuf(allowanceProto));
            } else {
                getNftSerials(
                    allowanceProto.hasOwner() ? AccountId.fromProtobuf(allowanceProto.getOwner()) : null,
                    AccountId.fromProtobuf(allowanceProto.getSpender()),
                    allowanceProto.hasDelegatingSpender() ? AccountId.fromProtobuf(allowanceProto.getDelegatingSpender()) : null,
                    TokenId.fromProtobuf(allowanceProto.getTokenId())
                ).addAll(allowanceProto.getSerialNumbersList());
            }
        }
    }

    /**
     * @deprecated - Use {@link #approveHbarAllowance(AccountId, AccountId, Hbar)} instead
     *
     * @param spenderAccountId          the spender account id
     * @param amount                    the amount of hbar
     * @return                          an account allowance approve transaction
     */
    @Deprecated
    public AccountAllowanceApproveTransaction addHbarAllowance(AccountId spenderAccountId, Hbar amount) {
        return approveHbarAllowance(null, spenderAccountId, amount);
    }

    /**
     * Approves the Hbar allowance.
     *
     * @param ownerAccountId            owner's account id
     * @param spenderAccountId          spender's account id
     * @param amount                    amount of hbar add
     * @return {@code this}
     */
    public AccountAllowanceApproveTransaction approveHbarAllowance(
        @Nullable AccountId ownerAccountId,
        AccountId spenderAccountId,
        Hbar amount
    ) {
        requireNotFrozen();
        Objects.requireNonNull(amount);
        if (amount.compareTo(Hbar.ZERO) < 0) {
            throw new IllegalArgumentException("amount passed to approveHbarAllowance must be positive");
        }
        hbarAllowances.add(new HbarAllowance(ownerAccountId, Objects.requireNonNull(spenderAccountId), amount));
        return this;
    }

    /**
     * @deprecated - Use {@link #getHbarApprovals()} instead
     *
     * @return                          list of hbar allowance records
     */
    @Deprecated
    public List getHbarAllowances() {
        return getHbarApprovals();
    }

    /**
     * Extract the list of hbar allowances.
     *
     * @return                          array list of hbar allowances
     */
    public List getHbarApprovals() {
        return new ArrayList<>(hbarAllowances);
    }

    /**
     * @deprecated - Use {@link #approveTokenAllowance(TokenId, AccountId, AccountId, long)} instead
     *
     * @param tokenId                   the token id
     * @param spenderAccountId          the spenders account id
     * @param amount                    the hbar amount
     * @return                          an account allowance approve transaction
     */
    @Deprecated
    public AccountAllowanceApproveTransaction addTokenAllowance(
        TokenId tokenId,
        AccountId spenderAccountId,
        long amount
    ) {
        return approveTokenAllowance(tokenId, null, spenderAccountId, amount);
    }

    /**
     * Approves the Token allowance.
     *
     * @param tokenId                   the token's id
     * @param ownerAccountId            owner's account id
     * @param spenderAccountId          spender's account id
     * @param amount                    amount of tokens
     * @return {@code this}
     */
    public AccountAllowanceApproveTransaction approveTokenAllowance(
        TokenId tokenId,
        @Nullable AccountId ownerAccountId,
        AccountId spenderAccountId,
        long amount
    ) {
        requireNotFrozen();
        if (amount < 0) {
            throw new IllegalArgumentException("amount given to approveTokenAllowance must be positive");
        }
        tokenAllowances.add(new TokenAllowance(
            Objects.requireNonNull(tokenId),
            ownerAccountId,
            Objects.requireNonNull(spenderAccountId),
            amount
        ));
        return this;
    }

    /**
     * @deprecated - Use {@link #getTokenApprovals()} instead
     *
     * @return                          a list of token allowances
     */
    @Deprecated
    public List getTokenAllowances() {
        return getTokenApprovals();
    }

    /**
     * Extract a list of token allowance approvals.
     *
     * @return                          array list of token approvals.
     */
    public List getTokenApprovals() {
        return new ArrayList<>(tokenAllowances);
    }

    /**
     * Extract the owner as a string.
     *
     * @param ownerAccountId            owner's account id
     * @return                          a string representation of the account id
     *                                  or FEE_PAYER
     */
    private static String ownerToString(@Nullable AccountId ownerAccountId) {
        return ownerAccountId != null ? ownerAccountId.toString() : "FEE_PAYER";
    }

    /**
     * Return a list of NFT serial numbers.
     *
     * @param ownerAccountId            owner's account id
     * @param spenderAccountId          spender's account id
     * @param delegatingSpender         delegating spender's account id
     * @param tokenId                   the token's id
     * @return list of NFT serial numbers
     */
    private List getNftSerials(@Nullable AccountId ownerAccountId, AccountId spenderAccountId, @Nullable AccountId delegatingSpender, TokenId tokenId) {
        var key = ownerToString(ownerAccountId) + ":" + spenderAccountId;
        if (nftMap.containsKey(key)) {
            var innerMap = nftMap.get(key);
            if (innerMap.containsKey(tokenId)) {
                return Objects.requireNonNull(nftAllowances.get(innerMap.get(tokenId)).serialNumbers);
            } else {
                return newNftSerials(ownerAccountId, spenderAccountId, delegatingSpender, tokenId, innerMap);
            }
        } else {
            Map innerMap = new HashMap<>();
            nftMap.put(key, innerMap);
            return newNftSerials(ownerAccountId, spenderAccountId, delegatingSpender, tokenId, innerMap);
        }
    }

    /**
     * Add NFT serials.
     *
     * @param ownerAccountId            owner's account id
     * @param spenderAccountId          spender's account id
     * @param delegatingSpender         delegating spender's account id
     * @param tokenId                   the token's id
     * @param innerMap                  list of token id's and serial number records
     * @return list of NFT serial numbers
     */
    private List newNftSerials(
        @Nullable AccountId ownerAccountId,
        AccountId spenderAccountId,
        @Nullable AccountId delegatingSpender,
        TokenId tokenId,
        Map innerMap
    ) {
        innerMap.put(tokenId, nftAllowances.size());
        TokenNftAllowance newAllowance = new TokenNftAllowance(
            tokenId,
            ownerAccountId,
            spenderAccountId,
            delegatingSpender,
            new ArrayList<>(),
            null
        );
        nftAllowances.add(newAllowance);
        return newAllowance.serialNumbers;
    }

    /**
     * @deprecated - Use {@link #approveTokenNftAllowance(NftId, AccountId, AccountId, AccountId)} instead
     *
     * @param nftId                     the nft id
     * @param spenderAccountId          the spender's account id
     * @return {@code this}
     */
    @Deprecated
    public AccountAllowanceApproveTransaction addTokenNftAllowance(NftId nftId, AccountId spenderAccountId) {
        requireNotFrozen();
        getNftSerials(null, spenderAccountId, null, nftId.tokenId).add(nftId.serial);
        return this;
    }

    /**
     * @deprecated - Use {@link #approveTokenNftAllowanceAllSerials(TokenId, AccountId, AccountId)} instead
     *
     * @param tokenId                   the token id
     * @param spenderAccountId          the spender's account id
     * @return {@code this}
     */
    @Deprecated
    public AccountAllowanceApproveTransaction addAllTokenNftAllowance(TokenId tokenId, AccountId spenderAccountId) {
        requireNotFrozen();
        nftAllowances.add(new TokenNftAllowance(
            tokenId,
            null,
            spenderAccountId,
            null,
            Collections.emptyList(),
            true
        ));
        return this;
    }

    /**
     * Approve the NFT allowance.
     *
     * @param nftId                     nft's id
     * @param ownerAccountId            owner's account id
     * @param spenderAccountId          spender's account id
     * @param delegatingSpender         delegating spender's account id
     * @return {@code this}
     */
    public AccountAllowanceApproveTransaction approveTokenNftAllowance(
        NftId nftId,
        @Nullable AccountId ownerAccountId,
        AccountId spenderAccountId,
        @Nullable AccountId delegatingSpender
    ) {
        requireNotFrozen();
        Objects.requireNonNull(nftId);
        getNftSerials(
            ownerAccountId,
            Objects.requireNonNull(spenderAccountId),
            delegatingSpender,
            nftId.tokenId
        ).add(nftId.serial);
        return this;
    }

    /**
     * Approve the NFT allowance.
     *
     * @param nftId                     nft's id
     * @param ownerAccountId            owner's account id
     * @param spenderAccountId          spender's account id
     * @return {@code this}
     */
    public AccountAllowanceApproveTransaction approveTokenNftAllowance(
        NftId nftId,
        @Nullable AccountId ownerAccountId,
        AccountId spenderAccountId
    ) {
        requireNotFrozen();
        Objects.requireNonNull(nftId);
        getNftSerials(
            ownerAccountId,
            Objects.requireNonNull(spenderAccountId),
            null,
            nftId.tokenId
        ).add(nftId.serial);
        return this;
    }

    /**
     * Approve the token nft allowance on all serials.
     *
     * @param tokenId                   the token's id
     * @param ownerAccountId            owner's account id
     * @param spenderAccountId          spender's account id
     * @return {@code this}
     */
    public AccountAllowanceApproveTransaction approveTokenNftAllowanceAllSerials(
        TokenId tokenId,
        @Nullable AccountId ownerAccountId,
        AccountId spenderAccountId
    ) {
        requireNotFrozen();
        nftAllowances.add(new TokenNftAllowance(
            Objects.requireNonNull(tokenId),
            ownerAccountId,
            Objects.requireNonNull(spenderAccountId),
            null,
            Collections.emptyList(),
            true
        ));
        return this;
    }

    /**
     * Delete the token nft allowance on all serials.
     *
     * @param tokenId                   the token's id
     * @param ownerAccountId            owner's account id
     * @param spenderAccountId          spender's account id
     * @return {@code this}
     */
    public AccountAllowanceApproveTransaction deleteTokenNftAllowanceAllSerials(
        TokenId tokenId,
        @Nullable AccountId ownerAccountId,
        AccountId spenderAccountId
    ) {
        requireNotFrozen();
        nftAllowances.add(new TokenNftAllowance(
            Objects.requireNonNull(tokenId),
            ownerAccountId,
            Objects.requireNonNull(spenderAccountId),
            null,
            Collections.emptyList(),
            false
        ));
        return this;
    }

    /**
     * @deprecated - Use {@link #getTokenNftApprovals()} instead
     *
     * @return {@code this}
     */
    @Deprecated
    public List getTokenNftAllowances() {
        return getTokenNftApprovals();
    }

    /**
     * Returns the list of token nft allowances.
     *
     * @return  list of token nft allowances.
     */
    public List getTokenNftApprovals() {
        List retval = new ArrayList<>(nftAllowances.size());
        for (var allowance : nftAllowances) {
            retval.add(TokenNftAllowance.copyFrom(allowance));
        }
        return retval;
    }

    @Override
    MethodDescriptor getMethodDescriptor() {
        return CryptoServiceGrpc.getApproveAllowancesMethod();
    }

    /**
     * Build the correct transaction body.
     *
     * @return {@link com.hedera.hashgraph.sdk.proto.CryptoApproveAllowanceTransactionBody builder }
     */
    CryptoApproveAllowanceTransactionBody.Builder build() {
        var builder = CryptoApproveAllowanceTransactionBody.newBuilder();

        for (var allowance : hbarAllowances) {
            builder.addCryptoAllowances(allowance.toProtobuf());
        }
        for (var allowance : tokenAllowances) {
            builder.addTokenAllowances(allowance.toProtobuf());
        }
        for (var allowance : nftAllowances) {
            builder.addNftAllowances(allowance.toProtobuf());
        }
        return builder;
    }

    @Override
    void onFreeze(TransactionBody.Builder bodyBuilder) {
        bodyBuilder.setCryptoApproveAllowance(build());
    }

    @Override
    void onScheduled(SchedulableTransactionBody.Builder scheduled) {
        scheduled.setCryptoApproveAllowance(build());
    }

    @Override
    void validateChecksums(Client client) throws BadEntityIdException {
        for (var allowance : hbarAllowances) {
            allowance.validateChecksums(client);
        }
        for (var allowance : tokenAllowances) {
            allowance.validateChecksums(client);
        }
        for (var allowance : nftAllowances) {
            allowance.validateChecksums(client);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy