Experimental Feature: GMP Precompile for Automatic Liquidity Routing

General Message Passing (GMP) Precompile

Abstract

Moonbeam is at the forefront of two important inter-chain messaging systems:

  • XCM connects blockchains within the Polkadot ecosystem. Being built on Substrate and having connectivity through its relay chain are all Moonbeam needs to be a part of this network.
  • GMP (General Message Passing) protocols connect many blockchains more broadly. These are often written for multiple protocols and in multiple languages, but they usually include the EVM in their implementation, which makes Moonbeam a trivial deployment for them.

These each create their own well-connected network but they remain disjoint. Moonbeam solves this with its EVM and precompiles like xtokens, allowing users to receive GMP messages and send XCM messages or vice-versa. This is possible today, although it generally requires multiple user-interactions.

Executive Summary

We can take this a step further by hooking the two technologies together within the EVM such that a single call can both receive one type of message and send the other. By doing so, we allow a user to use Moonbeam as a bridge between these two networks with a single interaction. The pitch: One click Moonbeam Liquidity Routing.

Solution

The Moonbeam team has created a proof-of-concept which focuses on a narrow set of functionality: receiving a GMP message containing tokens (using the Wormhole protocol) and forwarding these tokens on to another parachain (or relay) via XCM.

Briefly, Wormhole’s Contract Controlled Transfer feature works by having the recipient of a token transfer call its own bridge contract’s completeTransferWithPayload() function. This design lets the caller be either an EOA or a smart contract, and also removes complexity from the protocol. completeTransferWithPayload() takes a message blob which includes everything the bridge needs to validate the transfer and also includes an arbitrary payload, something we use in the design to encode the XCM destination in this PoC.

The PoC is accomplished by creating a precompile with a single function which takes the protocol’s VAA payload and calls completeTransferWithPayload() with it. This causes the bridge to send tokens to the precompile address itself. Once this occurs, the precompile looks for the XCM destination inside the payload. Specifically, the VAA payload includes an inner arbitrary payload, and we require that this payload be a SCALE-encoded struct representing its XCM destination. xtokens pallet is then used to forward these tokens on via XCM.

A Dapp could implement this UX in such a way that the user would only need to select a token to send and a destination chain/account to receive it. The “hop” on Moonbeam (the interaction with this precompile) can be completely transparent to the user.

Future Work

This feature would potentially require a lot more work beyond this initial PoC. I’ll briefly discuss the more significant tasks here.

  • There are many other protocols beyond Wormhole which we could support. While I haven’t looked at them in much detail yet, I can say that they all work differently, so each one may be a considerable amount of work.
  • No fee mechanism currently exists. Wormhole does have a fee mechanism, but it does not support the way we use the protocol. Even if it did, it may not cover fees associated with XCM.
  • Inverse use case: receive a XCM transfer and initiate a GMP interaction
  • Other, non-XCM cases: there may be other use cases (staking?) which a user might want to do instead of an XCM transfer.
  • Testing: not much was done in this PoC, and it would be hard to overstate just how much test coverage this could have.

Status

A first draft of the PoC has been deployed to Alphanet. We are treating this as experimental and do not have plans yet to deploy to Moonriver or Moonbeam.

Specifically, RT2300 included the initial PR and RT2301 included a small but important fix for it.

5 Likes

Could this not be considered with a batch call?

Or rather, why can’t it be done this way?

Good question. A batch call would help do two or more transactions at one time on Moonbeam. The point of the GMP precompile is to avoid having to interact with Moonbeam altogether, allowing it to seamlessly forward tokens/messages on.

It might be helpful in cases where a protocol itself could be modified to use the batch precompile, but I think this would end up pushing complexity outside the GMP precompile (making integrations more complex).

And what would be the risks associated with this implementation?

The main risk that was considered in the design is how to gracefully handle errors. Because bridges work across different consensus systems, they can’t roll back an entire bridging operation atomically. In other words, if a problem occurs on Chain B, a previous operation on Chain A can’t be rolled back. It could be undone with a new transaction, but the original transaction can’t be voided.

Different protocols handle this situation differently, but in general the problem comes with a risk of funds being stuck (lost forever), or needing some intervention (such as governance).

We have so far chosen to revert when any problem occurs, which in the case of Wormhole results in funds being stuck at the bridge level. Note that there isn’t a clear, graceful way to handle such errors, as the nature of the error means we don’t know what the user wanted to do with the funds. The bridge itself encounters some of these same problems as well. At the end of the day, if a user produces garbage input, it will likely lead to funds being lost. This is still open to research and we may have some improvements to make here.

More generally speaking, bridges have been a really sore spot for hacks recently, and so there is some risk that we introduce a way for funds to be delivered to the wrong person through buggy code.

This is one reason why we have chosen to be very paranoid about NOT taking custody of funds when we can avoid it. By “taking custody of funds” I mean having our protocol at some point store a large pool of funds earmarked for different recipients. By choosing to revert when it is unclear what to do, we avoid doing this, so there should never be a large pool of funds that needs a carefully written way to distribute them.

Technically, the precompile (in the case of Wormhole, at least) becomes the custody of funds briefly during an EVM transaction, but this is temporary/intermediate and because we revert no transaction should ever settle such that the precompile is stuck holding funds for someone else.

Thanks for a great question, I hope that makes sense :slight_smile:

3 Likes

ok it makes sense, in this case it works similar to a router

In the event that a tx goes through Moonbeam and precisely at that moment the congestion rises, will the tx revert? will stay pending?

In my opinion, after few blocks, it should be reversed, although the best thing would be to place a higher than average fee, to avoid those situations that can generate another tx and large fees in ethereum, for example

hey, Stephen, first of all, thank you for your hard work and this amazing proposal!

the ongoing work of the PureStake team on Moonbeam’s multi-chain capabilities is truly exciting. the proposed GMP Precompile feature is particularly interesting as it enables seamless connectivity between different chains, even those outside of the Polkadot ecosystem. IMO, the addition of the GMP Precompile feature would be a valuable enhancement to Moonbeam’s already impressive set of features. Moonbeam’s growing importance as a significant player in the multi-chain landscape is thrilling, and I look forward to seeing how this feature develops in the future

1 Like

Thank you @notlesh for putting this post together. The GMP precompile looks interesting.

Could you give an example for this ?

Overall, I thinks it’s a good idea.

hey Chris, MRL is an example. you can find more info on the Moonbeam docs and blog

1 Like

And HydraDX is already using it

1 Like

Thank you for the example.

Thank you @turrizt for the example.

1 Like