paint-brush
Radix’s Asset-Oriented Transactions: Making Transactions Meaningfulby@RadixDLT
9,892 reads
9,892 reads

Radix’s Asset-Oriented Transactions: Making Transactions Meaningful

by Radix PublishingJune 28th, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow
EN

Too Long; Didn't Read

Radix’s smart contract architecture gives everything on the platform to everything. Radix transactions contain a “manifest” of asset-oriented instructions that make transactions understandable, composable, and incredibly powerful. The design of Radix's transactions started from those first principles of intuitive user expectation and control.
featured image - Radix’s Asset-Oriented Transactions: Making Transactions Meaningful
Radix Publishing HackerNoon profile picture


In the previous article, we talked about how the concept of today’s blockchain transactions makes it impossible to address several serious problems that DeFi users and developers encounter - problems that block the mainstream potential of DeFi and Web3.


The design of most smart contract L-1 platforms limits transactions to being simply a message sent to a black box smart contract, and that limitation means that transactions simply cannot be flexible, powerful, or transparent enough.


The only way to truly fix the problem is to redefine what a transaction on a blockchain means, and that is exactly what Radix has done. Radix transactions (on the Babylon network that includes Radix’s unique smart contract capability) contain a “manifest” of asset-oriented instructions that make transactions understandable, composable, and incredibly powerful.


Let’s talk about what a Radix transaction is, and some of the amazing things they make possible for users and developers.

Redefining a “Transaction”

Forgetting about technology for a moment, what should a transaction ideally be?


What should it contain so that it’s flexible enough to do everything that makes Web3 and DeFi exciting and also understandable and safe to users?


As a starting point, let’s look at a real-world transaction that does something useful and is already very understandable to anyone. Take the example of using the real-world version of a DEX: a currency exchange kiosk.


Imagine I’m the customer, walking up to an exchange counter at the airport to exchange currencies. I might describe the transaction this way:


  • I take 20 USD from my wallet and put it on the counter.

  • I inform the exchange teller that I’d like to trade that 20 USD for GBP.

  • The teller takes my USD, taps on his computer for a moment, and puts 16.08 GBP on the counter.

  • I’m satisfied with the exchange rate I got, take the GBP, and put it in my wallet.


In this typical real-world scenario, while I’m not in control of how the exchange internally does business, I am fully in control of what matters to me: taking assets from my wallet, giving assets to the exchange with instructions for what I want, accepting (or rejecting) what they give back to me, and putting assets back in my wallet.


That knowledge and control of what matters to me are a natural, obvious expectation any time I’m interacting with someone and my assets are involved. I control what assets leave my wallet, I specify who I give them to and what I want, and I can see what comes back to me and approve. That is fundamentally what the word “transaction” means to me in the real world. Wouldn’t it be nice if blockchain transactions worked like that?


On Radix, they do. The design of Radix’s transactions started from those first principles of intuitive user expectation and control and modeled transactions on the Radix network in just the same way.

Making Transactions Meaningful

The most important thing to me about the real-world transaction above is that it is a direct description of movements of assets between my wallet and the exchange. To make Radix transactions work like that, the platform design has to start with assets. And fortunately, one of the defining features of the Radix platform design (from the Radix Engine virtual machine to the Scrypto smart contract language) is that the network has a native understanding of assets and asset behavior.


This “asset-oriented” architecture gives everything on the platform intuitive behavior when it comes to digital ownership. Tokens and NFTs aren’t balances in smart contracts; they act like physical objects that move from place to place. User accounts aren’t just keypairs; they are containers for assets where the user has the power to withdraw or manage the rules on what kinds of deposits it will accept. Smart contracts aren’t limited to accepting messages; they can accept “buckets” of assets as inputs – like pushing money across the exchange counter.


These platform capabilities provide the tools needed to reformulate the definition of transactions on Radix so that they work intuitively and predictably, similar to real-world transactions.


Radix transactions are a “manifest” of instructions that directly describe movements of assets between accounts and components (Radix’s form of smart contract).


Here’s a real transaction manifest (without addresses, for clarity) describing a trade like our real-world exchange example:



Note that you’re not looking at a summary - that is actually what the contents of a real Radix transaction look like! Similar to how a user would describe a real world transaction, the manifest describes the transaction in terms of the asset movements that matter to the user.


Here’s what’s happening in the 4 instructions of this manifest:


  1. I tell one of my accounts to withdraw 20 USD tokens. (I expect the 20 USD tokens are returned to something called the “transaction worktop”, which you can think of as the exchange counter. It’s just a temporary place for assets to sit when they’re being moved around during a transaction.)
  2. I sweep those 20 USD off the worktop and put them into a “bucket”. (Buckets are just asset containers that I can pass to other things.)
  3. I directly pass the bucket of USD to the exchange component’s “trade” method. (I expect the exchange will figure out the exchange rate and return some GBP tokens to the worktop.)
  4. I sweep the contents of the worktop back into my wallet.


