Summary of Changes to Ledger Transactions for Cadence 1.0

As part of the Cadence 1.0 upgrade, the flow team is updating all the transactions for the ledger hardware wallet to be compatible with the Cadence changes as well as the changes to the NFT standard and NFT standard.

The updated manifest files that include a list of all the ledger transactions that are being submitted to the ledger team are in the flow-core-contracts repo in the stable-cadence branch:

In addition to these mandatory changes, we are also proposing two additional changes to the transactions:

  • Remove all the deprecated locked tokens staking transactions, significantly reducing the size of the Flow ledger app
  • Use generic transactions for ft and nft interactions, allowing users to store any token they want in their ledger wallet

These changes have multiple benefits in addition to the ones mentioned above, but there are some potential issues for each one that we want to explore the impact of before committing.

Additionally, Flow Port is already preparing to easily support these changes. As far as we know, ledger isn’t used anywhere else besides flow port, but if that isn’t true, we would love to hear about the other places it is used so we can understand how these changes may affect the other apps that use ledger and how we can help them upgrade.

Remove all the deprecated LockedTokens staking transactions

When we released the first version of the ledger app, most accounts were receiving locked tokens from the token sale and the ledger app had a set of transactions that could only use the locked account setup to stake tokens. Eventually, we introduced the FlowStakingCollection smart contract, which allowed users to manage any number of nodes or delegators from a single account, regardless of whether they were using locked tokens or not. When we upgraded to this, we decided to stop using the old LockedTokens transactions and only use the staking collection transactions on flow port from then on, though we still kept the old transactions on the ledger app just in case they might be needed.

It has been almost three years since that change and as far as we know, those old transactions have never been used. Therefore, as part of the Cadence 1.0 upgrade, we want to remove the old locked token staking transactions completely from the ledger app. This will significantly reduce the size of the ledger app. Before, the flow ledger app was so big that a typical ledger nano s could only support it and maybe one or two other apps. This change will allow more space on a Flow user’s ledger to have additional apps.

To be clear, removing these transactions does not stop users from being able to use and stake with locked tokens. The transaction for claiming locked tokens will still remain. All the staking collection transactions support locked account setups, so the upgrade will not keep anyone from accessing the functionality they have always had with their locked tokens. Like was mentioned earlier, Flow port has been exclusively using the staking collection transactions since the Summer of the 2021 with no issues. In the rare case that there is an account that still is using the old locked account setup to stake with ledger, all they would need to do to access the same functionality is run the setup staking collection transaction to add the staking collection to their account.

Use generic transactions for FT and NFT interactions

For years, ledger users have been asking for the ability to store any FT or NFT in their ledger wallet, but all they currently have is support for FlowToken, USDC, and NBA Top Shot.

This proposal introduces generic FT and NFT transactions which allow users to store and transfer any token they want without needing a specific transaction for it.

NFT Transactions:

FT Transactions:

In addition to the obvious benefit of flexibility for ledger users, this will also reduce the size of the ledger app, because this will cut down the number of transactions for supporting NFTs and FTs from 7 to 6 and no new transactions will need to be added in the future because the new transactions can support any token type on Flow as long as they implement the correct token standard.

There is one drawback for this improvement though. Because the transactions are generic, they require parameters to specify which tokens need to be set up or transferred. For example, the transaction to set up an account to hold a given token requires the contract address and contract name to be supplied as arguments:

// Transaction to setup an account to support a token needs the address
// and contract name in order to borrow a reference to that contract to get the metadata required to set up an account
transaction(contractAddress: Address, contractName: String) {

And the transactions to transfer either have to have the same arguments (address and contract name) or need to include the storage path and public path to withdraw from and deposit to, respectively:

// The transaction only needs to paths because it can get the generic capabilities from those paths and withdraw/deposit
// without having to know the specific types of the collection/vault
transaction(to: Address, id: UInt64, senderPathIdentifier: String, receiverPathIdentifier: String) {

These can make for slightly more awkward experiences for the user and app because now one of them needs to know this information ahead of time in order to submit the transaction properly instead of just clicking on a “transfer top shot” button and getting the specific top shot transaction without needing to provide any of those identifying arguments.

It is important to understand though that this “easier UX” is inherently limited by the amount of specific transactions that a given app is willing to support. The solution of using generic transactions only requires the app to support 4-6 transactions and unlock the ability to use any token that has existed or will exist on flow until the end of time. At that point, if they want to make the UX better for their users, they can simply store default argument values for any tokens that are popular or that their user’s use regularly so that users don’t even need to know to submit the extra arguments unless it is for a token that the app doesn’t know about.

Additionally, an app can also just iterate through any user’s storage and use the token metadata getter functions to get these values for any token that a users stores in their account, removing the need to keep them persistently stored altogether.

Remember, these changes are only for ledger wallet. Other wallets are allowed to do whatever they want to do for token set ups and transfers.

These solutions are what Flow Port plans on using to support ledger users and as we’ve said before, we believe that Flow Port is the only place where ledger is used, so it should be just fine. The benefit of allowing ledger users to hold any fungible token is worth any small increase in complexity that is introduced by this support.

Again, if you are an app builder whose app supports ledger wallet and/or have concerns about how this will affect the user experience of Flow Port, please respond here or in the Flow discord and we’ll be happy to discuss with you. We are also happy to discuss these transactions with anyone else who sees them and decides that they also want the improvement of generic token transactions!

Thank you!


Here is a list of all the ledger transactions that are being submitted to the ledger team for review:

Account Transactions:

NFT Transactions:

FT Transactions:

Locked Tokens Transactions:

Staking Collection Transactions:


Transfer with name and address force uses nil as the resourveType when borrowing the contract view. Should that not also be sent in for completeness?

1 Like

We can’t really enforce that because it is a generic transaction so there is no way for the sender to specify the type they are looking for afaik since they aren’t importing the contract.

I don’t think this is a problem because for starters, 99% of contracts will only have a single type defined so calling their resolveContractView() function with a resourceType as nil will work just fine. Secondly, even for projects with multiple NFT types, I would imagine there is still one type that is more important than the others that can be defaulted to if resourceType is nil.

It is also important to consider that for this in particular, it is only for ledger users, so the vast majority of them will only want to use it to hold FLOW, USDC and maybe some of the popular NFT projects which currently all only have one type, so I’m not too worried if it doesn’t fully support the very small number of projects that might have multiple token types defined out of the gate.

If that becomes a problem in the future, we can always make changes to the transactions to support that. Does that make sense? Please let me know if I’m not considering something here

1 Like

We cant construct a runtime type from an identifier?

If that is not possible i think your assumptions work. The other generic transaction also works

1 Like