RootSoft / algorand-dart

Unofficial community SDK to interact with the Algorand network, for Dart & Flutter
MIT License
36 stars 16 forks source link

Atomic with app call and logicSig fails with 'msgpack decode error' #16

Closed 2i2i closed 2 years ago

2i2i commented 2 years ago

The below code (dapp_and_escrow_test) fails with error: msgpack decode error [pos 1]: only encoded map or array can be decoded into a struct

It is an atomic transaction with one app call and one logicSig payment. Atomic transactions work for me with one app call and one normal payment.

Any ideas please? (0.0.2-beta.8)

thx

Edit: The called dapp returns true if the first arg provided is 23. And the logicSig always returns true.

` Future escrowTEALTEST(algorand) async { final code = '''#pragma version 4 int 1 return '''; final result = await algorand.applicationManager.compileTEAL(code); final logicSig = LogicSignature.fromProgram(program: result.program); return logicSig; }

Future dapp_and_escrow_test() async { final algodClient = AlgodClient( apiUrl: AlgoExplorer.TESTNET_ALGOD_API_URL, ); final algorand = Algorand(algodClient: algodClient);

final words = 'flight stamp shoe envelope pool say tennis pelican seek betray bulb coast wife seminar palm case attack catalog shiver wrestle pass among float absent ugly'; final account = await Account.fromSeedPhrase(words.split(' ')); print('account.publicAddress'); print(account.publicAddress);

final params = await algorand.getSuggestedTransactionParams();

final arguments = 'int:23'.toApplicationArguments(); final stateTxn = await (ApplicationCallTransactionBuilder() ..sender = account.address ..applicationId = 25361817 ..arguments = arguments ..suggestedParams = params) .build();

final logicSig = await escrowTEALTEST(algorand); print('logicSig.signature'); print(logicSig.toAddress().encodedAddress); final ATxn = await (PaymentTransactionBuilder() ..sender = logicSig.toAddress() ..receiver = account.address ..amount = 50 ..suggestedParams = params) .build();

AtomicTransfer.group([stateTxn, ATxn]);

final stateTxnSigned = await stateTxn.sign(account); final stateTxnSignedRaw = stateTxnSigned.transaction.getEncodedTransaction(); final ATxnRaw = ATxn.getEncodedTransaction();

try { final txId = await algorand.sendRawTransactions( [stateTxnSignedRaw, ATxnRaw], waitForConfirmation: true); print(txId); return txId; } catch (ex) { print('error'); return 'error'; } }`

RootSoft commented 2 years ago

When using the sendTransactions or sendRawTransactions methods, you should always provide signed transactions or the binary form in sendRawTransactions (e.g. Encoder.encodeMessagePack(stateTxnSigned.toMessagePack())). In the code above, you fetched the underlying, unsigned base transaction from the signed transaction and tried to broadcast that to the network.

An example of Atomic Transfer can be found here

Next, the payment transaction should have been signed with the logic signature using logicSig.signTransaction(transaction: payTx);

This should be the correct code:

final words =
    'flight stamp shoe envelope pool say tennis pelican seek betray bulb coast wife seminar palm case attack catalog shiver wrestle pass among float absent ugly';
final account = await Account.fromSeedPhrase(words.split(' '));

final algorand = Algorand(
  algodClient: AlgodClient(apiUrl: AlgoExplorer.TESTNET_ALGOD_API_URL),
);

final params = await algorand.getSuggestedTransactionParams();

final arguments = 'int:23'.toApplicationArguments();
final appCallTx = await (ApplicationCallTransactionBuilder()
      ..sender = account.address
      ..applicationId = 25361817
      ..arguments = arguments
      ..suggestedParams = params)
    .build();

final logicSig = await _escrowTEALTEST(algorand);
print('logicSig.signature');
print(logicSig.toAddress().encodedAddress);

final payTx = await (PaymentTransactionBuilder()
      ..sender = logicSig.toAddress()
      ..receiver = account.address
      ..amount = 50
      ..suggestedParams = params)
    .build();

AtomicTransfer.group([appCallTx, payTx]);

final stateTxnSigned = await appCallTx.sign(account);
final paymentSigned = await logicSig.signTransaction(transaction: payTx);

try {
  final txId = await algorand.sendTransactions([
    stateTxnSigned,
    paymentSigned,
  ]);

  final result = await algorand.waitForConfirmation(txId);
  print(result);
} on AlgorandException catch (ex) {
  final cause = ex.cause;
  if (cause is DioError) {
    print(cause.response?.data['message']);
  }

  print(ex.message);
}
2i2i commented 2 years ago

thx - it works