I sign this transaction – which is how my account knows that I’m allowed to withdraw the 20 USD tokens – and submit it to the network.


Like the real-world scenario, while I may not have control of the internal workings of the exchange, I do have direct control over what matters to me: the tokens moving in and out of my accounts, and what I want to interact with.


This is already a huge improvement over a transaction that is just sending a message to a smart contract. But there’s something missing…

Putting the User in Control

In the real-world example, I made sure I was getting 16.08 GBP (maybe based on the current exchange rate and expected fees) for my 20 USD before I accepted the transaction. Shouldn’t I expect to be able to do the same sort of thing with a Radix transaction before I sign and submit it?


In fact I (with the help of my wallet software) can do the same thing by adding an instruction to the transaction manifest. It’s the second-to-last “ASSERT_WORKTOP_CONTAINS_BY_AMOUNT” instruction here:



The instruction in the manifest is “asserting” that the worktop contains at least 16.08 GBP tokens before I make the deposit back to my account. This means that when this transaction is processed by the network, if that assertion isn’t true (say, if the exchange only returned 15 GBP, or it returned the wrong kind of token entirely) then the transaction will be rejected by the network. The whole thing won’t happen because I didn’t get what I expected.


This works because transaction manifests are atomic. That’s just a fancy way of saying that everything in the transaction manifest must successfully run without problems or else none of it happens.


This is incredibly powerful. Like the real-world exchange, I don’t have to care about the internal exchange logic at all. I get protection from things like slippage or being front-run into a result I didn’t want in a way that is fully under my control without relying on smart contract logic.


The Radix Wallet can directly add my expectations as a user to the transaction manifest for me, and the network will guarantee all of those expectations are respected – or else my funds never leave my pocket.

Fixing the Transaction User Experience

Having transactions structured in this way is also exactly what is needed to allow the Radix Wallet to give users the kind of UX that Web3 asset transactions need to be mainstream-ready.


To see what that means, here’s how our exchange transaction would be presented to the user in the Radix Wallet:



This view wasn’t created by the exchange dApp. This is the Radix Wallet itself safely summarizing what matters to me by directly reading the contents of the transaction itself. And if you look again at the transaction manifest above, you can probably see how the Radix Wallet is able to automatically translate it into the summary UI for the user:


  • WITHDRAWING: Withdrawals from accounts are shown directly, and the wallet can see which accounts are owned by the wallet user.
  • Using dApps: Other components that are involved in the transaction are listed as user-understandable dApps. (To learn how the Radix Wallet does this, take a look at Radix’s dApp Definition system that allows a developer to associate components with a clear on-ledger description of their dApp.)
  • DEPOSITING: Deposits to the user’s accounts are also shown directly. Any deposit that doesn’t have a specified quantity in the transaction manifest is “estimated” via a preview run of the transaction, and a “guarantee” (the “assert” instruction we described earlier) is automatically added according to user preferences.
  • TRANSACTION FEE: And of course the wallet shows the required transaction fee (more on that below).


The result is a transaction summary that is meaningful and relevant to the user, is guaranteed to be accurate, and is fully trustless. The user knows exactly what will happen with their accounts and assets if they sign – as they would expect. When every part of the stack is designed to work together to enable a mainstream-capable product, you don’t have to give up good UX to go decentralized.

Clear, Flexible Authentication

Let’s talk about another tool in the Radix transaction toolbox.


The Radix Engine virtual machine includes a powerful built-in authentication system for components using “badges”. Much like a membership card in your wallet, badges are assets that you own that you can “present” proof of in a transaction. Components can check that you’ve presented a given proof as a prerequisite to doing something.


Presenting a proof of a badge is just another instruction in the transaction manifest that requests that proof from the account holding the badge. It’s like pulling a membership card out of my real wallet to show somebody.


This means that once again the Radix Wallet can show the user exactly what’s going on. Imagine that our exchange dApp needs to see proof that I hold a badge that indicates I’ve completed some KYC checks from a third party. The result is a transaction that is presented like this:



Once again, I get a clear presentation that a given badge is being presented and can decide if I’m comfortable with it before signing.

No-code, On-demand Atomic Composability

Now let's talk about the flexibility and power of Radix transactions. One of the transaction manifest’s superpowers is the ability to “compose” together multiple dApps in a single atomic transaction – without smart contract code.


Imagine I want to take a loan from a lending dApp smart contract, then use that loan to do a certain trade from a DEX smart contract. I might want to make sure that I only take out the loan if I am in fact able to make that trade.


