Download OpenAPI specification:Download
This API provides endpoints from a node for integration with the Radix ledger.
WARNING
The Core API is NOT intended to be available on the public web. It is designed to be accessed in a private network.
The Core API is separated into three:
The Core API is a low level API primarily designed for network integrations such as exchanges, ledger analytics providers, or hosted ledger data dashboards where detailed ledger data is required and the integrator can be expected to run their node to provide the Core API for their own consumption.
For a higher level API, see the Gateway API.
For node monitoring, see the System API.
The Data API and Construction API is inspired from Rosetta API most notably:
There are a few notable exceptions to note:
EntityIdentifier
rather than AccountIdentifier
OperationGroup
rather than related_operations
to express related
operationsFuture versions of the api will aim towards a fully-compliant Rosetta API.
All endpoints are enabled when running a node with the exception of two endpoints, each of which need to be manually configured to access:
/transactions
endpoint must be enabled with configuration api.transaction.enable=true
.
This is because the transactions endpoint requires additional database storage which may not
be needed for users who aren't using this endpoint/key/sign
endpoint must be enable with configuration api.sign.enable=true
. This is a
potentially dangerous endpoint if accessible publicly so it must be enabled manually.We have found success with generating clients against the api.yaml specification. See https://openapi-generator.tech/ for more details.
The OpenAPI generator only supports openapi version 3.0.0 at present, but you can change 3.1.0 to 3.0.0 in the first line of the spec without affecting generation.
The Data API can be used to synchronize a full or partial view of the ledger, transaction by transaction.
The Construction API can be used to construct and submit transactions to the network.
Unlike the Rosetta Construction API specification, this Construction API selects UTXOs on behalf of the caller. This has the unfortunate side effect of not being able to support high frequency transactions from a single account due to UTXO conflicts. This will be addressed in a future release.
Entities represent something that can hold resource balances and data objects. For example, a public key account is an entity which can hold token balances on behalf of a private key holder.
An Operation is an update which occurs on an Entity. There are two types of Operations:
There are different types of entities on Radix, each of which can contain certain resources and data objects.
The following table describes which resources and data objects are allowed for a given type of entity.
Overall, there are four main types of entities on Radix:
system
holds XRD
tokens which have been staked to this validator. A validator is represented by its Bech32 validator address.If an entity identifier references a sub-entity, it should be considered a separate entity to the primary entity.
For example, for tracking the balance of an Account entity, any operations against an entity identifier
with a non-empty entity_identifier.sub_entity
should be ignored, even if the entity_identifier.address
matches.
Account addresses, Validator addresses and Token RRIs are all Bech32 encoded.
A Bech32 encoding consists of a prefix which is an ASCII human readable part "HRP", followed by the character "1", followed by an encoded data payload, encoded as 32 values (5 bits) per character.
Assuming an address is legal, you can extract its HRP as the string before the last '1'. This can be used to distinguish between Account, Validator and Token/RRI addresses.
rdx
on mainnet. The data part encodes the account's public key.rv
on mainnet. The data part encodes the validator's public key._rr
on mainnet.
As an example, the mainnet address of the native token, XRD, is xrd_rr1qy5wfsfh
.
The data part of the Bech32 encoding encodes the token's unique radix engine address on ledger.
This radix engine address is hex 01
for XRD,
and presently, hex 03 | SHA256(SHA256(signer_public_key_compressed_33_bytes | symbol_in_utf8_bytes)
for user-created tokens, where | denotes the byte concatenation operator.The Account and Validator HRPs and the Token HRP suffix for the current network should be fetched from the
/network/configuration
endpoint.
It likely will not be necessary to actually decode the data parts of the Bech32 encodings, but if you do need to, you should be warned that Radix addresses are not Segwit addresses. Many Bech32 libraries assume a Segwit encoding, so may fail to extract the data from a Radix address.
In particular, the Segwit encoding assumes the first 5-bit-character of the 5-bit-per-character encoded data is a witness version, and that this is followed by the witness programme bytes, encoded into 5-bit chunks, padded with zeroes if necessary. Radix encoding just encodes its data bytes into 5-bit chunks with padded zeroes - without an initial single character version prefix. In other words, the padding and interpretation of the encoded data differs between Radix and Segwit addresses.
There are further restrictions on which resource movement and data updates and how operations must be combined. The following table describes what user actions (ledger updates that can be submitted as a transaction) are available.
prepared_stake
entity
with a specific validator. Once XRD is in this entity, at some point the system will move this
XRD to a Validator entity and mint StakeUnits into the originating account.prepared_unstake
entity. Once StakeUnits is in this entity, at some point the system will destroy this
StakeUnits and transfer XRD from the Validator entity into your exiting_stake
entity. Once
the unlocking period is over the system will move that XRD from the exiting_stake
entity into your
account.UnclaimedREAddr
and creating a
TokenData
and TokenMetadata
data object.The Radix network has no concept of blocks. Instead transactions are managed in a flat ordered list. A hash chain is formed from these transactions called a Transaction Accumulator. A Transaction Accumulator represents a point in time of the ledger with a valid state.
The transaction accumulator along with the index forms a State Identifier.
state_version required | integer <int64> (LongNumber) |
transaction_accumulator required | string Accumulator hash representing all transactions which occurred up to |
{- "state_version": 46001,
- "transaction_accumulator": "2892a2359c37ab02116d46f742c684234d5aa9658682815f8221fc0b613101e0"
}
A Transaction is an atomic state update to the ledger. It consists of one or more OperationGroups, each of which consist of one or more Operations.
A Committed Transaction has additional information such as the State Identifier which results after committing the transaction.
A transaction which has been committed on ledger.
required | object (TransactionIdentifier) |
required | object (StateIdentifier) |
required | Array of objects (OperationGroup) Transactions are split into operation groups which are roughly equivalent to ledger accounting entries where all credits have an equivalent debit amount. |
required | object (CommittedTransactionMetadata) |
{- "metadata": {
- "size": 360,
- "signed_by": {
- "hex": "02aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b6"
}, - "fee": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "72000000000000000"
}, - "hex": "07030e7094728c8d065c5db696977696bea9094f67bcfd4c021f99ec784e24023b0000000c0100210000000000000000000000000000000000000000000000000000ffcb9e57d4000002004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007c13bc4b1c16827082c00000008000002004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007ad6192165e31dff02c000002004506000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329b63364718000000000b015584aed8375f30b22a2203b77dbe15e5dc0a3618fb45ea30ee54a6ebe0054b673a471ad2214b7bd06c4228083643b57e095787c9fb01443e1c3d6890d28f60cf",
- "timestamp": 1627407310726
}, - "committed_state_identifier": {
- "state_version": 40898,
- "transaction_accumulator": "5ea573f2e31640d177047d14122f1015c262f0d14d522596068784406aa1d88f"
}, - "transaction_identifier": {
- "hash": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d99337193811842"
}, - "operation_groups": [
- {
- "metadata": {
- "action": {
- "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "72000000000000000"
}, - "from": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33",
- "type": "BurnTokens"
}
}, - "operations": [
- {
- "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "-2400000000000000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "030e7094728c8d065c5db696977696bea9094f67bcfd4c021f99ec784e24023b0000000c"
}, - "substate_operation": "SHUTDOWN"
}, - "entity_identifier": {
- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
}, - "type": "Resource"
}, - {
- "metadata": {
- "substate_data_hex": "06000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007c13bc4b1c16827082c0000"
}, - "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "2399999999928000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000000"
}, - "substate_operation": "BOOTUP"
}, - "entity_identifier": {
- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
}, - "type": "Resource"
}
]
}, - {
- "metadata": {
- "action": {
- "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "24000000000000000000000000"
}, - "from": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33",
- "to": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88",
- "type": "TokenTransfer"
}
}, - "operations": [
- {
- "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "-2399999999928000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000000"
}, - "substate_operation": "SHUTDOWN"
}, - "entity_identifier": {
- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
}, - "type": "Resource"
}, - {
- "metadata": {
- "substate_data_hex": "06000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007ad6192165e31dff02c0000"
}, - "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "2375999999928000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000001"
}, - "substate_operation": "BOOTUP"
}, - "entity_identifier": {
- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
}, - "type": "Resource"
}, - {
- "metadata": {
- "substate_data_hex": "06000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329b63364718000000"
}, - "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "24000000000000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000002"
}, - "substate_operation": "BOOTUP"
}, - "entity_identifier": {
- "address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
}, - "type": "Resource"
}
]
}
]
}
Similar to the Rosetta API, both reading and writing to the ledger use the same Address and Operation objects.
Every state change is expressed as an Operation which operates on a single Entity. Any state change which consists of two accounts (such as a token transfer) thus requires at least two Operations, one which debits the sender and one which credits the receiver.
Unlike Rosetta, operations are more explicitly linked via Operation Groups. Each Operation Group then represents a well formed accounting entry where credits and debits are equivalent (unless minting or burning occurred).
required | Array of objects (Operation) A group of operations representing a complete state update. |
metadata | object Metadata for the operation group. |
{- "metadata": {
- "action": {
- "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "24000000000000000000000000"
}, - "from": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33",
- "to": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88",
- "type": "TokenTransfer"
}
}, - "operations": [
- {
- "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "-2399999999928000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000000"
}, - "substate_operation": "SHUTDOWN"
}, - "entity_identifier": {
- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
}, - "type": "Resource"
}, - {
- "metadata": {
- "substate_data_hex": "06000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007ad6192165e31dff02c0000"
}, - "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "2375999999928000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000001"
}, - "substate_operation": "BOOTUP"
}, - "entity_identifier": {
- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
}, - "type": "Resource"
}, - {
- "metadata": {
- "substate_data_hex": "06000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329b63364718000000"
}, - "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "24000000000000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000002"
}, - "substate_operation": "BOOTUP"
}, - "entity_identifier": {
- "address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
}, - "type": "Resource"
}
]
}
Operations operate on a single Entity and are associated with a single Amount update and/or a single Data update.
amount
property represents either a positive or negative change in balance of some token.data
property represents either the creation or deletion of a data object.type required | string The type of operation: Resource, Data, or ResourceAndData. |
required | object (EntityIdentifier) |
object (Substate) | |
object (ResourceAmount) | |
object (Data) | |
metadata | object Metadata for the operation. |
{- "metadata": {
- "substate_data_hex": "06000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007ad6192165e31dff02c0000"
}, - "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "2375999999928000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000001"
}, - "substate_operation": "BOOTUP"
}, - "entity_identifier": {
- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
}, - "type": "Resource"
}
An Entity Identifier uniquely describes an entity which may have arbitrary balances and arbitrary data objects. An Entity Identifier may further specify a Sub Address which should be treated as a separate unique entity.
The interpretation of Entity Identifiers is discussed in detail in the Structure section.
address required | string The top level identifier for an entity. |
object (SubEntity) |
{- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33",
- "sub_entity": {
- "address": "prepared_stake"
}
}
A signed amount of a resource.
value required | string (BigInteger) ^-?[0-9]+$ |
required | object (ResourceIdentifier) |
{- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "2375999999928000000000000000"
}
A Resource Identifier uniquely describes either some token or stake units for a validator.
type required | string The type of resource. |
rri required | string The Radix Resource Identifier "RRI" of the token. |
{- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}
A Data update is the creation or destruction of a data object.
At any given time, an address will have up to one created-but-not-deleted data object of each type.
action required | string Data action to take on |
required | object (DataObject) |
{- "action": "CREATE",
- "data_object": {
- "round": 0,
- "type": "RoundData",
- "timestamp": 1627330381600
}
}
This example walks through how to track XRD balances across all accounts. To do this we need the following:
Let's start by performing a call to /transactions
with state_version
of 0
and limit
of 1000
. This will retrieve the first 1000 transactions on ledger, including the genesis
transaction.
Be sure to also match the network_identifier
with the network the node is using.
{
"network_identifier": {
"network": "mainnet"
},
"state_identifier": {
"state_version": 0
},
"limit": 1000
}
The corresponding java client code looks like:
TransactionsApi api = new TransactionsApi();
NetworkIdentifier networkIdentifier = new NetworkIdentifier().network("mainnet");
void main() {
PartialStateIdentifier stateIdentifier = new PartialStateIdentifier().stateVersion(0L);
CommittedTransactionsRequest committedTransactionsRequest = new CommittedTransactionsRequest()
.networkIdentifier(networkIdentifier)
.limit(1000L)
.stateIdentifier(stateIdentifier);
CommittedTransactionsResponse response = api.transactionsPost(committedTransactionsRequest);
}
Let's now expand our code to extract all XRD balance changes.
To extract account token balance changes in a transaction:
amount
existsamount.resource_identifier.type
is Token
rri
of the token is xrd_rr1qy5wfsfh
entity_identifier
and sum each balance_change
This gives us the change in XRD balance in that entity due to the transaction, in units of 10^(-18).
This forms the basis of tracking account balances over time.
TransactionsApi api = new TransactionsApi();
NetworkIdentifier networkIdentifier = new NetworkIdentifier().network("mainnet");
/**
* Returns true if the operation contains an XRD balance change, otherwise returns false
*/
boolean isXrd(Operation operation) {
if (operation.getAmount() == null) {
return false;
}
ResourceIdentifier identifier = op.getAmount().getResourceIdentifier();
if (!(identifier instanceof TokenResourceIdentifier)) {
return false;
}
TokenResourceIdentifier tokenResourceIdentifier = (TokenResourceIdentifier) identifier;
return tokenResourceIdentifier.getRri().equals("xrd_rr1qy5wfsfh");
}
/**
* Returns the XRD balance change which occured on every entity from a set
* of operation groups.
*/
Map<EntityIdentifier, BigInteger> operationGroupsToBalanceChanges(Stream<OperationGroup> operationGroups) {
return operationGroups
.flatMap(group -> group.getOperations().stream())
.filter(this::isXrd)
.collect(Collectors.groupingBy(
Operation::getEntityIdentifier,
Collectors.mapping(
op -> new BigInteger(op.getAmount().getValue()),
Collectors.reducing(BigInteger.ZERO, BigInteger::add)
)
));
}
void main() {
PartialStateIdentifier stateIdentifier = new PartialStateIdentifier().stateVersion(0L);
CommittedTransactionsRequest committedTransactionsRequest = new CommittedTransactionsRequest()
.networkIdentifier(networkIdentifier)
.limit(1000L)
.stateIdentifier(stateIdentifier);
CommittedTransactionsResponse response = api.transactionsPost(committedTransactionsRequest);
// Extract out operation groups
Stream<OperationGroup> operationGroups = response.getTransactions().stream()
.flatMap(txn -> txn.getOperationGroups().stream());
Map<EntityIdentifier, BigInteger> balanceChanges = operationGroupsToBalanceChanges(operationGroups);
}
Now that we can compute balance change we can now start updating some balance store.
In this example we simply use a hash map from entity to balance. In your system you may store these changes in a persistent database.
TransactionsApi api = new TransactionsApi();
NetworkIdentifier networkIdentifier = new NetworkIdentifier().network("mainnet");
/**
* Our balance store
*/
Map<EntityIdentifier, BigInteger> balances = new HashMap<>();
/**
* Returns true if the operation contains an XRD balance change, otherwise returns false
*/
boolean isXrd(Operation operation) {
if (operation.getAmount() == null) {
return false;
}
ResourceIdentifier identifier = op.getAmount().getResourceIdentifier();
if (!(identifier instanceof TokenResourceIdentifier)) {
return false;
}
TokenResourceIdentifier tokenResourceIdentifier = (TokenResourceIdentifier) identifier;
return tokenResourceIdentifier.getRri().equals("xrd_rr1qy5wfsfh");
}
/**
* Returns the XRD balance change which occured on every entity from a set
* of operation groups.
*/
Map<EntityIdentifier, BigInteger> operationGroupsToBalanceChanges(Stream<OperationGroup> operationGroups) {
return operationGroups
.flatMap(group -> group.getOperations().stream())
.filter(this::isXrd)
.collect(Collectors.groupingBy(
Operation::getEntityIdentifier,
Collectors.mapping(
op -> new BigInteger(op.getAmount().getValue()),
Collectors.reducing(BigInteger.ZERO, BigInteger::add)
)
));
}
/**
* Updates the balance store.
*/
void updateStore(Map<EntityIdentifier, BigInteger> balanceChanges) {
balanceChanges.forEach((identifier, value) -> balances.merge(identifier, value, BigInteger::add));
}
void main() throws ApiException {
PartialStateIdentifier stateIdentifier = new PartialStateIdentifier().stateVersion(0L);
CommittedTransactionsRequest committedTransactionsRequest = new CommittedTransactionsRequest()
.networkIdentifier(networkIdentifier)
.limit(1000L)
.stateIdentifier(stateIdentifier);
CommittedTransactionsResponse response = api.transactionsPost(committedTransactionsRequest);
// Extract out operation groups
Stream<OperationGroup> operationGroups = response.getTransactions().stream()
.flatMap(txn -> txn.getOperationGroups().stream());
Map<EntityIdentifier, BigInteger> balanceChanges = operationGroupsToBalanceChanges(operationGroups);
updateStore(balanceChanges);
}
So far we've only been requesting for the initial 1000 transactions on ledger. We will now want to continually sync as the ledger progresses.
To do this, we will keep our own current stateVersion and update it with the latest stateVersion we've seen. On a persistent database, it will be important to update the stateVersion and ledger updates atomically so that the sync process can handle process crashes gracefully and restart in a consistent manner.
We can now add continually check for updates on ledger and keep our own state up to date. This can easily look something like a cronjob process which periodically updates a local database.
TransactionsApi api = new TransactionsApi();
NetworkIdentifier networkIdentifier = new NetworkIdentifier().network("mainnet");
/**
* Our balance store
*/
long currentStateVersion = 0;
Map<EntityIdentifier, BigInteger> balances = new HashMap<>();
/**
* Returns true if the operation contains an XRD balance change, otherwise returns false
*/
boolean isXrd(Operation operation) {
if (operation.getAmount() == null) {
return false;
}
ResourceIdentifier identifier = op.getAmount().getResourceIdentifier();
if (!(identifier instanceof TokenResourceIdentifier)) {
return false;
}
TokenResourceIdentifier tokenResourceIdentifier = (TokenResourceIdentifier) identifier;
return tokenResourceIdentifier.getRri().equals("xrd_rr1qy5wfsfh");
}
/**
* Returns the XRD balance change which occured on every entity from a set
* of operation groups.
*/
Map<EntityIdentifier, BigInteger> operationGroupsToBalanceChanges(Stream<OperationGroup> operationGroups) {
return operationGroups
.flatMap(group -> group.getOperations().stream())
.filter(this::isXrd)
.collect(Collectors.groupingBy(
Operation::getEntityIdentifier,
Collectors.mapping(
op -> new BigInteger(op.getAmount().getValue()),
Collectors.reducing(BigInteger.ZERO, BigInteger::add)
)
));
}
/**
* Retrieves the current state version
*/
long loadStateVersion() {
return this.currentStateVersion;
}
/**
* Updates the balance store.
*/
void updateStore(long currentStateVersion, long nextStateVersion, Map<EntityIdentifier, BigInteger> balanceChanges) {
// Sanity check, in case we have multiple updater to our store
assert(this.currentStateVersion == currentStateVersion);
this.currentStateVersion = nextStateVersion;
balanceChanges.forEach((identifier, value) -> balances.merge(identifier, value, BigInteger::add));
}
/**
* Requests for new transactions from a node and then updates the balance store
*/
void update() throws ApiException {
long stateVersion = loadStateVersion();
PartialStateIdentifier stateIdentifier = new PartialStateIdentifier().stateVersion(stateVersion);
CommittedTransactionsRequest committedTransactionsRequest = new CommittedTransactionsRequest()
.networkIdentifier(networkIdentifier)
.limit(1000L)
.stateIdentifier(stateIdentifier);
CommittedTransactionsResponse response = api.transactionsPost(committedTransactionsRequest);
// Extract out operation groups
Stream<OperationGroup> operationGroups = response.getTransactions().stream()
.flatMap(txn -> txn.getOperationGroups().stream());
Map<EntityIdentifier, BigInteger> balanceChanges = operationGroupsToBalanceChanges(operationGroups);
long nextStateVersion = stateVersion + txns.size();
// Update stateVersion and balances, on a database these must be updated atomically together
updateStore(stateVersion, nextStateVersion, balanceChanges);
}
void main() throws Exception {
while (true) {
update();
Thread.sleep(1000L);
}
}
Building off of the Track XRD Balances example, we can simply remove the filter on only tracking XRD
and build a complete mapping of assets owned by every entity Entity -> Resource -> Amount
.
TransactionsApi api = new TransactionsApi();
NetworkIdentifier networkIdentifier = new NetworkIdentifier().network("mainnet");
/**
* Our balance store
*/
long currentStateVersion = 0;
Map<EntityIdentifier, Map<ResourceIdentifier, BigInteger>> balances = new HashMap<>();
/**
* Returns the token balance change which occured on every entity from a set
* of operation groups.
*/
Map<EntityIdentifier, Map<ResourceIdentifier, BigInteger>> operationGroupsToBalanceChanges(Stream<OperationGroup> operationGroups) {
return operationGroups
.flatMap(group -> group.getOperations().stream())
.filter(operation -> operation.getAmount() != null)
.collect(Collectors.groupingBy(
Operation::getEntityIdentifier,
Collectors.groupingBy(
op -> op.getAmount().getResourceIdentifier(),
Collectors.mapping(
op -> new BigInteger(op.getAmount().getValue()),
Collectors.reducing(BigInteger.ZERO, BigInteger::add)
)
)
)
);
}
/**
* Retrieves the current state version
*/
long loadStateVersion() {
return this.currentStateVersion;
}
/**
* Updates the balance store.
*/
void updateStore(long currentStateVersion, long nextStateVersion, Map<EntityIdentifier, Map<ResourceIdentifier, BigInteger>> balanceChanges) {
// Sanity check, in case we have multiple updater to our store
assert(this.currentStateVersion == currentStateVersion);
this.currentStateVersion = nextStateVersion;
balanceChanges.forEach((identifier, balanceMap) -> {
balanceMap.forEach((resource, value) ->
balances.merge(identifier, Map.of(resource, value), (b0, b1) ->
Stream.concat(b0.entrySet().stream(), b1.entrySet().stream()).collect(
Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.reducing(BigInteger.ZERO, BigInteger::add))
)
)
)
);
});
}
/**
* Requests for new transactions from a node and then updates the balance store
*/
void update() throws ApiException {
long stateVersion = loadStateVersion();
PartialStateIdentifier stateIdentifier = new PartialStateIdentifier().stateVersion(stateVersion);
CommittedTransactionsRequest committedTransactionsRequest = new CommittedTransactionsRequest()
.networkIdentifier(networkIdentifier)
.limit(1000L)
.stateIdentifier(stateIdentifier);
CommittedTransactionsResponse response = api.transactionsPost(committedTransactionsRequest);
// Extract out operation groups
Stream<OperationGroup> operationGroups = response.getTransactions().stream()
.flatMap(txn -> txn.getOperationGroups().stream());
Map<EntityIdentifier, Map<ResourceIdentifier, BigInteger>> balanceChanges = operationGroupsToBalanceChanges(operationGroups);
// Update stateVersion and balances, on a database these must be updated atomically together
updateStore(stateVersion, nextStateVersion, balanceChanges);
}
void main() throws Exception {
while (true) {
update();
Thread.sleep(1000L);
}
}
The above examples pull through the balances for any Entity, but typically you'll just want to pull down usable balances in an account - that is, balances against an account entity.
To do this, we can check filter entity_identifier
to those which have an address
starting rdx1
,
and no sub_entity
. We filter out sub-entities because these are separate entities/balances to the
core account, used by the system for staking.
For more information, and to support non-mainnet addresses, see the Structure and Addressing sections.
See the Addressing section for details on determining non-mainnet addresses.
The operation.substate.substate_identifier.identifier
gives a hex-encoded identifier for the UTXO used in that
transaction. If operation.substate.substate_operation
is BOOTUP
, the UTXO was created, and if SHUTDOWN
, it
was spent.
This can be used to track live UTXOs.
Before saving a copy of a transaction to an index, you should check that the parent accumulator matches the accumulator you have on record. Whilst we don't anticipate a need to rollback the ledger, this accumulator check could be used to detect this (and can be used to rollback an index to the point where the accumulators agree).
If you wish to also check the consistency of this accumulator, the following should be true:
post_transaction_state_accumulator = SHA256(SHA256(pre_transaction_state_accumulator | transaction_identifier_hash))
Where |
is the byte concatenation operator. Note that this uses two rounds of SHA256. The first maps from
64 bytes to 32 bytes, the second from 32 bytes to 32 bytes.
If you care about the timestamps that various transactions were committed, you can track the RoundData
data object under the system
entity.
Then, timestamp
in RoundData
gives a UNIX timestamp in milliseconds, derived from votes of each validator
of what the current wall clock time is. It is not guaranteed to be increasing and should only be used for
convenience and not as an accurate representation of the actual time of commit.
Let's now go through an example of how to transfer XRD using the API.
For the purpose of our example, let's say we want to:
TRANSFER 10.5 XRD FROM rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88 TO rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33
First we need to specify the entities identifiers to be used. In our case, we have two entity identifiers, one for the sender and one for the receiver.
Sender Entity Identifier:
EntityIdentifier sender() {
return new EntityIdentifier()
.address("rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88");
}
Receiver Entity Identifier:
EntityIdentifier receiver() {
return new EntityIdentifier()
.address("rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33");
}
Next we will need the Resource Identifier for the XRD Token which will be transferred.
XRD is Radix ledger's native token, used for staking and to pay fees. It is the only
token allowed with the symbol xrd
, and has a reserved radix engine address of 1
(01
in hex).
On mainnet, its RRI is xrd_rr1qy5wfsfh and it's resource identifier is:
TokenResourceIdentifier token() {
return new TokenResourceIdentifier()
.rri("xrd_rr1qy5wfsfh")
.type("Token");
}
Given our resource identifier we can now create resource balance changes. This will
be expressed as a Resource Amount. All amounts are expressed as 10^-18
subunits.
Thus, since we are transferring 1.5 XRD
this translates to a value of
1500000000000000000
or the following amounts:
Sender Amount:
Amount senderAmount() {
return new Amount()
.resourceIdentifier(token())
.value("-1500000000000000000");
}
Receiver Amount:
Amount receiverAmount() {
return new Amount()
.resourceIdentifier(token())
.value("1500000000000000000");
}
We now combine our amounts with our Entity Identifiers to create Operations.
"Resource"
is the type of our Operation since we are manipulating resource balances.
Sender Operation:
Operation senderOperation() {
return new Operation()
.entityIdentifier(sender())
.amount(senderAmount())
.type("Resource");
}
Receiver Operation:
Operation receiverOperation() {
return new Operation()
.entityIdentifier(receiver())
.amount(receiverAmount())
.type("Resource");
}
We then combine operations into a group. Note that the sender operation must be first.
OperationGroup operationGroup() {
return new OperationGroup()
.addOperationsItem(senderOperation())
.addOperationsItem(receiverOperation());
}
The last thing we need to add is to specify the fee payer account entity identifier. In this case it will be the same account as the sender.
We can now also add the network_identifier
and with this structure we can submit this
to /construction/build
. This network_identifier
needs to match the network identifier
of the node.
ConstructionBuildRequest constructionBuildRequest() {
return new ConstructionBuildRequest()
.addOperationsGroupItem(operationGroup())
.feePayer(sender())
.networkIdentifier(new NetworkIdentifier().network("mainnet"));
}
void main() {
ConstructionApi api = new ConstructionApi();
ConstructionBuildRequest request = constructionBuildRequest();
ConstructionBuildResponse response = api.constructionBuildPost(request);
}
After submitting to /construction/build
, we can take the unsigned_transaction
and parse it
through /construction/parse
.
ConstructionApi api = new ConstructionApi();
ConstructionParseResponse sendParseRequest(String unsignedTransactionHex) {
ConstructionParseRequest request = new ConstructionParseRequest()
.unsignedTransaction(unsignedTransactionHex);
return api.constructionParsePost(request);
}
void main() {
ConstructionBuildRequest request = constructionBuildRequest();
ConstructionBuildResponse response = api.constructionBuildPost(request);
String unsignedTransactionHex = response.getUnsignedTransaction();
ConstructionParseResponse response = sendParseRequest(unsigendTransactionHex);
System.out.println(response);
}
The response in json would look like:
{
"metadata": {
"fee": {
"resource_identifier": {
"rri": "xrd_rr1qy5wfsfh",
"type": "Token"
},
"value": "72000000000000000"
}
},
"operation_groups": [
{
"operations": [
{
"amount": {
"resource_identifier": {
"rri": "xrd_rr1qy5wfsfh",
"type": "Token"
},
"value": "-96000000000000000000000000"
},
"substate": {
"substate_identifier": {
"identifier": "4db58b950fcf446140dd945c6adfd06daa0b520f7eddf0467583d96babff579d00000002"
},
"substate_operation": "SHUTDOWN"
},
"entity_identifier": {
"address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
},
"type": "Resource"
},
{
"metadata": {
"substate_data_hex": "06000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab010000000000000000000000000000000000000000004f68ca6c8d0d7e082c0000"
},
"amount": {
"resource_identifier": {
"rri": "xrd_rr1qy5wfsfh",
"type": "Token"
},
"value": "95999999928000000000000000"
},
"substate": {
"substate_identifier": {
"identifier": "65f61dba3ed40a438c4694e8947f73530c1c6ca6b8115371c05c6565f9fb6a4900000000"
},
"substate_operation": "BOOTUP"
},
"entity_identifier": {
"address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
},
"type": "Resource"
}
]
},
{
"operations": [
{
"amount": {
"resource_identifier": {
"rri": "xrd_rr1qy5wfsfh",
"type": "Token"
},
"value": "-95999999928000000000000000"
},
"substate": {
"substate_identifier": {
"identifier": "65f61dba3ed40a438c4694e8947f73530c1c6ca6b8115371c05c6565f9fb6a4900000000"
},
"substate_operation": "SHUTDOWN"
},
"entity_identifier": {
"address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
},
"type": "Resource"
},
{
"metadata": {
"substate_data_hex": "06000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab010000000000000000000000000000000000000000004f68ca57bbfb708d160000"
},
"amount": {
"resource_identifier": {
"rri": "xrd_rr1qy5wfsfh",
"type": "Token"
},
"value": "95999998428000000000000000"
},
"substate": {
"substate_identifier": {
"identifier": "65f61dba3ed40a438c4694e8947f73530c1c6ca6b8115371c05c6565f9fb6a4900000001"
},
"substate_operation": "BOOTUP"
},
"entity_identifier": {
"address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
},
"type": "Resource"
},
{
"metadata": {
"substate_data_hex": "06000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b60100000000000000000000000000000000000000000000000014d1120d7b160000"
},
"amount": {
"resource_identifier": {
"rri": "xrd_rr1qy5wfsfh",
"type": "Token"
},
"value": "1500000000000000000"
},
"substate": {
"substate_identifier": {
"identifier": "65f61dba3ed40a438c4694e8947f73530c1c6ca6b8115371c05c6565f9fb6a4900000002"
},
"substate_operation": "BOOTUP"
},
"entity_identifier": {
"address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
},
"type": "Resource"
}
]
}
]
}
A couple of things to note above:
fee_payer
passed into /construction/build
substate
property) to perform the intent
of the operations initially passed in. That is, the balance changes of each entity should still be equivalent
to the original operations.Once payload_to_sign
has been signed, the original payload along with signature can be sent to
/construction/finalize
in order to get a signed_transaction
. This can then be submitted to
construction/submit
. You have successfully submitted an XRD transfer transaction!
ConstructionApi api = new ConstructionApi();
void main() {
ConstructionBuildRequest request = constructionBuildRequest();
ConstructionBuildResponse response = api.constructionBuildPost(request);
String unsignedTransactionHex = response.getUnsignedTransaction();
String payloadToSignHex = response.getPayloadToSign();
Signature signature = sign(payloadToSignHex);
ConstructionFinalizeRequest finalizeRequest = new ConstructionFinalizeRequest()
.unsignedTransaction(unsignedTransactionHex)
.signature(signature)
.networkIdentifier(new NetworkIdentifier().network("mainnet"));
ConstructionFinalizeResponse finalizeResponse = api.constructionFinalizePost(finalizeRequest);
String signedTransactionHex = finalizeResponse.getSignedTransaction();
ConstructionSubmitRequest submitRequest = new ConstructionSubmitRequest()
.networkIdentifier(new NetworkIdentifier().network("mainnet"))
.signedTransaction(signedTransactionHex);
ConstructionSubmitResponse submitResponse = api.constructionSubmitPost(submitRequest);
}
Returns the network configuration of the network the node is connected to.
Network Configuration
An unexpected error
{ }
{- "network_identifier": {
- "network": "mainnet"
}, - "bech32_human_readable_parts": {
- "account_hrp": "rdx",
- "validator_hrp": "rv",
- "node_hrp": "rn",
- "resource_hrp_suffix": "_rr"
}
}
Returns the current state and status of the node's copy of the ledger. If the node is syncing, the current_state_X
responses may be behind the global ledger.
required | object (NetworkIdentifier) |
Network Status
An Unexpected Error
{- "network_identifier": {
- "network": "mainnet"
}
}
{- "pre_genesis_state_identifier": {
- "state_version": 0,
- "transaction_accumulator": "0000000000000000000000000000000000000000000000000000000000000000"
}, - "current_state_timestamp": 1627452363772,
- "current_state_identifier": {
- "state_version": 322001,
- "transaction_accumulator": "e31f8314a67236076ad6d46391e93a93d7b9d34de2062acc620541c09dd69f95"
}, - "current_state_epoch": 1,
- "current_state_round": 321991,
- "genesis_state_identifier": {
- "state_version": 1,
- "transaction_accumulator": "1e62415e5fd95c63aff69142f1359cc6a981ff7169c128d266f45adf614d09b0"
}, - "node_identifiers": {
- "account_entity_identifier": {
- "address": "rdx1qspmwn5n0qyz685f20aevh4wglxxzg9k5t5vql20s4jqa7kj8hz0njclnh0mf"
}, - "validator_entity_identifier": {
- "address": "rv1qwm5aymcpqk3az2nlwt9atj8e3sjpd4zarq86nu9vs80453acnuuklp5yl2"
}
}, - "peers": [ ]
}
Gets the balances and data objects at an entity at the current state of the ledger.
required | object (NetworkIdentifier) |
required | object (EntityIdentifier) |
Entity Balances and Data
Unexpected error
{- "network_identifier": {
- "network": "mainnet"
}, - "entity_identifier": {
- "address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
}
}
{- "balances": [
- {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "token"
}, - "value": "13443027000000000000000"
}, - {
- "resource_identifier": {
- "rri": "veri_rr1qdtwzvy8lnfgl9t5tnj8f5fwl2znssnvx27vufcx7u3slv0gce",
- "type": "token"
}, - "value": "1000000000000000000"
}, - {
- "resource_identifier": {
- "validator": "rv1q04u5zwtgffsqkvr08xqm6vpm3gwxh4uqwtjpx5p47ew0m0v8m5zs3m3jed",
- "type": "StakeUnit"
}, - "value": "15000000000000000000000"
}
], - "data_objects": [ ]
}
Gets the transaction identifiers in the mempool
required | object (NetworkIdentifier) |
Mempool Transaction Identifiers
Unexpected error
{- "network_identifier": {
- "network": "mainnet"
}
}
{- "transaction_identifiers": [
- {
- "hash": "stringstringstringstringstringstringstringstringstringstringstri"
}
]
}
Gets the transaction from the mempool
required | object (NetworkIdentifier) |
required | object (TransactionIdentifier) |
Mempool Transaction Identifiers
Unexpected error
{- "network_identifier": {
- "network": "mainnet"
}, - "transaction_identifier": {
- "hash": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d99337193811842"
}
}
{- "transaction": {
- "transaction_identifier": {
- "hash": "stringstringstringstringstringstringstringstringstringstringstri"
}, - "operation_groups": [
- {
- "operations": [
- {
- "type": "string",
- "entity_identifier": {
- "address": "string",
- "sub_entity": {
- "address": null,
- "metadata": null
}
}, - "substate": {
- "substate_operation": "BOOTUP",
- "substate_identifier": {
- "identifier": null
}
}, - "amount": {
- "value": "string",
- "resource_identifier": {
- "type": null
}
}, - "data": {
- "action": "CREATE",
- "data_object": {
- "type": null
}
}, - "metadata": { }
}
], - "metadata": { }
}
], - "metadata": {
- "size": 0,
- "hex": "string",
- "fee": {
- "value": "string",
- "resource_identifier": {
- "type": "string"
}
}, - "signed_by": {
- "hex": "string"
}, - "message": "string"
}
}
}
Returns an ordered sublist of committed transactions. This endpoint is designed for lite clients to sync with the state of the ledger.
The example response demonstrates a transfer transaction.
There is a more detailed worked example of reading this endpoint in the examples section.
Sublist of Committed Transactions
An Unexpected Error
{- "network_identifier": {
- "network": "mainnet",
- "description": "The name of the network"
}, - "state_identifier": {
- "state_version": 40897
}, - "limit": 1
}
{- "state_identifier": {
- "state_version": 40897,
- "transaction_accumulator": "dd61e3e2c9cdda8bf8973ea7d6dd4e6482c569fff45f0ca5e2bfd196f5bae4c9"
}, - "transactions": [
- {
- "metadata": {
- "size": 360,
- "signed_by": {
- "hex": "02aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b6"
}, - "fee": {
- "resource": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "72000000000000000"
}, - "hex": "07030e7094728c8d065c5db696977696bea9094f67bcfd4c021f99ec784e24023b0000000c0100210000000000000000000000000000000000000000000000000000ffcb9e57d4000002004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007c13bc4b1c16827082c00000008000002004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007ad6192165e31dff02c000002004506000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329b63364718000000000b015584aed8375f30b22a2203b77dbe15e5dc0a3618fb45ea30ee54a6ebe0054b673a471ad2214b7bd06c4228083643b57e095787c9fb01443e1c3d6890d28f60cf",
- "timestamp": 1627407310726
}, - "committed_state_identifier": {
- "state_version": 40898,
- "transaction_accumulator": "5ea573f2e31640d177047d14122f1015c262f0d14d522596068784406aa1d88f"
}, - "transaction_identifier": {
- "hash": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d99337193811842"
}, - "operation_groups": [
- {
- "metadata": {
- "action": {
- "amount": "72000000000000000",
- "rri": "xrd_rr1qy5wfsfh",
- "from": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33",
- "type": "BurnTokens"
}
}, - "operations": [
- {
- "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "-2400000000000000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "030e7094728c8d065c5db696977696bea9094f67bcfd4c021f99ec784e24023b0000000c"
}, - "substate_operation": "SHUTDOWN"
}, - "entity_identifier": {
- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
}, - "type": "Resource"
}, - {
- "metadata": {
- "substate_data_hex": "06000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007c13bc4b1c16827082c0000"
}, - "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "2399999999928000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000000"
}, - "substate_operation": "BOOTUP"
}, - "entity_identifier": {
- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
}, - "type": "Resource"
}
]
}, - {
- "metadata": {
- "action": {
- "amount": "24000000000000000000000000",
- "rri": "xrd_rr1qy5wfsfh",
- "from": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33",
- "to": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88",
- "type": "TokenTransfer"
}
}, - "operations": [
- {
- "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "-2399999999928000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000000"
}, - "substate_operation": "SHUTDOWN"
}, - "entity_identifier": {
- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
}, - "type": "Resource"
}, - {
- "metadata": {
- "substate_data_hex": "06000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007ad6192165e31dff02c0000"
}, - "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "2375999999928000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000001"
}, - "substate_operation": "BOOTUP"
}, - "entity_identifier": {
- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
}, - "type": "Resource"
}, - {
- "metadata": {
- "substate_data_hex": "06000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329b63364718000000"
}, - "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "24000000000000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000002"
}, - "substate_operation": "BOOTUP"
}, - "entity_identifier": {
- "address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
}, - "type": "Resource"
}
]
}
]
}
]
}
Returns the entity identifier for an account, validator, or token given a public key
required | object (NetworkIdentifier) |
required | object (PublicKey) |
required | object (ConstructionDeriveRequestMetadata) |
Entity Identifier
{- "network_identifier": {
- "network": "mainnet"
}, - "public_key": {
- "hex": "03b74e9378082d1e8953fb965eae47cc6120b6a2e8c07d4f85640efad23dc4f9cb"
}, - "metadata": {
- "type": "Token",
- "symbol": "test"
}
}
{- "entity_identifier": {
- "address": "test_rr1q0xjsd8e3ud8dexqntmse9n0mcjhepfr7y404dd3tfqqngerma"
}
}
An unsigned transaction
Unexpected error
{- "network_identifier": {
- "network": "mainnet",
- "description": "The name of the network"
}, - "fee_payer": {
- "address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
}, - "operation_groups": [
- {
- "operations": [
- {
- "type": "Resource",
- "entity_identifier": {
- "address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
}, - "amount": {
- "resource_identifier": {
- "type": "Token",
- "rri": "xrd_rr1qy5wfsfh"
}, - "value": "-1500"
}
}, - {
- "type": "Resource",
- "entity_identifier": {
- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
}, - "amount": {
- "resource_identifier": {
- "type": "Token",
- "rri": "xrd_rr1qy5wfsfh"
}, - "value": "1500"
}
}
]
}
]
}
{- "unsigned_transaction": "07ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d99337193811842000000020100210000000000000000000000000000000000000000000000000000ffcb9e57d4000002004506000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329a636aa8c02c00000008000002004506000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329a636aa8c02bfa2402004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b60100000000000000000000000000000000000000000000000000000000000005dc00",
- "payload_to_sign": "06f82577392151638e059f31b16e52b056358ff9b7b72bedef21d701dc3ffa0f"
}
{- "network_identifier": {
- "network": "mainnet"
}, - "transaction": "0d000107ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000002010021000000000000000000000000000000000000000000000000000101ed50bab1800002004506000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329a6148f65d4e80000008000002004506000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329a6148f65d4e7f6a02004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000000000000000000000000009600",
- "signed": false
}
{- "metadata": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "72600000000000000"
}, - "operation_groups": [
- {
- "operations": [
- {
- "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "-24000000000000000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000002"
}, - "substate_operation": "SHUTDOWN"
}, - "entity_identifier": {
- "address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
}, - "type": "Resource"
}, - {
- "metadata": {
- "substate_data_hex": "06000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329a6148f65d4e8000"
}, - "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "23999999927400000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "e05bc84170aa74bcb0c7ed0393dc489afd8dbd761f68246d2f8de362b942707800000000"
}, - "substate_operation": "BOOTUP"
}, - "entity_identifier": {
- "address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
}, - "type": "Resource"
}
]
}, - {
- "operations": [
- {
- "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "-23999999927400000000000000"
}, - "substate": {
- "substate_identifier": {
- "identifier": "e05bc84170aa74bcb0c7ed0393dc489afd8dbd761f68246d2f8de362b942707800000000"
}, - "substate_operation": "SHUTDOWN"
}, - "entity_identifier": {
- "address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
}, - "type": "Resource"
}, - {
- "metadata": {
- "substate_data_hex": "06000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329a6148f65d4e7f6a"
}, - "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "23999999927399999999999850"
}, - "substate": {
- "substate_identifier": {
- "identifier": "e05bc84170aa74bcb0c7ed0393dc489afd8dbd761f68246d2f8de362b942707800000001"
}, - "substate_operation": "BOOTUP"
}, - "entity_identifier": {
- "address": "rdx1qspacch6qjqy7awspx304sev3n4em302en25jd87yrh4hp47grr692cm0kv88"
}, - "type": "Resource"
}, - {
- "metadata": {
- "substate_data_hex": "06000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b6010000000000000000000000000000000000000000000000000000000000000096"
}, - "amount": {
- "resource_identifier": {
- "rri": "xrd_rr1qy5wfsfh",
- "type": "Token"
}, - "value": "150"
}, - "substate": {
- "substate_identifier": {
- "identifier": "e05bc84170aa74bcb0c7ed0393dc489afd8dbd761f68246d2f8de362b942707800000002"
}, - "substate_operation": "BOOTUP"
}, - "entity_identifier": {
- "address": "rdx1qsp258zf47f288g4y47hm3plsp03370safcjg5x98e6j2h66p5we8ds8m7g33"
}, - "type": "Resource"
}
]
}
]
}
{- "network_identifier": {
- "network": "mainnet",
- "description": "The name of the network"
}, - "unsigned_transaction": "0d000107ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d9933719381184200000002010021000000000000000000000000000000000000000000000000000101ed50bab1800002004506000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329a6148f65d4e80000008000002004506000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329a6148f65d4e7f6a02004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000000000000000000000000009600",
- "signature": {
- "public_key": {
- "hex": ""
}, - "bytes": ""
}
}
{- "signed_transaction": "07030e7094728c8d065c5db696977696bea9094f67bcfd4c021f99ec784e24023b0000000c0100210000000000000000000000000000000000000000000000000000ffcb9e57d4000002004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007c13bc4b1c16827082c00000008000002004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007ad6192165e31dff02c000002004506000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329b63364718000000000b015584aed8375f30b22a2203b77dbe15e5dc0a3618fb45ea30ee54a6ebe0054b673a471ad2214b7bd06c4228083643b57e095787c9fb01443e1c3d6890d28f60cf"
}
Get the transaction identifier of a signed transaction
An unsigned transaction
Unexpected error
{- "network_identifier": {
- "network": "mainnet"
}, - "signed_transaction": "07030e7094728c8d065c5db696977696bea9094f67bcfd4c021f99ec784e24023b0000000c0100210000000000000000000000000000000000000000000000000000ffcb9e57d4000002004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007c13bc4b1c16827082c00000008000002004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007ad6192165e31dff02c000002004506000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329b63364718000000000b015584aed8375f30b22a2203b77dbe15e5dc0a3618fb45ea30ee54a6ebe0054b673a471ad2214b7bd06c4228083643b57e095787c9fb01443e1c3d6890d28f60cf"
}
{- "transaction_identifier": {
- "hash": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d99337193811842"
}
}
Submit a transaction to the mempool
An unsigned transaction
Unexpected error
{- "network_identifier": {
- "network": "mainnet"
}, - "signed_transaction": "07030e7094728c8d065c5db696977696bea9094f67bcfd4c021f99ec784e24023b0000000c0100210000000000000000000000000000000000000000000000000000ffcb9e57d4000002004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007c13bc4b1c16827082c00000008000002004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007ad6192165e31dff02c000002004506000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329b63364718000000000b015584aed8375f30b22a2203b77dbe15e5dc0a3618fb45ea30ee54a6ebe0054b673a471ad2214b7bd06c4228083643b57e095787c9fb01443e1c3d6890d28f60cf"
}
{- "transaction_identifier": {
- "hash": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d99337193811842"
}, - "duplicate": false
}
required | object (NetworkIdentifier) |
The node's public keys
Unexpected error
{- "network_identifier": {
- "network": "mainnet"
}
}
{- "public_keys": [
- {
- "public_key": {
- "hex": "string"
}, - "identifiers": {
- "account_entity_identifier": {
- "address": "string",
- "sub_entity": {
- "address": "string",
- "metadata": {
- "validator_address": "string",
- "epoch_unlock": 0
}
}
}, - "validator_entity_identifier": {
- "address": "string",
- "sub_entity": {
- "address": "string",
- "metadata": {
- "validator_address": "string",
- "epoch_unlock": 0
}
}
}, - "p2p_node": {
- "peer_id": "string"
}
}
}
]
}
{- "network_identifier": {
- "network": "mainnet"
}, - "unsigned_transaction": "string",
- "public_key": {
- "hex": "string"
}
}
{- "signed_transaction": "07030e7094728c8d065c5db696977696bea9094f67bcfd4c021f99ec784e24023b0000000c0100210000000000000000000000000000000000000000000000000000ffcb9e57d4000002004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007c13bc4b1c16827082c00000008000002004506000402aa1c49af92a39d15257d7dc43f805f18f9f0ea712450c53e75255f5a0d1d93b601000000000000000000000000000000000000000007ad6192165e31dff02c000002004506000403dc62fa04804f75d009a2fac32c8ceb9dc5eaccd54934fe20ef5b86be40c7a2ab0100000000000000000000000000000000000000000013da329b63364718000000000b015584aed8375f30b22a2203b77dbe15e5dc0a3618fb45ea30ee54a6ebe0054b673a471ad2214b7bd06c4228083643b57e095787c9fb01443e1c3d6890d28f60cf"
}
required | object (NetworkIdentifier) |
Submitted vote transaction information
Unexpected error
{- "network_identifier": {
- "network": "mainnet"
}
}
{- "transaction_identifier": {
- "hash": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d99337193811842"
}, - "duplicate": false
}
required | object (NetworkIdentifier) |
Submitted vote withdrawal transaction information
Unexpected error
{- "network_identifier": {
- "network": "mainnet"
}
}
{- "transaction_identifier": {
- "hash": "ef71a9d6c63444fce6abd2df8fab2755cfb51f6794e578f60d99337193811842"
}, - "duplicate": false
}