generateL2Transaction function
Prepares a transaction to be ready to be sent to a Coordinator.
@param {Object} transaction - ethAddress and babyPubKey together @param {String} transaction.from - The account index that's sending the transaction e.g hez:DAI:4444 @param {String} transaction.to - The account index of the receiver e.g hez:DAI:2156. If it's an Exit, set to a falseable value @param {String} transaction.amount - The amount being sent as a BigInt string @param {Number} transaction.fee - The amount of tokens to be sent as a fee to the Coordinator @param {Number} transaction.nonce - The current nonce of the sender's token account @param {String} bJJ - The compressed BabyJubJub in hexadecimal format of the transaction sender @param {Object} token - The token information object as returned from the Coordinator.
@return {Object} - Contains transaction
and encodedTransaction
. transaction
is the object almost ready to be sent to the Coordinator. encodedTransaction
is needed to sign the transaction
Implementation
Future<Set<Map<String, dynamic>>> generateL2Transaction(
Map tx, String? bjj, Token token) async {
final type = tx['type'] != null ? tx['type'] : getTransactionType(tx);
final nonce = await getNonce(tx['nonce'], tx['from'], bjj, token.id);
final toAccountIndex = isHermezAccountIndex(tx['to']) ? tx['to'] : null;
final decompressedAmount =
HermezCompressedAmount.decompressAmount(tx['amount']);
final feeBigInt = getTokenAmountBigInt(tx['fee'], token.decimals!);
String? toHezEthereumAddress;
if (type == 'TransferToEthAddr') {
toHezEthereumAddress = tx['to'];
}
/* else if (type == 'TransferToBJJ') {
toHezEthereumAddress = tx['toAuxEthAddr'] != null
? tx['toAuxEthAddr']
: INTERNAL_ACCOUNT_ETH_ADDR;
}*/
Map<String, dynamic> transaction = {};
transaction.putIfAbsent('type', () => type);
transaction.putIfAbsent('tokenId', () => token.id);
transaction.putIfAbsent('fromAccountIndex', () => tx['from']);
transaction.putIfAbsent('toAccountIndex',
() => type == 'Exit' ? 'hez:${token.symbol}:1' : toAccountIndex);
transaction.putIfAbsent('toHezEthereumAddress', () => toHezEthereumAddress);
transaction.putIfAbsent(
'toBjj', () => type == 'TransferToBJJ' ? tx['to'] : null);
// Corrects precision errors using the same system used in the Coordinator
transaction.putIfAbsent(
'amount', () => decompressedAmount.toString().replaceAll(".0", ""));
transaction.putIfAbsent(
'fee', () => getFeeIndex(feeBigInt.toDouble(), decompressedAmount));
transaction.putIfAbsent('nonce', () => nonce);
transaction.putIfAbsent('requestFromAccountIndex', () => null);
transaction.putIfAbsent('requestToAccountIndex', () => null);
transaction.putIfAbsent('requestToHezEthereumAddress', () => null);
transaction.putIfAbsent('requestToBjj', () => null);
transaction.putIfAbsent('requestTokenId', () => null);
transaction.putIfAbsent('requestAmount', () => null);
transaction.putIfAbsent('requestFee', () => null);
transaction.putIfAbsent('requestNonce', () => null);
Map<String, dynamic> encodedTransaction =
await encodeTransaction(transaction);
transaction.putIfAbsent(
'id',
() => getL2TxId(
encodedTransaction['fromAccountIndex'],
encodedTransaction['tokenId'],
decompressedAmount,
encodedTransaction['nonce'],
encodedTransaction['fee']));
return {transaction, encodedTransaction};
}