execute method

Future<ExecuteResult> execute(
  1. Algorand algorand, {
  2. int waitRounds = 5,
})

Send the transaction group to the network and wait until it's committed to a block. An error will be thrown if submission or execution fails.

The composer's status must be SUBMITTED or lower before calling this method, since execution is only allowed once. If submission is successful, this composer's status will update to SUBMITTED. If the execution is also successful, this composer's status will update to COMMITTED.

Note: a group can only be submitted again if it fails.

@return If the execution is successful, resolves to an object containing the confirmed round for this transaction, the txIDs of the submitted transactions, an array of results containing one element for each method call transaction in this group, and the raw transaction response from algod. If a method has no return value (void), then the method results array will contain null for that return value.

Implementation

Future<ExecuteResult> execute(Algorand algorand, {int waitRounds = 5}) async {
  if (_status == AtcStatus.COMMITED) {
    throw ArgumentError('Status shows this is already commited');
  }

  if (waitRounds < 0) {
    throw ArgumentError('wait round for execute should be non-negative.');
  }

  // Submit the transactions
  await submit(algorand, waitForConfirmation: false);

  var indexToWait = 0;
  for (var i = 0; i < signedTxns.length; i++) {
    if (methodMap.containsKey(i)) {
      indexToWait = i;
      break;
    }
  }

  final txInfo = await algorand.waitForConfirmation(
    signedTxns[indexToWait].transactionId,
    timeout: waitRounds,
  );

  final retList = <ReturnValue>[];
  _status = AtcStatus.COMMITED;

  for (var i = 0; i < transactions.length; i++) {
    if (!methodMap.containsKey(i)) continue;
    var currentTxInfo = txInfo;
    final txId = signedTxns[i].transactionId;

    if (i != indexToWait) {
      try {
        final response = await algorand.getPendingTransactionById(txId);
        currentTxInfo = response;
      } on AlgorandException catch (ex) {
        retList.add(ReturnValue(
          transactionId: txId,
          rawValue: null,
          value: null,
          method: methodMap[i],
          parseError: ex,
          txInfo: null,
        ));

        continue;
      }
    }

    if (methodMap[i]?.returns.type == Returns.VoidRetType) {
      retList.add(ReturnValue(
        transactionId: currentTxInfo.transaction.transactionId,
        rawValue: null,
        value: null,
        method: methodMap[i],
        parseError: null,
        txInfo: currentTxInfo,
      ));

      continue;
    }

    if (currentTxInfo.logs.isEmpty) {
      throw ArgumentError('App call transaction did not log a return value');
    }

    final retLine =
        base64Decode(currentTxInfo.logs[currentTxInfo.logs.length - 1]);
    if (!_checkLogRet(retLine)) {
      throw ArgumentError('App call transaction did not log a return value');
    }

    final abiEncoded =
        Array.copyOfRange(retLine, ABI_RET_HASH.length, retLine.length);

    Object? decoded;
    Object? parseError;
    try {
      final methodRetType = methodMap[i]?.returns.parsedType;
      decoded = methodRetType?.decode(Uint8List.fromList(abiEncoded));
    } catch (ex) {
      parseError = ex;
    }

    retList.add(ReturnValue(
      transactionId: currentTxInfo.transaction.transactionId,
      rawValue: Uint8List.fromList(abiEncoded),
      value: decoded,
      method: methodMap[i],
      parseError: parseError,
      txInfo: currentTxInfo,
    ));
  }

  return ExecuteResult(
    confirmedRound: BigInt.from(txInfo.confirmedRound ?? 0),
    transactionIds: getTransactionIds(),
    methodResults: retList,
  );
}