Asking for mosaics with aggregate bonded transaction

Ask an account to send you funds using an aggregate bonded transaction.

Prerequisites

Let’s get into some code

../../_images/aggregate-asking-for-mosaics.png

Asking for mosaics with an aggregate bonded transaction

Alice wants to ask Bob for 20 XEM.

  1. Set up both Alice’s and Bob’s accounts.
const nodeUrl = 'http://localhost:3000';
const transactionHttp = new TransactionHttp(nodeUrl);
const listener = new Listener(nodeUrl);

const alicePrivateKey = process.env.ALICE_PRIVATE_KEY as string;
const aliceAccount = Account.createFromPrivateKey(alicePrivateKey, NetworkType.MIJIN_TEST);

const bobPublicKey = 'F82527075248B043994F1CAFD965F3848324C9ABFEC506BC05FBCF5DD7307C9D';
const bobAccount = PublicAccount.createFromPublicKey(bobPublicKey, NetworkType.MIJIN_TEST);
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.ExecutionException;

import static java.time.temporal.ChronoUnit.HOURS;

class AskingForMosaicsWithAggregateBondedTransaction {

    @Test
    void askingForMosaicsWithAggregateBondedTransaction() throws ExecutionException, InterruptedException, MalformedURLException {

        // Replace with a Alice's private key
        final String alicePrivateKey = "";

        // Replace with a Bob's public key
        final String bobPublicKey = "";

        final Account aliceAccount = Account.createFromPrivateKey(alicePrivateKey, NetworkType.MIJIN_TEST);
        final PublicAccount bobPublicAccount = PublicAccount.createFromPublicKey(bobPublicKey, NetworkType.MIJIN_TEST);
const nodeUrl = 'http://localhost:3000';
const transactionHttp = new TransactionHttp(nodeUrl);
const listener = new Listener(nodeUrl);

const alicePrivateKey = process.env.ALICE_PRIVATE_KEY;
const aliceAccount = Account.createFromPrivateKey(alicePrivateKey, NetworkType.MIJIN_TEST);

const bobPublicKey = 'F82527075248B043994F1CAFD965F3848324C9ABFEC506BC05FBCF5DD7307C9D';
const bobAccount = PublicAccount.createFromPublicKey(bobPublicKey, NetworkType.MIJIN_TEST);
  1. Alice creates an aggregate bonded transaction with two inner transactions:
  1. Define the first inner transfer transaction:
  • message: “message reason” (custom, but not empty)
  • receiver: Bob address
  • signer: Alice
const transferTransaction1 = TransferTransaction.create(
    Deadline.create(),
    bobAccount.address,
    [],
    PlainMessage.create('send me 20 XEM'),
    NetworkType.MIJIN_TEST);
        final TransferTransaction transferTransaction1 = TransferTransaction.create(
            Deadline.create(2, HOURS),
            bobPublicAccount.getAddress(),
            Collections.emptyList(),
            PlainMessage.create("send me 20 XEM"),
            NetworkType.MIJIN_TEST
        );
const transferTransaction1 = TransferTransaction.create(
    Deadline.create(),
    bobAccount.address,
    [],
    PlainMessage.create('send me 20 XEM'),
    NetworkType.MIJIN_TEST);
  1. Define the second inner transfer transaction:
  • message: empty
  • receiver: Alice address
  • mosaics: 20 XEM
  • signer: Bob
const transferTransaction2 = TransferTransaction.create(
    Deadline.create(),
    aliceAccount.address,
    [XEM.createRelative(20)],
    EmptyMessage,
    NetworkType.MIJIN_TEST);
        final TransferTransaction transferTransaction2 = TransferTransaction.create(
                Deadline.create(2, HOURS),
                aliceAccount.getAddress(),
                Collections.singletonList(XEM.createRelative(BigInteger.valueOf(20))),
                PlainMessage.Empty,
                NetworkType.MIJIN_TEST
        );
const transferTransaction2 = TransferTransaction.create(
    Deadline.create(),
    aliceAccount.address,
    [XEM.createRelative(20)],
    EmptyMessage,
    NetworkType.MIJIN_TEST);

3.Wrap the defined transactions in an aggregate bonded transaction:

const aggregateTransaction = AggregateTransaction.createBonded(
    Deadline.create(),
    [transferTransaction1.toAggregate(aliceAccount.publicAccount),
        transferTransaction2.toAggregate(bobAccount)],
    NetworkType.MIJIN_TEST);

const signedTransaction = aliceAccount.sign(aggregateTransaction);
        final AggregateTransaction pullTransaction = AggregateTransaction.createBonded(
            Deadline.create(2, HOURS),
            Arrays.asList(
                transferTransaction1.toAggregate(aliceAccount.getPublicAccount()),
                transferTransaction2.toAggregate(bobPublicAccount)
            ),
            NetworkType.MIJIN_TEST
        );
const aggregateTransaction = AggregateTransaction.createBonded(
    Deadline.create(),
    [transferTransaction1.toAggregate(aliceAccount.publicAccount),
        transferTransaction2.toAggregate(bobAccount)],
    NetworkType.MIJIN_TEST);

const signedTransaction = aliceAccount.sign(aggregateTransaction);
  1. Alice signs the aggregate bonded transaction and announces it to the network, locking first 10 XEM.
const lockFundsTransaction = LockFundsTransaction.create(
    Deadline.create(),
    XEM.createRelative(10),
    UInt64.fromUint(480),
    signedTransaction,
    NetworkType.MIJIN_TEST);

const lockFundsTransactionSigned = aliceAccount.sign(lockFundsTransaction);

listener.open().then(() => {

    transactionHttp
        .announce(lockFundsTransactionSigned)
        .subscribe(x => console.log(x), err => console.error(err));

    listener
        .confirmed(aliceAccount.address)
        .pipe(
            filter((transaction) => transaction.transactionInfo !== undefined
                && transaction.transactionInfo.hash === lockFundsTransactionSigned.hash),
            mergeMap(ignored => transactionHttp.announceAggregateBonded(signedTransaction))
        )
        .subscribe(announcedAggregateBonded => console.log(announcedAggregateBonded),
            err => console.error(err));
});
        final SignedTransaction pullTransactionSigned = aliceAccount.sign(pullTransaction);

        // Creating the lock funds transaction and announce it
        final LockFundsTransaction lockFundsTransaction = LockFundsTransaction.create(
            Deadline.create(2, HOURS),
            XEM.createRelative(BigInteger.valueOf(10)),
            BigInteger.valueOf(480),
            pullTransactionSigned,
            NetworkType.MIJIN_TEST
        );

        final SignedTransaction lockFundsTransactionSigned = aliceAccount.sign(lockFundsTransaction);

        final TransactionHttp transactionHttp = new TransactionHttp("http://localhost:3000");

        transactionHttp.announce(lockFundsTransactionSigned).toFuture().get();

        System.out.println(lockFundsTransactionSigned.getHash());

        final Listener listener = new Listener("http://localhost:3000");

        listener.open().get();

        final Transaction transaction = listener.confirmed(aliceAccount.getAddress()).take(1).toFuture().get();

        transactionHttp.announceAggregateBonded(pullTransactionSigned).toFuture().get();
const lockFundsTransaction = LockFundsTransaction.create(
    Deadline.create(),
    XEM.createRelative(10),
    UInt64.fromUint(480),
    signedTransaction,
    NetworkType.MIJIN_TEST);

const lockFundsTransactionSigned = aliceAccount.sign(lockFundsTransaction);

listener.open().then(() => {

    transactionHttp
        .announce(lockFundsTransactionSigned)
        .subscribe(x => console.log(x), err => console.error(err));

    listener
        .confirmed(aliceAccount.address)
        .pipe(
            filter((transaction) => transaction.transactionInfo !== undefined
                && transaction.transactionInfo.hash === lockFundsTransactionSigned.hash),
            mergeMap(ignored => transactionHttp.announceAggregateBonded(signedTransaction))
        )
        .subscribe(announcedAggregateBonded => console.log(announcedAggregateBonded),
            err => console.error(err));
});

Note

The listener implementation changes when used on the client side (e.g., Angular, React, Vue).

If all goes well, Bob receives a notification.

What’s next?

Bob has not cosigned the transaction yet. Consider reading signing announced aggregate bonded transactions guide.

After receiving the transaction, Bob signs the transaction hash and announces the cosignature signed transaction.

As the aggregate bonded transaction has all the cosignatures required, it will be included in a block.