Sending multiple transactions together

Send transactions to different accounts at the same time, using aggregate transactions.

Use case

Dan wants to send mosaics to Alice and Bob. He could achieve this sending a couple of TransferTransactions. However, to make sure Alice and Bob receive the funds at the same time, he decides to use an AggregateTransaction.

../../_images/aggregate-sending-payouts1.png

Sending transactions to different recipients atomically

Prerequisites

Method #01: Using the SDK

  1. Open a new file, and define two transfer transactions to send 10 symbol.xym to different recipients.
// replace with network type
const networkType = NetworkType.TEST_NET;
// replace with sender private key
const privateKey = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
const account = Account.createFromPrivateKey(privateKey, networkType);
// replace with address
const aliceAddress =  'TCHBDE-NCLKEB-ILBPWP-3JPB2X-NY64OE-7PYHHE-32I';
const aliceAccount = Address.createFromRawAddress(aliceAddress);
// replace with address
const bobAddress = 'TB6Q5E-YACWBP-CXKGIL-I6XWCH-DRFLTB-KUK34I-YJQ';
const bobAccount = Address.createFromRawAddress(bobAddress);
// replace with symbol.xym id
const networkCurrencyMosaicId = new MosaicId('5E62990DCAC5BE8A');
// replace with network currency divisibility
const networkCurrencyDivisibility = 6;

const mosaic = new Mosaic (networkCurrencyMosaicId,
    UInt64.fromUint(10 * Math.pow(10, networkCurrencyDivisibility)));

const aliceTransferTransaction = TransferTransaction.create(
    Deadline.create(),
    aliceAccount,
    [mosaic],
    PlainMessage.create('payout'),
    networkType);
const bobTransferTransaction = TransferTransaction.create(
    Deadline.create(),
    bobAccount,
    [mosaic],
    PlainMessage.create('payout'),
    networkType);
// replace with network type
const networkType = symbol_sdk_1.NetworkType.TEST_NET;
// replace with sender private key
const privateKey = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA';
const account = symbol_sdk_1.Account.createFromPrivateKey(privateKey, networkType);
// replace with address
const aliceAddress = 'TCHBDE-NCLKEB-ILBPWP-3JPB2X-NY64OE-7PYHHE-32I';
const aliceAccount = symbol_sdk_1.Address.createFromRawAddress(aliceAddress);
// replace with address
const bobAddress = 'TB6Q5E-YACWBP-CXKGIL-I6XWCH-DRFLTB-KUK34I-YJQ';
const bobAccount = symbol_sdk_1.Address.createFromRawAddress(bobAddress);
// replace with symbol.xym id
const networkCurrencyMosaicId = new symbol_sdk_1.MosaicId('5E62990DCAC5BE8A');
// replace with network currency divisibility
const networkCurrencyDivisibility = 6;
const mosaic = new symbol_sdk_1.Mosaic(networkCurrencyMosaicId, symbol_sdk_1.UInt64.fromUint(10 * Math.pow(10, networkCurrencyDivisibility)));
const aliceTransferTransaction = symbol_sdk_1.TransferTransaction.create(symbol_sdk_1.Deadline.create(), aliceAccount, [mosaic], symbol_sdk_1.PlainMessage.create('payout'), networkType);
const bobTransferTransaction = symbol_sdk_1.TransferTransaction.create(symbol_sdk_1.Deadline.create(), bobAccount, [mosaic], symbol_sdk_1.PlainMessage.create('payout'), networkType);
            NetworkType networkType = repositoryFactory.getNetworkType().toFuture().get();

            // replace with sender private key
            String privateKey = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
            Account account = Account.createFromPrivateKey(privateKey, networkType);
            // replace with address
            String aliceAddress = "TCHBDE-NCLKEB-ILBPWP-3JPB2X-NY64OE-7PYHHE-32I";
            Address aliceAccount = Address.createFromRawAddress(aliceAddress);
            // replace with address
            String bobAddress = "TB6Q5E-YACWBP-CXKGIL-I6XWCH-DRFLTB-KUK34I-YJQ";
            Address bobAccount = Address.createFromRawAddress(bobAddress);

            NetworkCurrency networkCurrency = repositoryFactory.getNetworkCurrency().toFuture().get();

            Mosaic mosaic = networkCurrency.createRelative(BigDecimal.valueOf(10));

            TransferTransaction aliceTransferTransaction = TransferTransactionFactory
                .create(networkType, aliceAccount, Collections.singletonList(mosaic), PlainMessage.create("payout"))
                .build();

            TransferTransaction bobTransferTransaction = TransferTransactionFactory
                .create(networkType, bobAccount, Collections.singletonList(mosaic), PlainMessage.create("payout"))
                .build();
  1. Wrap both transactions in an AggregateTransaction, adding Dan’s public account as the required signer. As one private key—Dan’s account—can sign all the transactions in the aggregate, we can define the transaction as complete.
const aggregateTransaction = AggregateTransaction.createComplete(
    Deadline.create(),
    [aliceTransferTransaction.toAggregate(account.publicAccount),
        bobTransferTransaction.toAggregate(account.publicAccount)],
    networkType,
    [],
    UInt64.fromUint(2000000));
const aggregateTransaction = symbol_sdk_1.AggregateTransaction.createComplete(symbol_sdk_1.Deadline.create(), [aliceTransferTransaction.toAggregate(account.publicAccount),
    bobTransferTransaction.toAggregate(account.publicAccount)], networkType, [], symbol_sdk_1.UInt64.fromUint(2000000));
            AggregateTransaction aggregateTransaction = AggregateTransactionFactory.createComplete(networkType, Arrays
                .asList(aliceTransferTransaction.toAggregate(account.getPublicAccount()),
                    bobTransferTransaction.toAggregate(account.getPublicAccount()))).maxFee(BigInteger.valueOf(2000000))
                .build();
  1. Sign and announce the transaction with Dan’s account.
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash = '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = account.sign(aggregateTransaction, networkGenerationHash);
// replace with node endpoint
const nodeUrl = 'http://api-01.us-east-1.096x.symboldev.network:3000';
const repositoryFactory = new RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();

transactionHttp
    .announce(signedTransaction)
    .subscribe((x) => console.log(x), (err) => console.error(err));
// replace with meta.networkGenerationHash (nodeUrl + '/node/info')
const networkGenerationHash = '1DFB2FAA9E7F054168B0C5FCB84F4DEB62CC2B4D317D861F3168D161F54EA78B';
const signedTransaction = account.sign(aggregateTransaction, networkGenerationHash);
// replace with node endpoint
const nodeUrl = 'http://api-01.us-east-1.096x.symboldev.network:3000';
const repositoryFactory = new symbol_sdk_1.RepositoryFactoryHttp(nodeUrl);
const transactionHttp = repositoryFactory.createTransactionRepository();
transactionHttp
    .announce(signedTransaction)
    .subscribe((x) => console.log(x), (err) => console.error(err));
            String generationHash = repositoryFactory.getGenerationHash().toFuture().get();
            SignedTransaction signedTransaction = account.sign(aggregateTransaction, generationHash);

            try (Listener listener = repositoryFactory.createListener()) {
                listener.open().get();
                TransactionService transactionService = new TransactionServiceImpl(repositoryFactory);
                transactionService.announce(listener, signedTransaction).toFuture().get();

            }