On other networks, you only have one option: write and deploy a special smart contract that you can call that bakes in this logic. After it’s deployed, that smart contract would receive your request in a transaction, call the loan smart contract, attempt to call the DEX (assuming I’ve received the loan funds), and make sure to check that the DEX swap succeeded. This is a multi-step process that requires smart contract expertise, takes time, is single-purpose, and often is outright expensive in network fees.


On Radix, it’s just a transaction manifest of a few instructions:


  • Call the loan component to take out the loan
  • Put the loaned tokens in a bucket and pass them to the DEX
  • Assert that the DEX returned what you expected (transaction fails if this isn’t true)
  • Deposit the results in your account


You can build this simple transaction manifest, on demand, in a simple web frontend. No smart contract code or ahead-of-time deployment, no elaborate checks on smart contract results; you just describe how you want assets to move between your account and the dApp components and submit.


This opens up a host of new possibilities. Whole segments of DeFi dApps that help users find the best routes for trades can be built purely as website frontends, by developers who never touch smart contract code. Highly complex combinations of finance protocols can be stitched together in real-time to take advantage of ephemeral opportunities. And using “assertion” guardrails in transactions, clear and direct limits can be placed on the end-result that is desired without concern for the internal workings of the components being called.

dApp-paid Network Fees

Here’s another important feature of Radix transactions for developers. Many dApp developers would like to consider network fees an infrastructure cost that they bear for their users, so users never have to think about them. For example: maybe their users only want to transact in USDC and never touch ETH, or maybe they just want to offer this as an invisible benefit to users, like a merchant paying the Visa transaction fee when running a customer’s debit card.


Current transactions make this impossible – the signer must be the fee-payer. On Radix, fee payment is much more flexible; anything can pay it in the course of the transaction.


In fact I was cheating a little bit when I showed you the transaction manifests earlier. In the typical case where the user pays the transaction fee, there’s an extra manifest instruction to one of the user’s accounts to “lock” the network fee for the transaction. But the user locking that fee isn’t required if something else is willing to do that fee lock in the course of the transaction.


For example: Imagine I’m a known, registered user to an exchange dApp and they’d like to pay the network fees for me when I use their system. They issue me a user badge asset that I hold in one of my accounts that represents my registration. Now in transactions, I can present that badge to the exchange component (just like we saw earlier with the KYC badge), and the exchange can check that proof and then lock the fee for the transaction. If it does that, my Radix Wallet sees that no extra fee locking is required, and it’s as if the network fee is magically zero.

A Final Note on Sharding

For those who like digging into the tech, there’s one other wonderful benefit of Radix’s transaction model: it shards well.


Looking ahead to the Xi’an network upgrade when Radix’s massively parallelized Cerberus consensus protocol (recently peer reviewed) will roll out to deliver unlimited scalability, it’s crucial that the transaction model fits.


To enable massive parallelism, Cerberus relies on being able to separate the state of accounts and components across a virtually unlimited number of shards (or “threads” might be a more descriptive term), while being able to know specifically which of those shards must be brought together for consensus for each transaction.


This might sound on the surface somewhat like Cardano, which fragments its state across bits of state called “eUTXOs”. Cardano transactions then (similar to Bitcoin) include a direct specification of which eUTXOs are to be used to create the result of a given transaction. The problem with this is that it creates contention. A given smart contract (like, say, a DEX) might have a pool of tokens that many people are trying to interact with at the same time. If transactions are picking out individual token eUTXOs to use from within that pool, it’s nearly guaranteed that clients will often pick the same eUTXOs and thus cause many transactions to fail, even though there were plenty of tokens in the pool to serve everyone’s desires.


Instead, on Radix, the list of instructions in a transaction manifest is an expression of intent. I don’t need to specify the individual pieces of state to be used; I only have to specify what accounts and components I want to interact with – as I naturally want to do anyway.


Then when the transaction is actually processed by the Radix network, that intent can be deterministically translated into a definition of what state needs to be updated – and in turn which shards must be involved in consensus. That means that two transactions interacting with the same smart contract won’t automatically create a race where only one can succeed. 10 people can reliably submit a transaction to withdraw 5 tokens from a pool of 50 at the same time, and they’ll all go through one after the other without trouble.

The Bottom Line

By redefining how all transactions work on Radix, making use of Radix’s natively asset-oriented capabilities, multiple developer and user problems melt away. This kind of solution can’t be patched on to an existing network – all of the assumptions about how smart contracts and assets and transactions work are already baked into their protocol and the virtual machine design.


Radix’s new form of transactions are being introduced alongside Scrypto smart contract capability and the all-new Radix Wallet on the Radix mainnet at its “Babylon” release.