Transaction Structure
Each block on a blockchain, including Cosmos-based ones like Osmosis, are constructed of a series of transactions.
Each transaction, in turn, has its own internal structure. This document describes the structure of those transactions.
Retrieving a block
You can retrieve a single block by any one of:
- using the RPC API
- using the REST API
- running a full node (using
osmosisd
)
For our examples, we use osmosisd
to retrieve a single block:
osmosisd query block 2836990
The above retrieves the block 2836990
. The result generally is in json without any formatting,
so we run it through jq
to clean it up:
osmosisd query block 2836990 | jq '.'
The result is a large json file. To keep this document readable, we will not reproduce the whole thing here, only its structure. The entire file is available at block-2836990.json.
The main outline is as follows:
Outline
{
"block_id": {
"hash": "CC3F7B8C711393E0A6BF42F743C1E96A5E147C03CD2ACF50E15DF93515E4DCC5",
"parts": {
"total": 2,
"hash": "EB26807B983730D1B87D821D4A7E8BFDC83E78CDB4E5B89DD5A28C78CAE1931E"
}
},
"block": {
"header": {
"version": {
"block": "11",
"app": "1"
},
"chain_id": "osmosis-1",
"height": "2836990",
"time": "2022-01-17T17:14:01.589129908Z",
"last_block_id": {
"hash": "10419816E363D36492987AA2FBC1F09653DB026B2A6787F01B69C98EA54ADAEF",
"parts": {
"total": 3,
"hash": "468EAE52F145F55319BD41B6A62629E2424CF53B91D7AE28BD7E2C07D9B2F7B3"
}
},
"last_commit_hash": "D17D43C66F440B7B0FD23D085A195B839D022D8365B318B27484DACACC718F30",
"data_hash": "4C5F9C3A26A245945D5F6C7BB3854C2A8E8A2A54C3459DA135E93C5A5F916D6F",
"validators_hash": "6CE355CD08D5B5C775845B87F04C295E6F35FA6FD5353DA668482406B7360F45",
"next_validators_hash": "DE379515F7B35ABB57E5FECA27EB485731058EE045F26DE8AB9C8555B3FFD83D",
"consensus_hash": "A967D55FACBBA19AB96149048F2476C4657EC03D25B78A81AF5B8F0A08F61DFF",
"app_hash": "7356565B67989D373662FC5553E97A206BB8A58385FF42698F1A411C698555F3",
"last_results_hash": "DE3F62111363F655A6596B6DE8E1348FF46FE9A7859F695CCE59E4EA0F98253F",
"evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855",
"proposer_address": "1B002B6EBEB8653C721301B1B56472B1B4DE7247"
},
"data": {
"txs": [
"Cp0CCpoCCiovb3Ntb3Npcy5nYW1tLnYxYmV0YTEuTXNnU3dhcEV4YWN0QW1vdW50SW4S6wEKK29zbW8xZTBkbXpkeGRtcnd5ZjQ2bmNtNXNxY2xrZGFuM21hcTVrNWp2ZHgSSQjcBBJEaWJjLzk4N0MxN0IxMUFCQzJCMjAwMTkxNzhBQ0U2MjkyOUZFOTg0MDIwMkNFNzk0OThFMjlGRThFNUNCMDJCN0MwQTQSSQjjBBJEaWJjLzI3Mzk0RkIwOTJEMkVDQ0Q1NjEyM0M3NEYzNkU0QzFGOTI2MDAxQ0VBREE5Q0E5N0VBNjIyQjI1RjQxRTVFQjISCQgBEgV1b3NtbxoRCgV1b3NtbxIIMTUwMDAwMDAiCDE1MDAwMDAwEmYKUgpGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQI3Vc8hzNbQdpBrbHj8hELzzBskwVqQrad15VgsFn1RtBIECgIIARi+9AMSEAoKCgV1b3NtbxIBMBCAiXoaQD9uPzOcom2NJGzrHEkgytg585ybULi93PnLNKMsECGCNH5gH46Cmiv504ULlyMsTfiyYInMGo39jYIahbDcDLk=",
"Cp0CCpoCCiovb3Ntb3Npcy5nYW1tLnYxYmV0YTEuTXNnU3dhcEV4YWN0QW1vdW50SW4S6wEKK29zbW8xbDR1NTZsN2N2eDhuMG42Yzd3NjUwazAydno2N3F1ZGpsY3V0ODkSSQjcBBJEaWJjLzk4N0MxN0IxMUFCQzJCMjAwMTkxNzhBQ0U2MjkyOUZFOTg0MDIwMkNFNzk0OThFMjlGRThFNUNCMDJCN0MwQTQSSQjjBBJEaWJjLzI3Mzk0RkIwOTJEMkVDQ0Q1NjEyM0M3NEYzNkU0QzFGOTI2MDAxQ0VBREE5Q0E5N0VBNjIyQjI1RjQxRTVFQjISCQgBEgV1b3NtbxoRCgV1b3NtbxIIMTUwMDAwMDAiCDE1MDAwMDAwEmYKUgpGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQK1cR2MtFWdtiyO/qORycJYvhuEqF1W9howno2FFP/11xIECgIIARjM8wMSEAoKCgV1b3NtbxIBMBCAiXoaQHCrHmPW89D7BdROgVeDs0Uz4jz95MW/abhLOrsOT/fdS6UQ+Qvzj+htQe7TtKYGRfuK9UsyjcV6gIN7I8K0fbQ=",
"CpsCCpgCCiovb3Ntb3Npcy5nYW1tLnYxYmV0YTEuTXNnU3dhcEV4YWN0QW1vdW50SW4S6QEKK29zbW8xZTBkbXpkeGRtcnd5ZjQ2bmNtNXNxY2xrZGFuM21hcTVrNWp2ZHgSSQjcBBJEaWJjLzk4N0MxN0IxMUFCQzJCMjAwMTkxNzhBQ0U2MjkyOUZFOTg0MDIwMkNFNzk0OThFMjlGRThFNUNCMDJCN0MwQTQSSQjjBBJEaWJjLzI3Mzk0RkIwOTJEMkVDQ0Q1NjEyM0M3NEYzNkU0QzFGOTI2MDAxQ0VBREE5Q0E5N0VBNjIyQjI1RjQxRTVFQjISCQgBEgV1b3NtbxoQCgV1b3NtbxIHMTUwMDAwMCIHMTUwMDAwMBJmClIKRgofL2Nvc21vcy5jcnlwdG8uc2VjcDI1NmsxLlB1YktleRIjCiECN1XPIczW0HaQa2x4/IRC88wbJMFakK2ndeVYLBZ9UbQSBAoCCAEYv/QDEhAKCgoFdW9zbW8SATAQgIl6GkD7MtpJPRKqLCvv6b+1LXPjwq+tx/dk5qZDh9AIFbGdDDTptSLBuId7tzXeIqf9hXt6UqOzxbU/OrMAJ/LvOnEY",
"Cu8DCuwDCiovb3Ntb3Npcy5nYW1tLnYxYmV0YTEuTXNnU3dhcEV4YWN0QW1vdW50SW4SvQMKK29zbW8xMDI2anQycjl5ZnhtbmMzcm12cDBoZ2VlOWd3a215azl1M2t0aHESSQjQAxJEaWJjLzFEQzQ5NUZDRUZEQTA2OEEzODIwRjkwM0VEQkQ3OEI5NDJGQkQyMDREN0U5M0QzQkEyQjQzMkU5NjY5RDFBNTkSSQjNAxJEaWJjLzU5NzNDMDY4NTY4MzY1RkZGNDBERURDRjFBMUNCNzU4MkI2MTE2QjczMUNEMzFBMTIyMzFBRTI1RTIwQjg3MUYSCgjhAxIFdW9zbW8SSAgHEkRpYmMvN0M0RDYwQUE5NUU1QTc1NThCMEEzNjQ4NjA5NzlDQTM0QjdGRjhBQUYyNTVCODdBRjlFODc5Mzc0NDcwQ0VDMBJICAgSRGliYy8yNzM5NEZCMDkyRDJFQ0NENTYxMjNDNzRGMzZFNEMxRjkyNjAwMUNFQURBOUNBOTdFQTYyMkIyNUY0MUU1RUIyGk8KRGliYy8yNzM5NEZCMDkyRDJFQ0NENTYxMjNDNzRGMzZFNEMxRjkyNjAwMUNFQURBOUNBOTdFQTYyMkIyNUY0MUU1RUIyEgcxMDAwMDAwIgcxMDAwMDAwEloKUgpGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQNutTEMkmT7rngHNX19j0uA2419X1nPhqlDkZ/cqAk2exIECgIIARjMig8SBBCAiXoaQIoIWm3CI9esFCLaeQF9Aj6bEjgm1WItBdDnHeye5DJgEBBbaoc8iQQ3oC1pCX+BtxZVP8NpTLCeW6O/pW84jds=",
...
...
"CqQDCqEDCiovb3Ntb3Npcy5nYW1tLnYxYmV0YTEuTXNnU3dhcEV4YWN0QW1vdW50SW4S8gIKK29zbW8xNng5cmhqeTZ0ZjJkNDJ2MzRucXBna3B1d2tzY2d2dG0yYTBndDISSAgKEkRpYmMvRTY5MzFGNzgwNTdGN0NDNURBMEZENkNFRjgyRkYzOTM3M0E2RTA0NTJCRjFGRDc2OTEwQjkzMjkyQ0YzNTZDMRIJCAkSBXVvc21vEkkI3AQSRGliYy85ODdDMTdCMTFBQkMyQjIwMDE5MTc4QUNFNjI5MjlGRTk4NDAyMDJDRTc5NDk4RTI5RkU4RTVDQjAyQjdDMEE0EkkI4wQSRGliYy8yNzM5NEZCMDkyRDJFQ0NENTYxMjNDNzRGMzZFNEMxRjkyNjAwMUNFQURBOUNBOTdFQTYyMkIyNUY0MUU1RUIyGk8KRGliYy8yNzM5NEZCMDkyRDJFQ0NENTYxMjNDNzRGMzZFNEMxRjkyNjAwMUNFQURBOUNBOTdFQTYyMkIyNUY0MUU1RUIyEgc0MDg5MzU0Igc0MDg5MzU0EloKUgpGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQMQpu8Flaqd04iiBIBzIIqj4QDB8Lvgf8aMsLlQeX33nBIECgIIARjV5AsSBBCAiXoaQBFa9dKWBzls4GjqeEukgDTNZ9UYoXEa7vLfD5dzJ+HHFkZKGLsTP9brRdSOlMuq0iF9EGvMnoInd7leRYMQEl0="
]
},
"evidence": {
"evidence": null
},
"last_commit": {
"height": "2836989",
"round": 0,
"block_id": {
"hash": "10419816E363D36492987AA2FBC1F09653DB026B2A6787F01B69C98EA54ADAEF",
"parts": {
"total": 3,
"hash": "468EAE52F145F55319BD41B6A62629E2424CF53B91D7AE28BD7E2C07D9B2F7B3"
}
},
"signatures": [
{
"block_id_flag": 2,
"validator_address": "CB5A63B91E8F4EE8DB935942CBE25724636479E0",
"timestamp": "2022-01-17T17:14:01.597493021Z",
"signature": "/HG0b07XVaIDfBScZyT1tQ4iWvIvvvOeFAD58VvF46QMDh7F9ytxXlviso60bPmvrN/RXblgRB5G7XVEH0s9Cg=="
},
{
"block_id_flag": 2,
"validator_address": "16A169951A878247DBE258FDDC71638F6606D156",
"timestamp": "2022-01-17T17:14:01.679151429Z",
"signature": "cOh/DCVUfRMjhz5uEjmPUvr6YzM0rrjBSPYrcCIYExB+R2B/PmoctvE3HrYsXTTvPQOKEEGNpYf2Z9TaanyPDQ=="
},
...
{
"block_id_flag": 2,
"validator_address": "A677203440E86562D6DD475D0C2CA555EC01F803",
"timestamp": "2022-01-17T17:14:01.620734893Z",
"signature": "zONA/uGCfiOaRpHTMkMCtsnwUqmo1NnjRdQketHTZq6iCNbiGM5lI4QmPZtyg3bmk0GMNZ1kW06p1jrdAojkCQ=="
}
]
}
}
}
As the purpose of this document is to describe the transaction structure, rather than the block structure, we will not spend too much time on the block structure.
Briefly, the important points are:
.block_id
: contains the hash of the block.block
: the block data itself.block.header
: important information about the block, especially:.block.header.chain_id
.block.header.height
.block.header.last_block_id
.block.data.txs
: the transactions on which we will focus.block.last_commit
: information about the last commit prior to this one
The transactions themselves are in .block.data.txs
. This is an array, each entry
of which is an individual transaction.
The block we have chosen, 2836990, contains 64 transactions:
$ osmosisd query block 2836990 | jq -r '.block.data.txs | length'
64
Each transaction is base64-encoded data. For example, the first two are:
"Cp0CCpoCCiovb3Ntb3Npcy5nYW1tLnYxYmV0YTEuTXNnU3dhcEV4YWN0QW1vdW50SW4S6wEKK29zbW8xZTBkbXpkeGRtcnd5ZjQ2bmNtNXNxY2xrZGFuM21hcTVrNWp2ZHgSSQjcBBJEaWJjLzk4N0MxN0IxMUFCQzJCMjAwMTkxNzhBQ0U2MjkyOUZFOTg0MDIwMkNFNzk0OThFMjlGRThFNUNCMDJCN0MwQTQSSQjjBBJEaWJjLzI3Mzk0RkIwOTJEMkVDQ0Q1NjEyM0M3NEYzNkU0QzFGOTI2MDAxQ0VBREE5Q0E5N0VBNjIyQjI1RjQxRTVFQjISCQgBEgV1b3NtbxoRCgV1b3NtbxIIMTUwMDAwMDAiCDE1MDAwMDAwEmYKUgpGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQI3Vc8hzNbQdpBrbHj8hELzzBskwVqQrad15VgsFn1RtBIECgIIARi+9AMSEAoKCgV1b3NtbxIBMBCAiXoaQD9uPzOcom2NJGzrHEkgytg585ybULi93PnLNKMsECGCNH5gH46Cmiv504ULlyMsTfiyYInMGo39jYIahbDcDLk=",
"Cp0CCpoCCiovb3Ntb3Npcy5nYW1tLnYxYmV0YTEuTXNnU3dhcEV4YWN0QW1vdW50SW4S6wEKK29zbW8xbDR1NTZsN2N2eDhuMG42Yzd3NjUwazAydno2N3F1ZGpsY3V0ODkSSQjcBBJEaWJjLzk4N0MxN0IxMUFCQzJCMjAwMTkxNzhBQ0U2MjkyOUZFOTg0MDIwMkNFNzk0OThFMjlGRThFNUNCMDJCN0MwQTQSSQjjBBJEaWJjLzI3Mzk0RkIwOTJEMkVDQ0Q1NjEyM0M3NEYzNkU0QzFGOTI2MDAxQ0VBREE5Q0E5N0VBNjIyQjI1RjQxRTVFQjISCQgBEgV1b3NtbxoRCgV1b3NtbxIIMTUwMDAwMDAiCDE1MDAwMDAwEmYKUgpGCh8vY29zbW9zLmNyeXB0by5zZWNwMjU2azEuUHViS2V5EiMKIQK1cR2MtFWdtiyO/qORycJYvhuEqF1W9howno2FFP/11xIECgIIARjM8wMSEAoKCgV1b3NtbxIBMBCAiXoaQHCrHmPW89D7BdROgVeDs0Uz4jz95MW/abhLOrsOT/fdS6UQ+Qvzj+htQe7TtKYGRfuK9UsyjcV6gIN7I8K0fbQ=",
We can decode these by passing them through a base64 decoder. The correct arguments depend on your
platform, but generally are of the form base64 -D
. We do not recommend simply passing them through
to the terminal, as this is binary-encoded data, specifically protobufs.
osmosisd query block 2836990 | jq '.block.data.txs[0]' | base64 -D > outfile
The outfile
will contain raw protobuf data.
Protobuf data does not contain its own structre with it. It requires the .proto
file to understand
and interpret the fields, including converting them to a readable json format.
Fortunately, osmosisd
provides some basic tools for querying individual transactions. It does not,
however, let you retrieve any arbitrary transaction, as you must pass it "events":
osmosisd query txs --events '<type>.<key>=<value>' [--height <height>]
If you already know the events, you can retrieve individual transactions.
Fortunately, if you are dealing with an individual block, you can get the transactions - and have osmosisd
decode the protobufs for you - by making the event be the block height:
osmosisd query txs --height 2836990 --events 'tx.height=2836990' -o json
The results should match the number of transactions we have in the block:
{
"total_count": "64",
"count": "30",
"page_number": "1",
"page_total": "3",
"limit": "30",
"txs": [
...
The total_count
is 64, as we expected. osmosisd query txs
is paginated, so it only returned the first 30 of 64,
with this being page 1.
By passing the total transactions to retrieve, we can avoid the pagination:
osmosisd query txs --height 2836990 --events 'tx.height=2836990' -o json --limit 64
For convenience, we also will pass it through jq
for formatting, and save the results to a file:
osmosisd query txs --height 2836990 --events 'tx.height=2836990' -o json --limit 64 | jq '.' > outfile.json
The entire block's transactions is available at txs-block-2836990.json.
We now have the ability to look at transactions:
# to see all transactions
cat outfile.json | jq '.txs'
# to see an individual transaction
cat outfile.json | jq '.txs[1]'
Below is part of the transaction at index 1 of the above block.
transaction 1
{
"height": "2836990",
"txhash": "5BBC27779EA33FC99C319D74CFE730DC2A3102277D75410E75F2F9F5ED259BFE",
"codespace": "",
"code": 0,
"data": "0A2C0A2A2F6F736D6F7369732E67616D6D2E763162657461312E4D7367537761704578616374416D6F756E74496E",
"raw_log": "<raw data>",
"logs": [
{
"msg_index": 0,
"log": "",
"events": [
{
"type": "coin_received",
"attributes": [
{
"key": "receiver",
"value": "osmo1thscstwxp87g0ygh7le3h92f9ff4sel9y9d2eysa25p43yf43rysk7jp93"
},
{
"key": "amount",
"value": "15000000uosmo"
},
{
"key": "receiver",
"value": "osmo1l4u56l7cvx8n0n6c7w650k02vz67qudjlcut89"
},
{
"key": "amount",
"value": "289236271ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4"
},
...
]
},
{
"type": "coin_spent",
"attributes": [
{
"key": "spender",
"value": "osmo1l4u56l7cvx8n0n6c7w650k02vz67qudjlcut89"
},
{
"key": "amount",
"value": "15000000uosmo"
},
{
"key": "spender",
"value": "osmo1thscstwxp87g0ygh7le3h92f9ff4sel9y9d2eysa25p43yf43rysk7jp93"
},
{
"key": "amount",
"value": "289236271ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4"
},
...
]
},
{
"type": "message",
"attributes": [
{
"key": "action",
"value": "/osmosis.gamm.v1beta1.MsgSwapExactAmountIn"
},
{
"key": "sender",
"value": "osmo1l4u56l7cvx8n0n6c7w650k02vz67qudjlcut89"
},
{
"key": "sender",
"value": "osmo1thscstwxp87g0ygh7le3h92f9ff4sel9y9d2eysa25p43yf43rysk7jp93"
},
...
]
},
{
"type": "token_swapped",
"attributes": [
{
"key": "module",
"value": "gamm"
},
{
"key": "sender",
"value": "osmo1l4u56l7cvx8n0n6c7w650k02vz67qudjlcut89"
},
{
"key": "pool_id",
"value": "604"
},
{
"key": "tokens_in",
"value": "15000000uosmo"
},
{
"key": "tokens_out",
"value": "289236271ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4"
},
{
"key": "module",
"value": "gamm"
},
{
"key": "sender",
"value": "osmo1l4u56l7cvx8n0n6c7w650k02vz67qudjlcut89"
},
{
"key": "pool_id",
"value": "611"
},
{
"key": "tokens_in",
"value": "289236271ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4"
},
{
"key": "tokens_out",
"value": "3802225ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2"
},
...
]
},
{
"type": "transfer",
"attributes": [
{
"key": "recipient",
"value": "osmo1thscstwxp87g0ygh7le3h92f9ff4sel9y9d2eysa25p43yf43rysk7jp93"
},
{
"key": "sender",
"value": "osmo1l4u56l7cvx8n0n6c7w650k02vz67qudjlcut89"
},
{
"key": "amount",
"value": "15000000uosmo"
},
{
"key": "recipient",
"value": "osmo1l4u56l7cvx8n0n6c7w650k02vz67qudjlcut89"
},
{
"key": "sender",
"value": "osmo1thscstwxp87g0ygh7le3h92f9ff4sel9y9d2eysa25p43yf43rysk7jp93"
},
{
"key": "amount",
"value": "289236271ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4"
},
...
]
}
]
}
],
"info": "",
"gas_wanted": "2000000",
"gas_used": "183726",
"tx": {
"@type": "/cosmos.tx.v1beta1.Tx",
"body": {
"messages": [
{
"@type": "/osmosis.gamm.v1beta1.MsgSwapExactAmountIn",
"sender": "osmo1l4u56l7cvx8n0n6c7w650k02vz67qudjlcut89",
"routes": [
{
"poolId": "604",
"tokenOutDenom": "ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4"
},
{
"poolId": "611",
"tokenOutDenom": "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2"
},
{
"poolId": "1",
"tokenOutDenom": "uosmo"
}
],
"tokenIn": {
"denom": "uosmo",
"amount": "15000000"
},
"tokenOutMinAmount": "15000000"
}
],
"memo": "",
"timeout_height": "0",
"extension_options": [],
"non_critical_extension_options": []
},
"auth_info": {
"signer_infos": [
{
"public_key": {
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "ArVxHYy0VZ22LI7+o5HJwli+G4SoXVb2GjCejYUU//XX"
},
"mode_info": {
"single": {
"mode": "SIGN_MODE_DIRECT"
}
},
"sequence": "63948"
}
],
"fee": {
"amount": [
{
"denom": "uosmo",
"amount": "0"
}
],
"gas_limit": "2000000",
"payer": "",
"granter": ""
}
},
"signatures": [
"cKseY9bz0PsF1E6BV4OzRTPiPP3kxb9puEs6uw5P991LpRD5C/OP6G1B7tO0pgZF+4r1SzKNxXqAg3sjwrR9tA=="
]
},
"timestamp": "2022-01-17T17:14:01Z"
}
Each transaction has an identical structure. The differences are in the details inside each structure:
transaction 2
{
"height": "2836990",
"txhash": "5BBC27779EA33FC99C319D74CFE730DC2A3102277D75410E75F2F9F5ED259BFE",
"codespace": "",
"code": 0,
"data": "0A2C0A2A2F6F736D6F7369732E67616D6D2E763162657461312E4D7367537761704578616374416D6F756E74496E",
"raw_log": "<raw data>",
"logs": [
{
"msg_index": 0,
"log": "",
"events": [
{ ... },
{ ... },
...
]
}
],
"info": "",
"gas_wanted": "2000000",
"gas_used": "183726",
"tx": {
"@type": "/cosmos.tx.v1beta1.Tx",
"body": {
"messages": [
{
"@type": "/osmosis.gamm.v1beta1.MsgSwapExactAmountIn",
"sender": "osmo1l4u56l7cvx8n0n6c7w650k02vz67qudjlcut89",
"routes": [
{
"poolId": "604",
"tokenOutDenom": "ibc/987C17B11ABC2B20019178ACE62929FE9840202CE79498E29FE8E5CB02B7C0A4"
},
{
"poolId": "611",
"tokenOutDenom": "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2"
},
{
"poolId": "1",
"tokenOutDenom": "uosmo"
}
],
"tokenIn": {
"denom": "uosmo",
"amount": "15000000"
},
"tokenOutMinAmount": "15000000"
}
],
"memo": "",
"timeout_height": "0",
"extension_options": [],
"non_critical_extension_options": []
},
"auth_info": {
"signer_infos": [
{
"public_key": {
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "ArVxHYy0VZ22LI7+o5HJwli+G4SoXVb2GjCejYUU//XX"
},
"mode_info": {
"single": {
"mode": "SIGN_MODE_DIRECT"
}
},
"sequence": "63948"
}
],
"fee": {
"amount": [
{
"denom": "uosmo",
"amount": "0"
}
],
"gas_limit": "2000000",
"payer": "",
"granter": ""
}
},
"signatures": []
},
"timestamp": "2022-01-17T17:14:01Z"
}
Each transaction is structured of the following key elements. The more complex ones will be described in detail below.
height
: height of the block in which the transaction is includedtxhash
: hash of the transaction, obviously excluding thetxhash
itselfraw_log
: raw data of the messages; compressed, original format of all of the content of.logs
logs
: array of individual log messages that make up the contents of the transaction; details belowgas_wanted
: how much gas the transaction sender allowedgas_used
: how much gas actually was usedtx
: the originally sent transaction, from the sender; this, in turn, triggered the various messages that comprise the transaction; will be described in detail belowtimestamp
: timestamp of the original transaction
Let's explore the parts that require more detail. In addition, for practical examples, we will link to individual analyses of several transactions.
tx
The tx
field contains the original transaction that was sent to the blockchain that triggered the
rest of the messages.
This tx
could be something simple - transfer 10osmo from account A to account B - or something more
complex, like swapping tokens via a liquidity pool or bonding.
When you use the Osmosis Web App or osmosisd
to send a transaction, it
composes and sends the single message in the tx
field.
"@type": "/cosmos.tx.v1beta1.Tx",
"body": {
"messages": [
{
"@type": "<transaction type>",
"sender": "<sender account>",
...
// fields that are unique to the transaction type
}
],
"memo": "",
"timeout_height": "0",
"extension_options": [],
"non_critical_extension_options": []
},
"auth_info": {
"signer_infos": [
{
"public_key": {
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "ArVxHYy0VZ22LI7+o5HJwli+G4SoXVb2GjCejYUU//XX"
},
"mode_info": {
"single": {
"mode": "SIGN_MODE_DIRECT"
}
},
"sequence": "63948"
}
],
"fee": {
"amount": [
{
"denom": "uosmo",
"amount": "0"
}
],
"gas_limit": "2000000",
"payer": "",
"granter": ""
}
},
"signatures": []
Exploring the fields:
@type
: the base transaction type. In our block, every single one of the transactions has the same base type,/cosmos.tx.v1beta1.Tx
. This is defined by the cosmos SDK.body
: the core body of the transaction.auth_info
: who signed this message when it was sent to the chain?
signer
The auth_info
field contains the signer. This normally will be signed by a Cosmos public key
signified by auth_info.signer_infos[0].public_key.@type
, while the .key
field will give the public key.
This public key should match the sender of the messages in the body
, and is checked by the chain upon submission.
body
The body
contains the original transaction. It contains one or more messages
, all of which must succeed
for the transaction to succeed, i.e. a transaction. Most of the transactions are likely to have a single message, but more can exist.
The fields of message always will contain at least two fields:
@type
: the specific type of the message within the application, for example,/osmosis.gamm.v1beta1.MsgSwapEactAmountIn
sender
: the sender of the message
The rest of the fields are specific to the @type
of message. Once you know the type of message, you can look in the
source code for the protobuf definition of the message type.
Each Cosmos SDK app implementation will have its own modules and therefore its own message types, in addition to basic ones inherited from the Cosmos SDK.
When the Cosmos app, in this example osmosisd, and specifically the target module, in our example gamm
, receives the message, it in turn
does internal activities, including
sending various messages that comprise the fulfillment of the requested transaction. These are recorded in the logs
.
logs
The logs
represent the various emitted messages that describe the internal components of fulfillment of the requested transaction.
There can be 0, 1 or multiple entries in the logs
field.
Each message in logs
has just 3 properties:
msg_index
: increments from 0 for messages within the transaction; if there are multiple messages, each will have an incrementedmsg_index
, although the 0th index may be optional.log
: often blankevents
: events emitted by the application
Each entry in events
has just two properties:
type
: the type of event, which has meaning solely to the applicationattributes
: an array of key-value structures
The type
is a simple string, which has meaning only in the context of the application, for example:
"type": "coin_received",
The attributes
are an array of key-value structures, with just two keys: key
and value
. For example:
{
"key": "receiver",
"value": "osmo1thscstwxp87g0ygh7le3h92f9ff4sel9y9d2eysa25p43yf43rysk7jp93"
},
Since the attributes are an array of objects with two properties - key
and value
- applications may use
several of them in series to complete a message. Check out the analyzed transactions below for a better understanding.
Sample transactions: