Atomic Transaction Groups
In traditional finance, trading assets generally requires a trusted intermediary, like a bank or an exchange, to make sure that both sides receive what they agreed to. On the Algorand blockchain, this type of trade is implemented within the protocol as an Atomic Transfer. This simply means that transactions that are part of the transfer either all succeed or all fail. Atomic transfers allow complete strangers to trade assets without the need for a trusted intermediary, all while guaranteeing that each party will receive what they agreed to.
On Algorand, atomic transfers are implemented as irreducible batch operations, where a group of transactions are submitted as a unit and all transactions in the batch either pass or fail. This also eliminates the need for more complex solutions like hashed timelock contracts that are implemented on other blockchains. An atomic transfer on Algorand is confirmed in the same time like any other transaction. These atomic transactions can contain any type of transactions inside of the group.
Use Cases
Atomic transfers enable use cases such as:
-
Circular Trades- Alice pays Bob if and only if Bob pays Claire if and only if Claire pays Alice.
-
Group Payments- Everyone pays or no one pays.
-
Decentralized Exchanges- Trade one asset for another without going through a centralized exchange.
-
Distributed Payments- Payments to multiple recipients.
-
Pooled Transaction Fees- One transaction pays the fees of others.
Process Overview
To implement an atomic transfer, generate all of the transactions that will be involved in the transfer and then group those transactions together. The result of grouping is that each transaction is assigned the same group ID. Once all transactions contain this group ID, the transactions can be split up and sent to their respective senders to be authorized. A single party can then collect all the authorized transactions and submit them to the network together.
How-to
Below you will find how to create and send atomic transaction groups using Algokit Utils in Python and Typescript
""" Create a transaction group that will execute atomically Either all transactions succeed, or they all fail """ algorand_client.new_group().add_payment( # First transaction: Payment from A to B PaymentParams( sender=account_a.address, receiver=account_b.address, amount=AlgoAmount(algo=1), note=b"First payment in atomic group", ) ).add_payment( # Second transaction: Payment from B to C PaymentParams( sender=account_b.address, receiver=account_c.address, amount=AlgoAmount( micro_algo=500_000 ), # B sends half of what they received to C note=b"Second payment in atomic group", ) ).send() # Send the atomic group of transactions
// Create a transaction group that will execute atomically // Either all transactions succeed, or they all fail await algorand .newGroup() // First transaction: Payment from A to B .addPayment({ sender: randomAccountA, receiver: randomAccountB, amount: algo(1), note: 'First payment in atomic group', }) // Second transaction: Payment from B to C .addPayment({ sender: randomAccountB, receiver: randomAccountC, amount: algo(0.5), // B sends half of what they received to C note: 'Second payment in atomic group', }) // Send the atomic group of transactions .send()
Step by Step in Goal
The next guide will illustrate how atomic transaction groups can be created following a step by step approach using goal.
Create Transactions
Create two or more (up to 16 total) unsigned transactions of any type. Read about transaction types in the Transactions Overview section.
This could be done by a service or by each party involved in the transaction. For example, an asset exchange application can create the entire atomic transfer and allow individual parties to sign from their location.
The example below illustrates creating, grouping, and signing transactions atomically and submitting to the network.
$ goal clerk send --from=my-account-a<PLACEHOLDER> --to=my-account-c<PLACEHOLDER> --fee=1000 --amount=100000 --out=unsginedtransaction1.txn"
$ goal clerk send --from=my-account-b<PLACEHOLDER> --to=my-account-a<PLACEHOLDER> --fee=1000 --amount=200000 --out=unsginedtransaction2.txn"
At this point, these are just individual transactions. The next critical step is to combine them and then calculate the group ID.
Group Transactions
The result of this step is what ultimately guarantees that a particular transaction belongs to a group and is not valid if sent alone (even if properly signed). A group-id is calculated by hashing the concatenation of a set of related transactions. The resulting hash is assigned to the Group field within each transaction. This mechanism allows anyone to recreate all transactions and recalculate the group ID to verify that the contents are as agreed upon by all parties. Ordering of the transaction set must be maintained.
$ cat unsignedtransaction1.tx unsignedtransaction2.tx > combinedtransactions.tx$ goal clerk group -i combinedtransactions.tx -o groupedtransactions.tx -d data -w yourwallet
Split Transactions Goal Only
At this point the transaction set must be split to allow distributing each component transaction to the appropriate wallet for authorization.
# keys in distinct wallets$ goal clerk split -i groupedtransactions.tx -o splitfiles -d data -w yourwallet
Wrote transaction 0 to splitfiles-0Wrote transaction 1 to splitfiles-1
# distribute files for authorization
Sign Transactions
With a group ID assigned, each transaction sender must authorize their respective transaction.
# sign from single wallet containing all keys$ goal clerk sign -i groupedtransactions.tx -o signout.tx -d data -w yourwallet
# -- OR --
# sign from distinct wallets$ goal clerk sign -i splitfiles-0 -o splitfiles-0.sig -d data -w my_wallet_1$ goal clerk sign -i splitfiles-1 -o splitfiles-1.sig -d data -w my_wallet_2
Assemble Transaction Group
All authorized transactions are now assembled into an array, maintaining the original transaction ordering, which represents the transaction group.
# combine signed transactions filescat splitfiles-0.sig splitfiles-1.sig > signout.tx
Send Transaction Group
The transaction group is now broadcast to the network.
goal clerk rawsend -f signout.tx -d data -w yourwallet