What is Rosetta main use-case?

We discussed internally the assumptions Rosetta may imply and it seems that we need a better understanding of the core values and use-cases Rosetta wants to enable. It seems that Rosetta is fine to compromise on the underlying blockchain features. How much do you care about things that are not balance changes? Do you expect that the balance we report via the balance endpoint is immediately spendable? (We have staked [locked] balance on accounts, and we also have a minimal required balance)

All great questions @frolvlad.

Determining the amount of underlying blockchain features to expose (outside of balance changes) is completely up to you. We encourage you to support as many underlying features as possible (even if they aren’t balance-changing) so that your implementation can be more widely used, however, we will initially use “balance-changing” functionality exclusively. We strongly encourage getting the “basis” working (i.e. “balance-changing” functionality before expanding the scope of work to include other functionality).

All this being said, we acknowledge that the current Operation model does not really support a lot of first-class information outside of what you would expect to populate for a balance transfer (ex: there is no governance field). So, you would be populating information in the Operation.Metadata field and users of the implementation would need to figure out how to parse manually.

Do you expect that the balance we report via the balance endpoint is immediately spendable? (We have locked balance on accounts, and we also have minimal required balance)

The guidance we have given to other implementers around locked balances is to represent the entire “owned” amount here (spendable + minimum). However, if there are different fund states (ex: staked), we expect these to use SubAccounts. Here is an example from Celo’s implementation (they have different SubAccounts for different staking balance states):

Different staking operations move funds between different SubAccounts (ex: address1 -> address1:staked).

Evgeny Kuzyakov shed some light on our liquid balances:

I think we can distinguish 3 types of balances:

  • liquid - the balance on account (no sub-account).
  • locked - the amount locked for staking. (sub-account # 1)
  • liquid_for_storage - the amount of non locked balance used to cover the remaining storage balance (sub-account # 2). Let’s say you need 30 NEAR for storage, and locked balance is 20NEAR. It means you ONLY need 10 NEAR to cover the remaining balance for storage. So liquid_for_storage in this case will be 10 NEAR.

Rosetta model with balance checks and sub-accounts complicates our implementation because you need to compute storage_balance before you can compute liquid_for_storage . This is fine, but now every action that modifies any account value can trigger sub-account operation change.

This means that almost any transaction will lead to micro-changes to the liquid balance (the sum of liquid + liquid_for_storage will remain the same), so we will have micro-balance changes between subaccounts all the time. Is that fine? Well, given that every transaction charges transaction fees, I assume it is fine.

I want to clarify the uniqueness of SubAccount address, as it is stated:

The SubAccount address may be a cryptographic value or some other identifier (ex: bonded) that uniquely specifies a SubAccount.

Is it fine if we have the subaccount address unique in the scope of each individual account? I mean, I want to have subaccount address reflecting the staked balance to be staked, so every account will have a subaccount called staked. Alternatively, I can prefix it with the account address (frol.near:staked).

@frolvlad Before I provide additional guidance here, I was wondering if this “balance required for storage” is some constant value (like Ripple’s reserve) or if it is dynamic in some way (either dependent on code deployed to an account or some governance parameter)?

Storage includes the code and the state (state used to store persistent values for a contract and also state used for access keys). Thus, operations like adding/removing an access key, contract execution which mutates the persistent data, so this changes the “locked” minimal balance.

Sorry for the delay in responding here @frolvlad. Thanks for the additional context on this point.

This means that almost any transaction will lead to micro-changes to the liquid balance (the sum of liquid + liquid_for_storage will remain the same), so we will have micro-balance changes between subaccounts all the time. Is that fine? Well, given that every transaction charges transaction fees, I assume it is fine.

Yes this is fine and even encouraged (given the context you’ve shared). I imagine that spending greater than your liquid balance either results in an error or causes your account to be reaped (neither of which are probably intended). Making it clear at any particular block what is liquid would be very important to us.

You alluded to this but want to re-iterate for other readers, most people typically consider the liquid balance as the default SubAccount and do not populate SubAccount for it.

I also want to clarify for other readers (you appear to understand this) that balances in SubAccounts are summed to get the total balance at an address. The balance returned for an AccountIdentifier should not be the sum of the balances at all SubAccounts (this will lead to a reconciliation error).

Is it fine if we have the subaccount address unique in the scope of each individual account? I mean, I want to have subaccount address reflecting the staked balance to be staked , so every account will have a subaccount called staked . Alternatively, I can prefix it with the account address ( frol.near:staked ).

Yes, this is 100% fine! SubAccount.Address is not considered globally unique (it is scoped to AccountIdentifier.Address). If you want to make a PR to improve the docs on this point, I recommend modifying this description:

Here is an example PR that @matheusd made to this repo:

1 Like