github.com/hashgraph/hedera-sdk-go/v2@v2.48.0/ethereum_flow.go (about)

     1  package hedera
     2  
     3  /*-
     4   *
     5   * Hedera Go SDK
     6   *
     7   * Copyright (C) 2020 - 2024 Hedera Hashgraph, LLC
     8   *
     9   * Licensed under the Apache License, Version 2.0 (the "License");
    10   * you may not use this file except in compliance with the License.
    11   * You may obtain a copy of the License at
    12   *
    13   *      http://www.apache.org/licenses/LICENSE-2.0
    14   *
    15   * Unless required by applicable law or agreed to in writing, software
    16   * distributed under the License is distributed on an "AS IS" BASIS,
    17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    18   * See the License for the specific language governing permissions and
    19   * limitations under the License.
    20   *
    21   */
    22  
    23  import "github.com/pkg/errors"
    24  
    25  // Execute an Ethereum transaction on Hedera
    26  type EthereumFlow struct {
    27  	Transaction
    28  	ethereumData    *EthereumTransactionData
    29  	callDataFileID  *FileID
    30  	maxGasAllowance *Hbar
    31  	nodeAccountIDs  []AccountID
    32  }
    33  
    34  // Execute an Ethereum transaction on Hedera
    35  func NewEthereumFlow() *EthereumFlow {
    36  	tx := EthereumFlow{
    37  		Transaction: _NewTransaction(),
    38  	}
    39  
    40  	tx._SetDefaultMaxTransactionFee(NewHbar(20))
    41  
    42  	return &tx
    43  }
    44  
    45  // SetEthereumData sets the raw Ethereum transaction.
    46  func (transaction *EthereumFlow) SetEthereumData(data *EthereumTransactionData) *EthereumFlow {
    47  	transaction._RequireNotFrozen()
    48  	transaction.ethereumData = data
    49  	return transaction
    50  }
    51  
    52  // SetEthereumDataBytes sets the raw Ethereum transaction.
    53  func (transaction *EthereumFlow) SetEthereumDataBytes(data []byte) *EthereumFlow {
    54  	transaction._RequireNotFrozen()
    55  	temp, err := EthereumTransactionDataFromBytes(data)
    56  	if err != nil {
    57  		panic(err)
    58  	}
    59  	transaction.ethereumData = temp
    60  	return transaction
    61  }
    62  
    63  // GetEthreumData  returns the data of the Ethereum transaction
    64  func (transaction *EthereumFlow) GetEthereumData() *EthereumTransactionData {
    65  	return transaction.ethereumData
    66  }
    67  
    68  // SetCallDataFileID sets the file ID containing the call data.
    69  func (transaction *EthereumFlow) SetCallDataFileID(callData FileID) *EthereumFlow {
    70  	transaction._RequireNotFrozen()
    71  	transaction.callDataFileID = &callData
    72  	return transaction
    73  }
    74  
    75  // GetCallDataFileID returns the file ID containing the call data.
    76  func (transaction *EthereumFlow) GetCallDataFileID() FileID {
    77  	if transaction.callDataFileID == nil {
    78  		return FileID{}
    79  	}
    80  
    81  	return *transaction.callDataFileID
    82  }
    83  
    84  // SetMaxGasAllowance sets the maximum gas allowance for the transaction.
    85  func (transaction *EthereumFlow) SetMaxGasAllowance(max Hbar) *EthereumFlow {
    86  	transaction._RequireNotFrozen()
    87  	transaction.maxGasAllowance = &max
    88  	return transaction
    89  }
    90  
    91  // GetMaxGasAllowance returns the maximum gas allowance for the transaction.
    92  func (transaction *EthereumFlow) GetMaxGasAllowance() Hbar {
    93  	if transaction.maxGasAllowance == nil {
    94  		return Hbar{}
    95  	}
    96  
    97  	return *transaction.maxGasAllowance
    98  }
    99  
   100  // SetNodeAccountIDs sets the node account IDs for this Ethereum transaction.
   101  func (transaction *EthereumFlow) SetNodeAccountIDs(nodes []AccountID) *EthereumFlow {
   102  	transaction._RequireNotFrozen()
   103  	transaction.nodeAccountIDs = nodes
   104  	return transaction
   105  }
   106  
   107  // GetNodeAccountIDs returns the node account IDs for this Ethereum transaction.
   108  func (transaction *EthereumFlow) GetNodeAccountIDs() []AccountID {
   109  	return transaction.nodeAccountIDs
   110  }
   111  
   112  func (transaction *EthereumFlow) _CreateFile(callData []byte, client *Client) (FileID, error) {
   113  	fileCreate := NewFileCreateTransaction()
   114  	if len(transaction.nodeAccountIDs) > 0 {
   115  		fileCreate.SetNodeAccountIDs(transaction.nodeAccountIDs)
   116  	}
   117  
   118  	if len(callData) < 4097 {
   119  		resp, err := fileCreate.
   120  			SetContents(callData).
   121  			Execute(client)
   122  		if err != nil {
   123  			return FileID{}, err
   124  		}
   125  
   126  		receipt, err := resp.GetReceipt(client)
   127  		if err != nil {
   128  			return FileID{}, err
   129  		}
   130  
   131  		return *receipt.FileID, nil
   132  	}
   133  
   134  	resp, err := fileCreate.
   135  		SetContents(callData[:4097]).
   136  		Execute(client)
   137  	if err != nil {
   138  		return FileID{}, err
   139  	}
   140  
   141  	receipt, err := resp.GetReceipt(client)
   142  	if err != nil {
   143  		return FileID{}, err
   144  	}
   145  
   146  	fileID := *receipt.FileID
   147  
   148  	resp, err = NewFileAppendTransaction().
   149  		SetFileID(fileID).
   150  		SetContents(callData[4097:]).
   151  		Execute(client)
   152  	if err != nil {
   153  		return FileID{}, err
   154  	}
   155  
   156  	_, err = resp.GetReceipt(client)
   157  	if err != nil {
   158  		return FileID{}, err
   159  	}
   160  
   161  	return fileID, nil
   162  }
   163  
   164  // Execute executes the Transaction with the provided client
   165  func (transaction *EthereumFlow) Execute(client *Client) (TransactionResponse, error) {
   166  	if transaction.ethereumData == nil {
   167  		return TransactionResponse{}, errors.New("cannot submit ethereum transaction with no ethereum data")
   168  	}
   169  
   170  	ethereumTransaction := NewEthereumTransaction()
   171  	if len(transaction.nodeAccountIDs) > 0 {
   172  		ethereumTransaction.SetNodeAccountIDs(transaction.nodeAccountIDs)
   173  	}
   174  	dataBytes, err := transaction.ethereumData.ToBytes()
   175  	if err != nil {
   176  		return TransactionResponse{}, err
   177  	}
   178  
   179  	if transaction.maxGasAllowance != nil {
   180  		ethereumTransaction.SetMaxGasAllowanceHbar(*transaction.maxGasAllowance)
   181  	}
   182  
   183  	if transaction.callDataFileID != nil { //nolint
   184  		if len(transaction.ethereumData._GetData()) != 0 {
   185  			return TransactionResponse{}, errors.New("call data file ID provided, but ethereum data already contains call data")
   186  		}
   187  
   188  		ethereumTransaction.
   189  			SetEthereumData(dataBytes).
   190  			SetCallDataFileID(*transaction.callDataFileID)
   191  	} else if len(dataBytes) <= 5120 {
   192  		ethereumTransaction.
   193  			SetEthereumData(dataBytes)
   194  	} else {
   195  		fileID, err := transaction.
   196  			_CreateFile(dataBytes, client)
   197  		if err != nil {
   198  			return TransactionResponse{}, err
   199  		}
   200  
   201  		transaction.ethereumData._SetData([]byte{})
   202  
   203  		ethereumTransaction.
   204  			SetEthereumData(dataBytes).
   205  			SetCallDataFileID(fileID)
   206  	}
   207  
   208  	resp, err := ethereumTransaction.
   209  		Execute(client)
   210  	if err != nil {
   211  		return TransactionResponse{}, err
   212  	}
   213  
   214  	_, err = resp.GetReceipt(client)
   215  	if err != nil {
   216  		return TransactionResponse{}, err
   217  	}
   218  
   219  	return resp, nil
   220  }