# A post-blockchain Web3

A post-blockchain  Web3

## "Web3" is trapped in itself

The web3/crypto community has an incredibly powerful vision of secure user autonomy and coordination. And it's not without foundation --- blockchains and web3 protocols have a combination of *unique superpowers* that no previous network protocol achieve: censorship resistance, decentralized trust, and user-aligned incentives.

But we don't actually see a true "Web3": a successor to Web2 with radically better user autonomy and coordination. The current crypto world is viciously meta: with the notable exception of collectibles like NFTs and memecoins, most crypto apps are about speculating on tokenized shares of crypto apps. DeFi, for example, mostly finances speculation on tokens (many of which belong to DeFi projects!), rather than anything outside the crypto sphere. It's as absurd as if the primary use of web2 tech was to host brokerages where people can speculate on web2 tech company stocks.

This problem is usually posed as "mainstream crypto adoption", and the usual solution everyone peddles is some combination of "better UX" and shoehorning external systems into the self-referential crypto ecosystem (like "real-world assets"). But we've tried this for the better half of a decade, and it's not working.

## Mel: freeing crypto superpowers from crypto

Mel is a blockchain engineered for a Web3 paradigm shift.

Instead of smart-contract dApps running on a world computer, we envision what we call a **post-blockchain Web3** –- an internet-scale ecosystem with full-stack decentralized security. Mel is the embedded security component for this ecosystem, *not an app platform*.

<figure><img src="/files/Tz84HYnrIfNqSRDRdKgQ" alt=""><figcaption></figcaption></figure>

This means a largely non-blockchain world with two key properties:

1. **Off-chain programs trustlessly compose with on-chain programs.** Off-chain programs, whether dApp frontends or whole alt-tech stacks, must integrate on-chain functionality without sacrificing L1 security.

For instance, a frontend for an anonymously published blog can't be censorable by any SaaS provider, and no platform provider should be able to tamper with queries to an on-chain PKI used by an end-to-end encrypted chat program. The "web3 superpowers" end up successfully crossing over the boundaries of the blockchain.

2. **Decentralized protocols compose into dApps off-chain.** Decentralized protocols with blockchain-backed security should not primarily compose using on-chain constructs such as standardized smart-contract interfaces. Instead, they are composed in off-chain programs like mobile apps and frontends to create a "full-stack" decentralized system.

For example, clients for a decentralized encrypted chat platform with cryptocurrency payments can be built from a Sybil-resistant DHT, a blockchain-backed naming system, a micropayment network, etc, all of which are protocols trustlessly compose with on-chain logic to provide robust decentralized security. But none of these systems need to have interoperating on-chain logic.

<figure><img src="https://lh4.googleusercontent.com/nFaHg6RtvtYZ1KY056l_SPLlzLVwpRsR8rXJ2-eCL8EdQf2oRO50ikgBEuit83N5aXWiln7UfTvjvVBxAo4Xx1aLKU2vJvXNC4FTf_9dwJjrBXtJ_brvgFP_vRhXWKUi-tty52nS1tneyXty8MCDn_3kXA=s2048" alt=""><figcaption><p>A “tech tree” of a Mel-powered world</p></figcaption></figure>

## Why do we need a new blockchain?

Why do we need a new blockchain to build out this vision?

This is because Mel is a clean-slate design revolving around one key feature --- **trustless, powerful light clients**.

This means that code running on apps outside the blockchain can *know what's going inside the blockchain* without trusting RPC providers like Infura. We can finally take crypto superpowers out of the on-chain ecosystem and into the real world, where people, apps, and devices actually live --- without stuffing the real world onto the on-chain world!

Mel will be used as a piece of *low-level internet infrastructure*, just like the Internet Protocol or DNS. Decentralized secure protocols then pass the superpowers to user-facing apps, and a great example is Earendil (<https://earendil.network>), a decentralized, uniquely censorship-resistant communication protocol we are building as the core communication system for the Mel ecosystem.

## An overview of the docs

Throughout this website, you'll find

* A wiki on key Mel concepts from our [TXO-based data model](/concepts/data-model) to [Melnet](/concepts/melnet-the-p2p-layer), our HTTP-based P2P layer
* Guides on developer-oriented tasks like [building an off-chain composable protocol](/developer-guides/gibbername) and [minting MEL](/developer-guides/getting-tokens/using-melminter)
* Resources like a [FAQ](/resources/page-3) and [yellow paper](/resources/yellow-paper)


# Data model

A key way on-chain logic with "web3 superpowers" can be exported off-chain is through Mel's **data model**: how on-chain data and logic is organized. Mel uses a unique *coin-based* (or UTXO-based) data model, a family including many of the earliest blockchains, like Bitcoin and Litecoin. We go into more detail into the differences in a [separate blogpost](https://medium.com/themelio/utxos-vs-accounts-54b3bbeb4428), but the main difference is that unlike account-based blockchains like Ethereum, Mel has no concept of "contracts" or "accounts".

<figure><img src="/files/p4OMocQM1sixwWQxOSqF" alt=""><figcaption><p>Coin-based vs account-based models</p></figcaption></figure>

Instead, the main abstraction that Mel presents is that of **coins**. The only kind of data on-chain is a "coin", also known as a transaction output (TXO). Each coin contains a sum of money (say, 100 MEL), as well as a **covenant**, or a program that runs to determine what transactions can spend this coin. Knowledge of how to satisfy the covenant of a coin (e.g. by producing a signature from the right public key) essentially maps to "ownership".

Transactions then reduce to atomic actions that remove (or "spend") and create coins, atomically. Since all coins are created by transactions, a coin can be uniquely identified by the transaction that created it plus an **output index** — which output of that transaction created it.

## An example of a transaction

A great way to understand how Mel's coin-based model works is to look at some transactions on Melscan. For example, consider [this rather boring money transfer](https://melscan.io/blocks/1270751/127442da8d5f7a20607e1ab99efb1e22717be852c1b56de02e8e5377fcb450e7).

<figure><img src="/files/eLCcBkEc5BJvoTDKHeqN" alt=""><figcaption></figcaption></figure>

As the picture above illustrates, the transaction spent 4 coins, all of which contain MEL, with the aggregate amount of 0.572319 MEL. They are all encumbered with the covenant with hash `t57...6dg` (which only allows transactions with a signature from a particular public key). These coins all have different coin IDs though, as they were created by different transactions.

The outputs of this transaction are more interesting: they must sum to the same amount of 0.572319 MEL (including the fees), but one of the outputs — the first one with value 0.546470 MEL — is locked by a different covenant, with hash `t97..b6g`, and colored green in the graphical visualization above.

Thus, the net result is that whoever can unlock coins with the `t57...6dg` covenant lost 0.546470 MEL, while the master of the `t97..b6g` covenant gained the same amount. And indeed, this is how a simple money transfer works in a coin-based model!

## Why coins?

At first sight, this seems pretty weird. Don't accounts, like those found on Ethereum, map much more nicely to usual intuitions about money transfers?

The first reason why Mel uses coins is that we *aren't* trying to simulate a ledger of bank account balances. Instead, we want to encode *the consistency of a graph of interdependent events*. A huge class of security-critical problems boils down to establishing a consistent, valid event graph. For example, in a naming system, a successful name transfer also depends on a series of previous events: the previous owner relinquishing control, the new owner registering the name, and so forth. For a PKI, one CA issuing a valid certificate for a domain depends on the absence of conflicting histories of other CAs issuing other certificates for that same domain.

This essentially *forces a programming model suitable for off-chain composability*, where the core purpose of on-chain logic is to use coins and covenants to curate minimal globally-consistent data, while [app-embedded light clients](/concepts/light-clients) query and manipulate this data to implement "superpowered" features.

Furthermore, coin-based transactions can generally be processed more efficiently than account-based transactions. Since transactions declare "up front" what blockchain state they manipulate, block validation can be done entirely in parallel, increasing the performance achievable given a certain level of node decentralization. Coins are also much easier to work with in **stateless clients** a technique that allows light clients to achieve complete equality in security with full nodes by paying a full node's bandwidth — but not storage — cost. (See the yellow paper TODO)

## The contents of coins

A full specification is found in the [yellow paper](/resources/yellow-paper), but from a high level a Mel coin contains the following:

* A **value**, like 100
* A **token denomination**, like MEL, SYM, or a custom token
* A **covenant hash**, referring to the covenant that locks this coin by hash
* Arbitrary **additional data**, usually used to pass arguments to covenants

An interesting fact is that we never embed covenants directly into coins, but only refer to them by hash. This is because the *spending* transaction actually needs to supply the covenant — a technique borrowed from Bitcoin's ["pay by script hash"](https://en.bitcoin.it/wiki/Pay_to_script_hash) that avoids bloating the blockchain state with code before it is run.

## Querying coins

Finally, it should be noted that a really important feature for Mel's off-chain composable ecosystem is that *the coin graph can be trustlessly traversed by light clients*. In fact, the entire Melscan coin-graph explorer could be implemented without trusting a full node!

The details of how this works are described in the [article on light clients](/concepts/light-clients).


# Consensus

**Consensus** refers to the procedure Mel uses to produce and decide on a canonical blockchain history.

In broad strokes:

* Mel uses a *fixed-term proof of stake* to decide consensus participants, known as **stakers**. Stakers must stake SYM, a special PoS token, for integer multiples of 200,000-block (\~70-day) **epochs**, and changes in the effective list of stakers only happen on epoch boundaries.
* Each block is decided by a Byzantine fault-tolerant (BFT) consensus algorithm that eventually produces a **consensus proof** — signatures from stakers owning at least 2/3 of the staked SYM. This produces *immediate finality*, meaning the block can never be reverted, and Mel can never have "block reorgs". Interestingly, the exact consensus algorithm used is not part of the core protocol rules and anything can be used as long as it produces consensus proofs of the right format; the current implementation, however, uses Streamlette, an extremely simple consensus derived from Streamlet.
* The **consensus game** — the cryptoeconomic mechanism incentivizing consensus correctness — generally trades off other properties (like capital efficiency) for robust long-term economic security. The "carrot" of a *collusion-tolerant fee economy* allows stakers to extract value primarily through "benign collusion" on fees rather than block rewards or misbehavior. Strict **slashing**, including a catastrophic form known as "nuking", act as unusually powerful "sticks" against staker misbehavior.

## Staking and epochs

To select who gets to participate in consensus, Mel uses a proof-of-stake system. In short, anyone can lock up a sum of SYM, and while it is locked up, a designated node (the *staker*, which may or may not be the same person who locked up the SYM) receives voting power in consensus.

How does this work in practice? blockchain history is divided into 200,000-block epochs, conventionally numbered from 0. For example, block 12,345 is in epoch 0, while block 1,968,968 is in epoch 9. Anyone can stake (lock up) a particular SYM for a fixed number epochs, during which this SYM will give a designated staker voting power. This is done by sending a special transaction (of type `TxKind::Stake`, see TodoYellowPaper) with a SYM-denominated output, with the following metadata:

* the *beneficiary staker public key* that uniquely identifies the staker who receives voting power
* the *starting epoch* of this stake, or the first epoch in which this stake contributes to the staker's voting power. This must be an epoch after the current epoch.
* the *post-end epoch of this stake*, or the epoch *after* the last epoch that the stake contributes to the staker's voting power.

The SYM — known as an individual **stake** — is then locked up until the end of the the post-end epoch; after the start of the starting epoch and before the start of the post-end epoch, the staker has voting power.

To illustrate this, let's look at example. Here, Stacy is a staker node, and Alice is someone who staked 100 SYM at block height 900,000 for epochs 5..10, designating Stacy as the beneficiary:

<figure><img src="/files/b1qckhD6vYDIb0b4pTFx" alt=""><figcaption></figcaption></figure>

This somewhat weirdly constrained staking system has two important consequences:

* Although stakes can be locked at any time, the *vote weights only change at epoch boundaries*. This turns out to be crucial for [mitigating "weak subjectivity" and enabling scalable and trustless light clients](/concepts/light-clients).
* *Each stake is "inactive" for 1 epoch before unlocking* — epoch 10 in our illustrated example. This is important for economic security, as we will discuss shortly in the section on incentives.

## The BFT consensus itself

Given the list of consensus participants produced through proof-of-stake, a consensus protocol still needs to run to actually produce any blocks. The two important properties of Mel's consensus protocol, Synkletos, are its *immediate finality* and *detached consensus proofs*.

### Immediate finality

Most blockchains use some form of "longest-chain" consensus, such as [Nakamoto consensus](https://decentralizedthoughts.github.io/2021-10-15-Nakamoto-Consensus/). There, anyone can grow the blockchain by building more blocks on existing blocks and broadcasting them, forming a continually growing "block tree". We then simply define the canonical blockchain as the "longest" or "heaviest" branch of this tree by some metric of long or heavy, and design incentives so that people build on what they see as the canonical chain — this then leads to the canonical branch being overwhelmingly longer than the others.

<figure><img src="/files/0simWGZw8hayqU5fF7yx" alt=""><figcaption></figcaption></figure>

Although elegant and highly resilient to temporary network faults, longest-chain consensus has a pretty big problem: lack of **finality**. You can never be sure that what you think is the canonical chain actually is the longest chain, since there *always could be a longer chain that you haven't discovered yet*, due to network lag, a malicious ISP, or other reasons. There's thus no objective, immutable blockchain history.

In practice, this problem mostly affects recent blocks, which often get "reorganized" when other recent branches turn out to be longer, and *most* of the time waiting for a while (say for an hour) before trusting a block's content makes the chances of a subsequent reorganization past its height exceedingly unlikely. But the problem is that there's no way to define how long "a while" is — especially when dealing with possibly malicious networks rather than simply lag.

This an especially bad problem for any apps that need to autonomously verify on-chain data from off-chain or other blockchains — crucial to Mel's off-chain composable vision! All of these apps need to either handle the complex state rollback needed to deal with block reorganizations, or introduce large artificial latencies to wait for blocks to be old enough, which may or may not be long enough depending on factors (network latency and security) outside of the app's control.

Mel therefore does not use a longest-chain algorithm. Instead, we use an *immediately final* BFT consensus. This means that once a block appears on the blockchain, it is permanently canonical and can *never be reverted*.

This solves all the finality problems related to off-chain composability, especially when combined with the next point — off-chain verifiable proofs that a particular block is canonical.

### Detached consensus proofs

Every Mel block committed to history has a **consensus proof** — signatures from stakers whose aggregate vote share for the epoch that the block belongs to exceeds 2/3 of the total vote share.

The interesting thing is that these proofs are *detached* from the precise mechanism in which the BFT consensus works. The consensus algorithm does not need to produce the consensus proof: it may simply guarantee that all honest participants arrive at the same belief for each block. Each staker can then just "ask around" after the consensus produces a result, and given that the BFT consensus is correct, it's guaranteed that they will eventually gather a consensus proof and be able to broadcast the block to the wider Mel network.

In short, there's a three-step process for creating a block in Mel:

1. the stakers, among themselves, run a BFT to decide the block
2. an "asking around" gossip produces a consensus proof
3. the block, with a consensus proof attached, is broadcast throughout the Mel network and becomes part of history.

This means that nobody other than the stakers need to care about the precise way the BFT works. In particular, *changing the consensus algorithm doesn't need a governance upgrade to the blockchain validation rules*, which is important given [Mel's governance-free ethos](/concepts/governance-free-neutrality) and the steady innovation seen in BFT consensus algorithms. For instance, through the history of the Mel betanet we started with a rough implementation of HotStuff, moved to the extremely simple and elegant Streamlet consensus, then to a different instantiation, ["Streamlette"](https://github.com/mel-project/streamlette), optimized for deciding one block in an immediate-finality setting.

Moreover, the simplicity of the consensus proof makes it really easy to verify by off-chain apps other than blockchain nodes. A light client that has the vote weights for the current epochs (which can be known [near-trustlessly](/concepts/light-clients)) can easily verify a claim that a certain block is canonical, by simply checking the signatures in the consensus proof and adding the corresponding weights. This makes fully consensus-verifying light clients much easier to write than those for PoS algorithms with complex finalization rules (say, Ethereum), or even longest-chain proof-of-work blockchains.

## Consensus game

While staking decides *who* gets to create blocks and the consensus algorithm *how* they create blocks, the consensus game is the incentives behind *why* anyone would create blocks.

The overall theme of Mel's consensus game is a overwhelming focus on maximizing economic security, especially long-term economic security. This because with governance delegitimized, we cannot really rely on "the community will fork away the bad guys" as a normal-case defense against consensus attacks (though, as we'll see, it's still used as a defense-in-depth for extreme cases). Upholding consensus security needs to be the profitable thing to do for stakers in a wide variety of circumstances.

Towards this end, we have a "carrot" and a "stick".

### Carrot: collusion-tolerant fee economy

Unlike most blockchains, Mel studiously avoids non-coordination assumptions in its consensus incentives. This means that it's *totally fine for rational stakers to collude* and attempt to extract monopoly profits, or worse. Decentralization becomes more a matter of fault tolerance and ensuring that the average staker is economically rational, rather than trying to make collusion impossible, making the consensus oligopoly situations that often occur with both PoS and PoW much less scary.

The way Mel does this is a little surprising: we *give stakers all the tools they need to collude in a fee cartel*. In a system distantly inspired by EIP-1559, stakers vote on a uniform minimum fee level that all stakers must charge, in a system designed to simulate a "despotic" blockchain controlled entirely by a rational profit-maximizing monopoly — who would turns out to actually behave in a trustworthy manner. This way, incentives to collude to extract more fees disappear, the equilibrium fee is the same no matter the level of collusion, and a whole lot of game-theoretical gnarliness surrounding pathological strategies in not-quite-collusion conditions (e.g. just a few dominant stakers) disappears.

Furthermore, our fee model turns to have the additional benefit of funding staker income almost entirely through fees rather than inflation, making staker income much more closely aligned with the interests of actual users of the blockchain rather than "SYM go up" or even "block reward go up".

### Stick: slashing and nuking

Like in other PoS systems, misbehaving stakers are punished by *slashing* their stake. Anybody observing a staker misbehaving in a provable way (say, by signing two conflicting blocks for the same height) can submit a transaction that slashes their stake. This is also the reason for the mandatory "inactive epoch" before unstaking: to give a chance for slashing evidence to be submitted before the staker leaves.

Two important features separate Mel slashing from most other systems.

First, *slashing totally destroys the stake, redistributing it among other stakers*. Unlike blockchains like Ethereum that attempt to differentially penalize slashing based on how likely it is that it's part of coordinated attack, any slashing in Mel splits up the entire stake to the other stakers. Not only does this simplify the incentives and increase security, it gives an incentive for stakers to police each other, as they all stand to profit if a staker is slashed!

Second, there is *nuking*, an exceptional action similar but not quite like slashing, where more than 1/3 of the voting power has behaved maliciously. In this case, it is not possible to slash them on-chain anymore, since the malicious stakers can simply censor anybody who attempts to expose them.

Instead, *all nodes and clients are programmed to shut down* if given proof of nuking. This makes attacking the network successfully without quickly shutting down the network extremely difficult even with the cooperation of all consensus participants, making the set of adversaries who would benefit from breaking consensus safety much smaller.

If even despite this threat nuking happens, a manual hard-fork recovery would indeed be necessary, but coordinating this would be much easier because people would be forced to recover the nuked network; there is simply no option to go along with the attack. Or in Vitalik's words, successful consensus attacks ["default to chaos" rather than "default to victory"](https://vitalik.ca/general/2020/08/17/philosophy.html).

## Summary

Mel's consensus is a combination of a fixed-term proof-of-stake, a Byzantine fault-tolerant consensus algorithm, and a collusion-tolerant fee economy with strict slashing and "nuking".

Proof-of-stake decides who gets to participate in consensus, and the consensus algorithm decides how blocks are created and provides immediate finality. The consensus game incentivizes stakers to create blocks reliably, with the "carrot" of a collusion-tolerant fee economy and the "stick" of strict slashing and nuking.

The combination of these three elements provides strong economic security against long-term consensus attacks, while also making light clients easy to write and blockchain upgrades easy to implement.


# MEL: trustless sound money

Despite using [SYM for proof-of-stake consensus](/concepts/consensus), Mel's native *circulating* currency is **MEL**. MEL is used extensively in the base-layer incentive design:

* all transaction fees must be paid in MEL
* block rewards are denominated in MEL

The most interesting feature of MEL is that it is probably the *first ever cryptocurrency to have* **endogenous stability**. This means that:

* The way MEL is issued is entirely trustless and decentralized. Just like Bitcoin, no oracles, governance DAOs, or issuers are involved.
* Nevertheless, MEL maintains a stable purchasing power.

## Why endogenous stability?

Why do we want something like this in the first place?

First of all, volatile cryptocurrency prices actually do pose a serious problem. The value of a currency going up and down erratically makes it bad as money: it becomes less useful as a store of value or unit of account, and it greatly damages the ability to create interesting financial instruments. Nobody is going to sign a 30-year mortgage in Bitcoin without knowing whether Bitcoin will be worth 1, 1,000, or 1,000,000 apples 30 years in the future.

This also greatly impacts mechanism design and DeFi --- the ecosystem relies heavily on fiat-pegged stablecoins like USDC and Dai. But these stablecoins are not what we want: they inherently rely on exogenous trust, in oracles, central issuers, etc. Note that this is a problem even when the stablecoin aims to track a basket of commodities rather than fiat currency — we may lose centralized trust in the Fed, but not trust in oracles. Oracles supplying external information about the market are crucial for the feedback loop of any stablecoin backed by off-chain assets, and they rely heavily on preexisting trust in people or institutions, not endogenous trust guaranteed by protocol incentives.

Thus, we uses an oracle-free system that doesn’t try to peg MEL to any external asset. Instead, we define a new, *trustlessly-measurable value unit*, called the **DOSC (day of sequential computation)**, which can be measured on-chain by an autonomous mechanism with full endogenous trust. This, and not dollars or gold, is what the core mechanism, called Melmint, then pegs MEL to.

## How does Melmint work?

The one-sentence summary of Melmint’s job is to maintain **peg 1 MEL to 1 DOSC**.

### The peg target: 1 DOSC

A “DOSC” is a “day of sequential computation”. It’s defined as the *cost of running a sequential computation for 24 hours, using the fastest processor available*. For example, a DOSC in the year 2000 is the cost of occupying the fastest single CPU core *available in 2000* for 24 hours, while a DOSC in the year 2021 is the cost of doing the same with a 2021 processor.

The DOSC has two really cool properties that make it a great target for a peg:

* It has a relatively stable purchasing power. Empirically, the “fastest processor” typically costs about the same, despite its performance drastically increasing over time. We explore this further in our [DOSC analysis data](https://github.com/themeliolabs/dosc-analysis).
* More importantly, it’s *trustlessly measurable* through a “sequential proof of work”. A hash-based sequential proof of work, like the one invented by Cohen and Pietrzak, produces a succinct proof that starting from some seed `x`, a large amount of sequentially nested hashes `H(H(H(H(...H(x)))))` have been computed. By using a cleverly incentivized on-chain benchmark, we can then measure how fast the fastest processor is. This gets us a way of showing on-chain that we’ve wasted a day’s worth of sequential computation, letting us measure the DOSC with strong endogenous trust. The DOSC’s trustless measurability is the *key to Melmint’s oracle-free mechanism*.

### How is this peg maintained?

There are two main steps to actually pegging the MEL to DOSC: *erg-minting* and the *central mechanism*, summarized in the following picture:

<figure><img src="/files/N2jl3x6npeTOc6cIcjws" alt=""><figcaption></figcaption></figure>

Erg-minting involves allowing anybody to use a special transaction type (`DoscMint`) to prove that they completed a certain amount of sequential proof-of-work. This transaction then generates $$k$$ "erg" for each DOSC of work done. $$k$$ here is not a constant, but an exponentially increasing conversion factor --- while 1 DOSC of work may generate $$10$$ erg today, it might generate $$100$$ erg a year from now. Due to this rapid inflation, erg act as an on-chain, tokenized representation of *recent* sequential work.

The central mechanism uses **Melswap**, a built-in, Uniswap-like decentralized exchange that supports all Mel-based tokens. Its objective is to *peg 1 MEL to 1 DOSC worth of SYM*, using a feedback loop that prints MEL and buys SYM or vice-versa. Recall that SYM is Mel's separate, proof-of-stake token. First, we read two exchange rates off of Melswap:

* $$s$$: how much SYM can 1 MEL buy
* $$t$$: how much SYM can 1 erg buy

Then, Melswap targets an exchange rate of 1 MEL = $$tk$$ SYM --- that is, 1 DOSC ($$k$$ erg) worth of syms. When this $$s=tk$$ peg fails to hold, we use *inflation* to back it:

* **Mel too cheap**: This is the blue box in the picture, where $$s\<tk$$. In this case, Melmint continually prints SYM out of thin air, using them to buy MEL, which are subsequently destroyed. This artificially increases the demand for MEL, increasing its purchasing power until $$s=tk$$.
* **Mel too expensive**: This is the red box in the picture, where $$s>tk$$. Here, Melmint would instead print mels, using them to buy syms. This increases the supply of MEL, decreasing its price until $$s=tk$$.

We now take a look at each individual step in this process:

### Step 1: Minting erg

The first step in Melmint is for minters --- which can be anybody --- to mint **erg**, $$k$$ of which represent a DOSC.

#### Proving work

In summary, the `data` field of a DoscMint transaction contains two values: a *difficulty exponent* $$z$$, as well as a *proof* $$\pi$$. This uses MelPoW, a non-interactive proof-of-sequential-work system whose details aren't important for this document, but in short, $$(D,\pi)$$ is a proof that roughly $$2^z$$ nested hashes have been computed on the *seed* $$\chi$$, which consists of the first input to the transaction, hashed together with the block hash of the block in which that first input was confirmed.

The key property here is that *the minter cannot predict* $$\chi$$ *before the first input to the transaction is confirmed*. This means that the minter must have finished the $$2^z$$ hashes after the first input has confirmed, but before the DoscMint transaction itself has confirmed. We now have a time interval, and therefore a *trustless measure of the minter's speed in hashes per second*.

By simply remembering the fastest minter ever seen, the blockchain knows how many hashes the fastest minter can do in a day; let's call that $$M$$. Then, we know that our minter did $$d=2^z/M$$ DOSC of work --- that is, the same amount of sequential work as the fastest minter run for $$2^z/M$$ days would do.

#### Creating ergs

Now, the DoscMint transaction has proven that the minter did $$d$$ DOSCs of work. The blockchain needs to award the minter with $$k d$$ erg (where $$k$$ is the erg-DOSC conversion factor) --- in Mel's coin-based model, this is simply done by allowing imbalance in incoming and outgoing erg: the transaction's allowed to produce $$k d$$ more erg than it consumed.

**Important note**: $$k$$ here is an exponentially increasing conversion factor: $$k=1$$ at the genesis block, and then $$k$$ increases by 0.00005% every block. This translates to approximately a 70% annual inflation rate. The purpose of an exponentially increasing $$k$$ is so that *the supply of erg is dominated by freshly minted ergs* --- this ensures that the market value of $$k$$ erg tracks the 1 DOSC cost of creating those ergs. If $$k$$ were instead constant, a drop in demand would cause a glut of old erg that would not sell, where $$k$$ erg become worth less than 1 DOSC despite them costing 1 DOSC when they were minted. This would make erg useless as way of quantifying the value of a DOSC.

#### Selling the ergs

Because of the astronomical inflation rate, ergs are not very useful as money. Instead, minters would almost always want to sell their ergs soon for a more value-stable asset.

Mel conveniently comes with a built-in decentralized exchange, called Melswap, where any Mel-based token (including custom tokens) can be exchanged for any other. This, of course, includes ergs. Minters can easily take their ergs and exchange them for other tokens, most likely the two main Mel tokens Sym and Mel.

In particular, the SYM/erg market is "special" --- it is crucial for driving Melmint's core pegging mechanism, and in fact it's subsidized by diverting half of all SYM block rewards to the SYM/erg Melswap pool.

### Step 2: Core pegging mechanism

#### Inflation-backed MEL/SYM peg

The core pegging mechanism of Melmint is that *through inflating either MEL or SYM, 1 MEL is pegged to* $$k$$ *ergs (1 DOSC) worth of sym*. In particular, at every block height, either some SYM or some MEL is printed out of thin air and used to buy the other token in the MEL/SYM market on Melswap, always "nudging" the exchange rate closer to 1 MEL = 1 DOSC worth of SYM.

For example, consider a Melswap market with the following exchange rates:

* $$1$$ MEL = $$2$$ SYM
* $$1$$ ERG = $$1.5$$ SYM
* $$k=1.5$$

Here, "1 DOSC worth of SYM" would be "1.5 erg worth of SYM", or $$1.5\times 1.5 = 2.25$$ SYM. Yet the current market exchange rate is only $$2$$ SYM, meaning that *MEL is too cheap*.

Thus, to support the peg, every block Melmint will print up some SYM to buy up MEL, until the peg holds.

#### What backs MEL?

Any stablecoin can easily hold a peg when the stablecoin is too expensive --- just print more. The true challenge is when the peg must be defended when the market price is below the peg. The stablecoin must in some way be "backed" by another asset, with an independent value, that it can be redeemed for at the pegged value.

In our case, MEL's value is backed by the *value that can be extracted by inflating sym*. We call this value the **implicit reserve** of Melmint. Because inflating SYM is essentially a tax on all holders of SYM, the implicit reserve is very roughly the market capitalization of SYM. We can therefore say that **SYM backs MEL**.

Thus, to be stable in a worst-case scenario where everybody wants to sell their mels, the **MEL marketcap must stay below the SYM marketcap**. Fortunately, as the [original Melmint paper shows](https://docs.themelio.org/assets/mel.pdf) that's likely to be the case in any reasonable economic conditions.

## Failure scenarios

### Drastic changes in DOSC purchasing power

Because Melmint pegs 1 MEL to 1 DOSC, if the value of a DOSC drastically changes, MEL will lose its stable purchasing power. Historically, this has not really happened, and due to the definition of a DOSC in terms of *time* rather than *amount* of computation, usual technological improvements will not cause shocks to the value of a DOSC. Instead, an external shock must greatly affect *how expensive is running the fastest processor available*. Here are some hypothetical scenarios where the value of a DOSC will drastically change:

**Sudden increases in DOSC value**:

* Massive energy crisis makes electricity 10x more expensive than before.
* Somebody finds a way to build an extremely expensive, energy-inefficient machine that does sequential computation 10x faster than top-end machines, at 100x the daily cost.

**Sudden decreases in DOSC value**:

* Breakthrough in energy generation makes electricity nearly free
* Breakthrough in processor design leads to the domination of extremely high core-count machines where the per-core operational cost is drastically lower, yet sequential speed is comparable to current processors
  * "GPU except every core is a fully general-purpose CPU"

### Sudden decrease in Mel market sentiment

For a variety of reasons (say, a general cryptocurrency crash), there might be extremely rare scenarios where a large amount of SYM or MEL is simultaneously panic-sold. This threatens the basis of the Melmint peg by reducing both MEL demand and its implicit reserve, and in a case where MEL issuance cannot be backed by the implicit reserve, the peg may no longer be tenable.

The danger here is hyperinflation of SYM and subsequent mechanism collapse, as Melmint desperately prints SYM to buy and prop up the value of MEL, until both SYM and MEL are utterly worthless. Fortunately, this is inherently prevented by the way Melmint works --- per the Melmint specification, the amount of assets printed to support the peg is *proportional to existing liquidity in the SYM/MEL market*. This means that "how fast" Melmint reacts depends on market conditions. In a panic where market participants anticipate a possible Melmint-driven SYM hyperinflation that will cause both MEL and SYM to become worthless, liquidity will quickly drain from the MEL/SYM market as both MEL and SYM are dumped for alternative assets, making the prophecy self-refuting.

Without MEL/SYM liquidity on Melswap, Melmint is effectively turned off. **The peg will fail**, massively increasing MEL volatility, but a wholesale monetary collapse will be averted. This is especially because unlike users of USD stablecoins, MEL users never expected zero exchange-rate risk and are unlikely to completely dump MEL due to a temporary pause of the peg. The economic impact of such a depeg is likely to be around the same order of magnitude as a fiat "currency crisis" --- bad but not catastrophic.

Once sufficient liquidity returns to the Melswap MEL/SYM market, the peg will gradually be restored.


# Governance-free neutrality

An important principle of Mel is that *after the protocol stabilizes, governance is not socially legitimate*. This means that once the proper mainnet launches, MEL and SYM are widely circulating, and the protocol reaches "1.0", Mel is not supposed to allow, or need, any sort of changes (e.g. "hard/soft forks") to the core blockchain rules.

Governance-freedom has an interesting *synergy* with Mel's off-chain composable vision. An off-chain composable ecosystem needs an L1 that does not change, since protocol upgrades tightly couple off-chain app development and L1 improvements, and off-chain ecosystems are unlikely to have a unified "community", making the credible neutrality of their common L1 both important and fragile. In the other direction, a L1 that wants to be governance-free needs to be used extensively by off-chain apps --- an primarily on-chain ecosystem encourages rather than resists governance.

## Off-chain needs governance-freedom

The key property of blockchains is **endogenous trust**: we can trust a blockchain *without trusting any of the people running it*. Trust emerges from internal incentives that drive rational actors, rather than from preexisting trust in the parties that run the protocol. This is probably in fact *only* found in blockchains and similar tech: BitTorrent has decentralization, Keybase has transparency, and TLS has security, to name a few, but none of them have endogenous trust.

Any sort of consensus-breaking governance (like the numerous Ethereum network upgrades) inherently damages endogenous trust, since it enables *external actors to rewrite the protocol upholding the internal incentives* --- ultimately rooting trust outside the protocol, in the hands of developers, community sentiment, etc.

Trading away the blockchain killer feature is sometimes "okay" for an on-chain ecosystem; not everything on-chain is there to maximize endogenous trust, and often having your decentralized, transparent "world computer" backed by trusting the Ethereum/Solana/etc community is perfectly fine, and the advantages of the rich composability and interoperability offered by smart contract ecosystems outweigh any reduction in security.

But it is not fine for off-chain apps, whose *only reason* to use a blockchain is endogenous trust. Removing trust in community-run Tor directory servers, for instance, is a lot less appealing if the only result is shifting trust from the Tor community to the Ethereum community. Only an L1 with an uncompromising focus on the robust credible neutrality and reliability offered by purely incentive-based, endogenous trust can unlock new horizons in decentralized security in the off-chain world.

Furthermore, off-chain ecosystems are far more disrupted by protocol upgrades compared to L1 smart contract ecosystems. Even far-reaching changes to the blockchain rules (e.g. Ethereum's transition to PoS) can be made seamless to on-chain code, but these protocol upgrades entail *every single blockchain client upgrading at once*. In an off-chain ecosystem, blockchain light client implementations will massively proliferate as dependencies of any program that needs to interact with on-chain logic, making coordinating such an upgrade extremely difficult and failures highly disruptive. While a protocol upgrade for current L1s means at worse a glitchy day on cryptocurrency exchanges and wallets, a upgrade of an L1 underlying a global off-chain ecosystem means all sorts of apps greatly removed from the "crypto community" requiring updates, and perhaps even embedded or unmaintained clients simply becoming "bricked".

## Off-chain produces governance-freedom

The interesting other side of the coin is that precisely because protocol upgrades are so disruptive, an off-chain ecosystem *socially enforces L1 governance-freedom*. Coordinating everybody in a dispersed ecosystem, full of diverse protocol stacks and communities, to switch to a different set of protocol rules is practically impossible.

A great example of this dynamic in action is the Internet Protocol. Like Mel in an off-chain composable ecosystem, IP is a deeply embedded, simple, and low-level principle that is crucial for the functioning of many different protocol stacks.

And as we would expect, "governance" on IP is *extremely* hard. Ever since IPv6 was created in 1998, many influential members of “the community” have spent great efforts to try to replace the older IPv4 with its technically superior successor. Impressive-sounding events sponsored by “big shots”, like the Internet Society’s “World IPv6 Day” in 2011 and “World IPv6 Launch Day” in 2012 were supposed to jump-start IPv6 adoption.

Yet IPv4, though it doesn't even try to be governance-free and in fact has serious limitations like a drastic shortage of IP addresses, is just not going. 25 years later and 11 years after “World IPv6 Launch”, only a little more than 30% of networks support IPv6, and the vast majority of Internet traffic continues to be IPv4.

Thus, even the security of Mel's incentives not changing depends on incentive-based endogenous trust, not preexisting trust in some community. The sort of social-coordination problem that prevents a protocol from upgrading is exactly the sort of incentive-based security that upholds the correct execution of a blockchain rules.


# Covenants

In Mel's [data model](/concepts/data-model), every coin/UTXO is locked by a *covenant*, or a program that constrains what sort of transaction can spend it. Common covenants include:

* Checking that a transaction is signed by a particular public key
* Checking that a transaction is signed by some subset of keys (a *multisig* covenant)
* Encoding arbitrary stateful logic using *self-propagating* covenants

On the blockchain level, covenants are written in the low-level [MelVM](/resources/melvm-spec) language, but in practice covenants are programmed using the high-level [Melodeon](https://melodeonlang.org/) language. More info on specific programming patterns can be found in the [Melodeon guide](https://guide.melodeonlang.org/).


# Light clients

**Light clients** in Mel are participants that don't replicate the blockchain history or state. Instead, when they want to query on-chain information, they ask any [full node](/concepts/network-architecture) for that information.

The key thing to remember is that *light clients are trustless* — they ask a full node for information, but they do not trust the full node not to lie to them. This is absolutely central to enabling scalable off-chain composability, since most off-chain apps would not want to replicate blockchain history.

Trustless light clients are possible due to two things: extensive **state commitments** that allow a light client to verify proofs of blockchain data with only the latest block header, and a **bootstrapping** mechanism that lets clients retrieve the latest block hash while only trusting the [consensus mechanism](/concepts/consensus).

## State commitments

Every Mel block has a short **header** that commits to the contents of that block and previous history, but also the entire *state* of the blockchain. The detailed data format can be seen in the TodoYellowPaper, but on a high level, the Mel block header contains the root hashes for the following **sparse Merkle trees** (SMTs) that commit to on-chain state:

* Block number of a previous block -> its hash
* [Unspent coin](/concepts/data-model) IDs (transaction hash and index) -> coin contents and the height at which it was committed
* [Covenant](/concepts/data-model) hash -> number of unspent coins with that covenant
* A list of all *frozen* [stakes](/concepts/consensus) (whether active or inactive)

SMTs are a key-value mapping structure that has an important property: they can produce succinct proofs, checkable by anyone with the root hash, that a certain key is mapped to a certain value (proof of inclusion), or that a certain key is absent from the mapping (proof of exclusion).

What this means is that when a light client asks a full node, say, to list all the unspent coins locked by a certain covenant, the full node is able to *prove* to a client the correctness of the response. (In this case, by providing proofs of inclusion for all the unspent coins, as well as a proof of inclusion of the *count* of the coins, showing that the full node is not hiding any coins)

This is useful beyond simple queries made by e.g. wallets. In fact, we can design [highly flexible *coin graph traversal* APIs](/developer-guides/gibbername/melprot-a-quick-intro) on top of these verified SMT queries, allowing trustless and efficient manipulation of all sorts of on-chain data:

{% code overflow="wrap" %}

```rust
// Traverse through the first parent, its first parent, etc of 674735b7b7e4163f7404715bd6b8433a8db523c52279ad07e2b4e88a6708d873 indefinitely, until a coinbase transaction is hit
let client = melprot::Client::autoconnect(NetID::Mainnet);
let traversal = client.traverse_back(
   BlockHeight(1901450),
   "674735b7b7e4163f7404715bd6b8433a8db523c52279ad07e2b4e88a6708d873".parse()?,
   |tx| {
      // always go to the first input
      Some(0)
   }
).boxed();
while let Some(next) = traversal.next().await? {
   println!("transaction found: {:?}", next);
}
```

{% endcode %}

Of course, all this magic is possible only if we assume that the client already knows the latest block header. That requires a secure bootstrapping procedure.

## Bootstrapping light clients

Before doing any queries, a light client must know the latest block header. Of course, the client can't just ask the full node for this info — the full node could lie and subvert all the security guarantees of Mel!

Instead, the client follows a two-step procedure:

1. The *staker vote weights* of the current [consensus epoch](/concepts/consensus) are determined, based on the active stakes of the current epoch.
2. The latest block header, together with a *consensus proof* that more than 2/3 of the vote weight voted for the block header, is retrieved from the full node. This then proves that the claimed block header really was approved by the blockchain consensus.

### Determining the vote weights

Recall that in the [Mel's consensus mechanism](/concepts/consensus), the set of active stakers and their voting weights is the same during every 200,000-block epoch, being determined by which stakes are "active" during this epoch.

It turns out that since the 1. the block header commits to all locked stakes, not just all active ones, 2. stakes must be locked before their first active epoch starts, *the last block header of epoch N commits to the active stakes of epoch N+1*.

This gives us an elegant recursive algorithm to derive the current stake set, as long as the client knows *some* stake set (and it always does, since the initial stake set is hardcoded):

To get the active stakes of epoch N:

* If we already know it, we are done. (base case)
* Otherwise,
  * We get the active stakes of epoch N-1
  * We ask for the last block header of the epoch N-1, verifying the consensus proof with the active stakes we just obtained
  * We ask for the list of all stakes locked by the end of epoch N-1, verifying it against the commitment in the block header
  * We filter the list for stakes that will be active in epoch N, and return that.

### "Ultraweak subjectivity"

There is a subtle attack on the sort of consensus-participant-updating bootstrapping procedure described. If a light client is very out of date (say, it only knows the initial stake set and not anything subsequent), an attacker can collude with *old stakers who have completely unstaked* to sign malicious claims about block headers — including epoch-end block headers — and completely mislead a client as to the current state of the blockchain.

This problem, called ["weak subjectivity"](https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/weak-subjectivity/) since it makes the canonical current block "subjective", is common to PoS blockchains. It only works on old clients, since incentives ([slashing](/concepts/consensus)) defend against collusion with newer stakers who still have money at stake.

Mel's long consensus epochs defends against this. All stakers must stake for at least epoch, and their stakes must lie inactive but locked for at least another epoch. This means that even in the worst case, where every staker stakes for the shortest possible period, only clients that have been offline for more than two epochs are vulnerable to weak subjectivity --- that is a whopping *140 days*.

This is far beyond the typical weak-subjectivity period of other PoS blockchains (e.g. Ethereum has 2 weeks), and probably longer that any reasonable light-client app would stay offline. In a sense, we can say that Mel has "ultraweak subjectivity".


# Network architecture

In Mel, participants in the network can be divided into three roles:

<figure><img src="/files/ggwyQptNEckTbZTMjMJ0" alt=""><figcaption></figcaption></figure>

* **Staker nodes** are full nodes directly participate in the proof-of-stake [consensus](/concepts/consensus). They have stake, denominated in SYM, locked up on-chain, and receive consensus voting power in exchange.
* **Replica nodes** are full nodes that do not have SYM stake, but replicate and validate the output of the staker consensus. They not only provide a “CDN” for the blockchain, but more importantly by using a [nuking procedure](/concepts/consensus#stick-slashing-and-nuking), they shut the network down if a quorum of stakers produces invalid results.
* **Light clients**, also known as "clients", merely *consume* the security enforced by the stakers and replicas. They do not replicate the blockchain, but trust consensus proofs provided by the stakers that commit to a particular blockchain state. As long as the network as a whole is working correctly, light clients cannot be fooled. [Trustless light clients](/concepts/light-clients), embedded into apps as libraries (like [melprot](/developer-guides/gibbername/melprot-a-quick-intro)), are the cornerstone of Mel's off-chain composable vision.

{% hint style="info" %}
**Note**: "stakers" are called "validators" in most other blockchains. We intentionally use a different word because:

* *Staker* normalizes self-staking rather than pooled staking, and makes it clear that delegating stake to a staker is similar in trust to giving them a loan.
* *Validator* is highly misleading, since the main purpose of consensus is not to "validate" blocks, but to produce and decide on them. In fact, "validation" describes the job of normal full nodes much better!
  {% endhint %}

The staker and replica nodes form a P2P gossip network using the [HTTP-based melnet protocol](/concepts/melnet-the-p2p-layer); light clients can also talk the same protocol to query these nodes.


# Melnet: the P2P layer

Mel uses a very simple P2P protocol, melnet, for communication among [full nodes](/concepts/network-architecture) and between full nodes and light clients. Implemented as a [Rust crate](https://crates.io/crates/melnet2) within the [nanorpc](https://crates.io/crates/nanorpc) framework, it has the following features:

* Unstructured gossip network, similar to Bitcoin (and unlike libp2p and similar DHTs)
* Uses JSON-RPC 2.0 over plain HTTP/1.1. Not even WebSockets is used.

Using simple web standards makes it easy for (still future) web-based clients written in JavaScript or WebAssembly to directly access the P2P network. In-browser light clients, or even full nodes, become possible.

{% hint style="info" %}
Eventually, we'll have a more detailed description and spec of melnet here. For now, [check out the actual codebase on GitHub](https://github.com/mel-project/melnet2)!
{% endhint %}


# What belongs on-chain?

Instead of stuffing as much functionality as possible into on-chain smart contracts, Mel's paradigm encourages using on-chain logic and data much more sparingly, with complex app logic and ecosystem composability happening off-chain. What exactly belongs on-chain then?&#x20;

The answer is that for any decentralized app or protocol, the **minimal root of trust** should be implemented on the blockchain. This means

* the *smallest* part of the system
* on whose security the whole system's security depends upon

For example, consider an end-to-end encrypted chat app. Most parts of the app aren't actually security-critical. For instance, it isn't particularly important how secure the storage of in-transit messages are, since it's all encrypted anyway --- they could very well be put on some centralized cloud like AWS. But one part of the system is really important: the *public key infrastructure* (PKI), or the system that lets users know the public keys of other users. If this were centralized and insecure, end-to-end encryption could be entirely defeated through impersonation and [man-in-the-middle](https://en.m.wikipedia.org/wiki/Man-in-the-middle_attack) attacks.

Thus, the PKI should be built with on-chain trust, either through custom on-chain logic or by leveraging some existing Mel-based protocol (e.g. an ENS-like secure naming system?)

{% hint style="info" %}
More detailed advice on how to practically design the on-chain pieces of an off-chain composable protocol can be found in the [Gibbername tutorial](/developer-guides/gibbername/design).&#x20;
{% endhint %}


# Overview

A high-level overview of the different developer tools available to get started participating in the Mel ecosystem.

Mel is currently in *beta mainnet*: there is a "[mainnet](https://scan.mel.org/)" with relatively stable and persistent history, but the staking tokens are not publicly available and the protocol is not quite production-ready.

Nevertheless, there is already a rich developer toolkit for interacting with the blockchain.

## Mel's architecture

Before diving into the specific tools, it's helpful to keep in mind the overall architecture of Mel.

<figure><img src="/files/ggwyQptNEckTbZTMjMJ0" alt=""><figcaption><p>Mel off-chain composable app ecosystem architecture</p></figcaption></figure>

Participants in the Mel blockchain network itself can be roughly divided into (full) **nodes** and (thin) **clients**. Nodes replicate every block and transaction on the blockchain and help maintain network security. A subset of nodes, **staker nodes**, have `SYM` locked up and participate in the consensus to decide canonical blockchain history. All other nodes are **replica nodes** that replicate and verify blocks but do not propose new blocks.

Clients do not replicate any blocks, but are able to interact with the blockchain state by asking full nodes. An important design principle is that *clients do not trust full nodes*: full nodes must present proof that the info sent to the client is part of canonical blockchain history.

**Apps** are generally built *on top of* Mel light clients. The most basic app is probably a **wallet**, a tool for managing on-chain assets and "manual" interaction with blockchain state. More complex applications can be built by composing on-chain logic with off-chain functionality using trust-minimizing light clients; this is the cornerstone of Mel's off-chain composability vision.

## Tooling overview

Currently, the following tools are available:

### Full nodes

Both staker and replica nodes are supported by **melnode**, our official node software. A basic guide is currently available.

Staking requires SYM, which is currently available only on the testnet. You can follow our testnet staking guide to learn how to run a staker node.

### light clients

We have a full-featured light client library available in **melprotocol**, our protocol crate. You can find detailed documentation on docs.rs.

Also available is an introductory guide to building your first trustless, off-chain app using a Mel light client.

### Wallets

We have an official, feature-complete CLI reference wallet called `melwallet-cli`.

There is also an alpha-quality GUI wallet, [Mellis](https://github.com/Mellabs/mellis), but features may be missing or broken.

### On-chain development

You can deploy on-chain logic using our high-level covenant programming language [Melodeon](https://melodeonlang.org/).

### Melminter

Help contribute information about the current price of computation to the network while earning Mel native tokens by running your own instance of [`melminter`](/developer-guides/getting-tokens/using-melminter), a convenient CLI for minting ERG and converting to MEL.


# Gibbername: your first off-chain composable protocol

## On-chain vs. off-chain composability

The best way of understanding **off-chain composability**, Mel's new paradigm for the blockchain ecosystem, is to contrast it with the way Web3 is right now. Right now, smart contracts using standard APIs like ERC-20 form a pretty nice interoperable on-chain ecosystem, enabling applications like complex DeFi instruments beyond what's possible with first-generation blockchains like Bitcoin.

But interacting with anything outside this smart contract ecosystem turns out to be *really* hard. For instance, let's say you heard that ENS is decentralized and trustless, so you want to use it to replace DNS in some off-chain decentralized protocol (maybe to name Tor hidden services?).

You might think that it'll be a nice drop-in replacement, since it's very easy to integrate ENS into on-chain contracts. But you would be very wrong: the names are stored "illegibly" in the ENS contract state, exposed only through an on-chain contract API. All of your options for calling this API from off-chain code are bad:

* **Sacrifice security:** just call RPC methods on some full node (with something like Web3.js), who you end up trusting completely. Just like with DNS, a centralized third party can now arbitrarily lie to you, censor you, etc. Oops!
* **Sacrifice scalability**: force all your clients to run their own Ethereum full node, that you then query using the same RPC methods. This is going to be impractical for almost any application.
* **Reverse-engineer the contract and hack together a hyper-fragile light client**: Ethereum does have *some* light-client support. So you can sorta-trustlessly query ENS names by disassembling the EVM code of ENS, figuring out where exactly in the blockchain state it stores name information, then craft the exact `getProof` calls needed to get the data in a verifiable way. But this is horribly complex and brittle. The smallest ENS governance upgrade can require you to re-reverse-engineer the EVM code, not to mention L1 issues like consensus-breaking upgrades and block reorganizations. You'll never compete against DNS's reliability and simplicity.

Furthermore, this "on/off-chain boundary problem" persists regardless of how much blockchains scale and how far we make protocols "crypto-native". Any web3 ecosystem has components like frontends, apps, and *human users* that fundamentally live off-chain while needing to securely talk to on-chain.

We need to solve this problem to have a truly successful Web3, with a rich ecosystem of secure decentralized protocols and apps outside of the blockchain. This requires a new kind of blockchain — Mel — that actually supports use as an off-chain root of trust. Features like a simple-to-implement protocol, a governance-free development model, and embeddable light clients cooperate to let off-chain programs efficiently utilize on-chain security.

More interestingly, on-chain logic for decentralized protocols plays a very different role. Instead of interoperating with on-chain code, *on-chain protocols are written for off-chain consumers*. Mel's overall data model lacks the entire concept of smart contracts calling each other, but it is supremely suited for encoding on-chain logic in a way that is legible and usable off-chain.

## What will we build?

To demonstrate that, we'll build **Gibbername**, a trivial DNS-like decentralized naming system that would serve as an exemplary citizen of an off-chain composable ecosystem. Gibbername allows you to

* **Register** a short, human-readable name. You won't be able to pick the name though, it will look something like `sublak-demfet`. (As we'll see, this makes the implementation really simple)
* **Bind** the name to any data you wish, like a DNS record or JSON document.
* **Transfer** the name to another person.

Like DNS, Gibbername will be very easy to integrate into apps, with a simple Rust library that allows for looking up and managing names. Unlike DNS, though, Gibbername will have three important, blockchain-backed "superpowers":

* **Identity retention**: without the consent of the current owner, nobody can change the name-to-data mapping or transfer the name
* **Censorship resistance**: nobody is able to prevent from name from resolving or prevent the current owner from updating or transferring the name
* **Permissionlessness**: nobody can stop name registrations

All the above properties will be upheld despite the fact that lookups, transfers, etc will all be initiated by off-chain code rather than on-chain contracts.


# melprot: a quick intro

## melprot::Client: a trustless light client

The most basic tool for light-client interaction in Mel is `melprot::Client`, a struct exposed by the melprot Rust crate that implements Mel's P2P protocol. `melprot::Client` is a light client that can be used to query full nodes for information about blockchain contents.

But unlike a raw RPC client (which does exist as `melprot::NodeRpcClient`), `melprot::Client` internally validates Merkle-tree proofs and staker signatures so that it *avoids trusting any full node*. Everything that `melprot::Client` returns is backed by the decentralized, incentive-based trust of the Mel blockchain, and nothing can be faked by a malicious node or RPC network.

## Basic data model

```
a picture of the whole data model, looking roughly like:

[snapshot]  ... [snapshot]
     |
 [map]  [map] ...
```

### Snapshots

The data model of `melprot::Client` is largely focused on the **state snapshot**, which is an immutable, trustless view of *the state of the blockchain at a given height*. For instance, the following code obtains snapshots of the state at different heights, and queries how many unspent coins a particular address owns at the two heights.

```rust
// get a mainnet Client
let client = melprot::Client::autoconnect(NetID::Mainnet);
// get the current snapshot
let snap_current = client.latest_snapshot().await?;
// get the snapshot at block height 10000
let snap_10000 = client.snapshot(BlockHeight(10000)).await?;
// display how many UTXOs are labeled with foobar_address now vs at block 10000
println!("address {} has {} UTXOs now but {} UTXOs at block 10000",
   foobar_address,
   snap_current.coin_count(foobar_address).await?,
   snap_10000.coin_count(foobar_address).await?
);
```

### Looking up info

Within a snapshot at a given height, there are many mappings associated with the state of the blockchain at that given height and a variety of methods for conveniently looking them up. Some of the most important ones include:

* `get_coin(id: CoinID)`: given the ID (transaction hash and index) of a particular coin, return the coin data.
* `get_transaction(txhash: TxHash)`: given a transaction hash, return the `Transaction` if it exists.

### Moving a snapshot back in time

Since snapshots commit to the state of a blockchain at a particular height — which includes the previous history — they can be used to verify older claims about blockchain contents but not later claims. This is represented in `melprot` by `Snapshot::get_older(height: BlockHeight)`, which can move snapshots backwards in time, but not forwards:

```rust
// get a snapshot at block height 100
let snap_100 = client.snapshot(BlockHeight(100)).await?;
// get a snapshot at block height 50
let snap_50 = snap_100.get_older(BlockHeight(50)).await?;
// this fails:
let snap_200 = snap_100.get_older(BlockHeight(200)).await?;
```

## Coin graph traversal

A very common task for light clients is traversing the **coin graph** of the blockchain, which is the global directed graph of all transactions spending and creating coins. For instance, this is a fragment of the coin graph centered around [a particular mainnet transaction in block 1901450](https://scan.themelio.org/blocks/1901450/674735b7b7e4163f7404715bd6b8433a8db523c52279ad07e2b4e88a6708d873):

<figure><img src="/files/5WSRh2BQ4SzV1DuGaQPj" alt=""><figcaption></figcaption></figure>

Given a known starting point — a particular transaction with a known location on the blockchain — the basic snapshot model detailed above allows easy traversal:

* **Moving backwards in time**: looking up the `CoinID` of a transaction input in a snapshot *older* than the transaction itself retrieves a `CoinDataHeight` that contains the height in which the transaction input was committed to the blockchain. This gets you the location of a "parent" transaction.
* **Moving forwards in time**: to look up when an output is spent, a binary search can be done between the state in which the transaction was committed and the present, to see the exact block height at which the output was spent. Then, a snapshot at that height can be used to retrieve the "child" transaction that spent the output.

It's certainly possible to manually implement the above, but `melprot` provides to very convenient methods `Client::traverse_back` and `Client::traverse_fwd`. These functions take in a "starting" transaction (block height and transaction hash), as well as a closure to specify *which* parent or child coin to follow to the next link, and return a `Stream` of `Transaction`s:

```rust
let client = melprot::Client::autoconnect(NetID::Mainnet);

let traversal = client.traverse_back(
   BlockHeight(1901450),
   "674735b7b7e4163f7404715bd6b8433a8db523c52279ad07e2b4e88a6708d873".parse()?,
   |tx| {
      // find the first input
      tx.outputs.get(0)
   }
).boxed();

while let Some(next) = traversal.next().await? {
   println!("transaction found: {:?}", next);
}
```

The above example will, starting from the [transaction mentioned previously](https://scan.themelio.org/blocks/1901450/674735b7b7e4163f7404715bd6b8433a8db523c52279ad07e2b4e88a6708d873), traverse its ancestry through the first input until it hits a transaction with no inputs (the first ever transaction in the blockchain!). Graphically, it essentially does this:

<figure><img src="/files/4KR03J3XdGgQwIRzpCjO" alt=""><figcaption><p>Clicking on the first parent indefinitely</p></figcaption></figure>


# Design

## Overall design process

Designing a off-chain composable, Mel-backed protocol is roughly a three-step process:

1. **What needs to be on the blockchain?** In the mature off-chain composability ecosystem of the future, most of the time you don't need to put anything on the blockchain yourself. For example, given an anonymous communication network and a secure naming system, an I2P-like anonymous web hosting platform can be built by combining the two protocols. But for the low-level primitives we need to build right now (like Gibbername), generally something needs to be on-chain.
2. **How to encode the on-chain info in a&#x20;*****light-client legible*****&#x20;fashion?** We need to then figure out how to encode the on-chain info in the on-chain coin graph in a way that, given the `melprot` data model, can easily and trustlessly be queried by off-chain programs.
3. **How to uphold invariants in the on-chain data?** Often, we need to force the on-chain data to be of a certain shape in order for our encoding to work. This generally requires either writing Melodeon covenants or exploiting some trick of Mel's coin model.

Let's follow this process for Gibbername!

## Designing Gibbername

### What needs to be on the blockchain?

We don't have any sort of off-chain decentralized key-value store available. So we need to encode the whole contents of the naming system on-chain.

More specifically, for every gibbername, we need to somehow store an on-chain blob of data. Since the blockchain is immutable, we really want to store the *history* of a particular gibbername on-chain. Anybody can then look up this history to get the data bound to a gibbername.

### How to encode the on-chain info?

There is a standard technique for encoding append-only histories in a coin graph: a **Catena chain**. A Catena chain is simply a chain of transactions, each one spending a particular output coin (say, the first) of the previous one. Metadata on the coins or transactions then encodes the append-only log, and the transaction hash of the first element uniquely identifies the whole chain.

<figure><img src="/files/jS4k3MAW1OiqnQNXW5UF" alt=""><figcaption><p>The Catena chain after <code>register</code> and <code>transfer</code> operations</p></figcaption></figure>

In our case, we can use the `CoinData::additional_data` field of the coins within a Catena chain to record the binding history of a gibbername. The gibbername itself (like `hehheh-hehheh`) would be some form of encoding of the *location of the first link in the chain*.

{% hint style="info" %}
We will discuss *how* the "gibbername encoding" that maps a gibbername to a unique blockchain location works in the [implementation section](/developer-guides/gibbername/implement#the-gibbername-encoding).
{% endhint %}

Now, light clients are able to do the core Gibbername features:

* **Lookup**: The latest, unspent entry in the chain will contain the latest piece of data bound to that gibbername.
* **Bind**: To bind the name to a different piece of data, a new item can simply be added at the end of the Catena chain.
* **Transfer**: Whoever can spend the last item of the Catena chain "owns" the name and has exclusive access to rebind the name or transfer it to a different owner. Rebindings are just a special kind of transfer that repeats the same address as the last binding. (The "permission" is specified in the covenant hash, or "address", embedded in the last coin)

### How to uphold invariants?

How do we ensure that the owner of a Gibbername actually continues the Catena chain? We *could* just define the Catena chain as always continuing from the first output and place no constraints at all — this will give us a canonical interpretation of *any* transaction as a gibbername and its subsequent first child, first grandchild, etc as a Gibbername binding history.

But this has several disadvantages:

* It doesn't mark Gibbername activity out in the blockchain, making it easy to mistake other transactions as gibbernames
* Using any regular chain of coins makes it very easy to accidentally rebind or transfer a gibbername. Wallet software would not be able to distinguish Gibbername coins from regular $MEL coins, and would accidentally spend the first and mess up the binding without a lot of manual intervention.

Instead, we use **special transaction metadata** **custom token denomination** to mark Catena chains used by Gibbername. In particular: the *first* transaction in a Gibbername Catena chain must:

* Have the `Transaction::data` field set to `"gibbername-v1"`
* Have *one of its outputs* have denomination `Denom::NewCustom` and value `1`.

Subsequently, the canonical Catena chain is defined as the unique chain of coins that have denomination `Denom::Custom(<transaction hash of the first transaction>)`.

This exploits two nice features of Mel's transaction model:

* A coin with `Denom::NewCustom` creates a new, unique token denomination named after the hash of its parent transaction.
* A coin with value `1` can no longer be subdivided by spending transactions. There's thus always only going to be one unspent coin in the world with the right denomination, making a unique Catena chain.

Gibbername transactions are now very obvious (allowing, say, Melscan to offer a global Gibbername listing), and wallets will no longer accidentally spend Gibbername-related coins because they have their own denomination.


# Implement

In this page, we go over the details of actually implementing a Gibbername library in Rust.

:man\_technologist: [**Follow along on GitHub!**](https://github.com/mel-project/gibbername)

{% hint style="info" %}
In the future, cross-language `melprot` bindings will make it possible to implement protocol libraries in other languages, including in-browser JavaScript!

For now, though, Rust is the only supported language.
{% endhint %}

## Project setup

The first step of implementing Gibbername is to create a new Rust library with the `melprot` dependency:

```shell-session
cargo new --lib gibbername
cd gibbername
```

We'll also be adding some dependencies. These will show up in the `Cargo.toml`:

```shell-session
cargo add futures-util anyhow gibbercode hex melprot melstructs stdcode tmelcrypt
```

## Looking up names

The easiest part of Gibbername is looking up the names. This consists of three parts:

* **Decoding the Gibbername** into a *blockchain location* identifying the start of the Catena chain. This means a block height and a transaction hash.
* **Obtaining and validating the start transaction** by obtaining a snapshot at the given block height, retrieving the start transaction, and making sure that its `data` field says `"gibbername-v1"`.
* **Traversing the Catena chain**, following all the custom-token coins, traverse the Catena chain to the most recent element. We'll then have our binding!

### The Gibbername encoding

How can we squeeze a blockchain location — which identifies a transaction and its location — into a short "gibberish string" like `xoxqax-lobteh`? After all, unique transaction hashes are very long and unwieldy.

Instead, we encode a unique blockchain location as two numbers: the *block height* and the *transaction position*. This position is the 0-indexed position of the transaction within all the transactions in that block sorted by hash.

This lets us represent any transaction in the blockchain uniquely with two smallish numbers. For instance, the transaction with the "smallest" hash in block `100000` would be represented as `100000,0`.

We then need to represent this pair of numbers as a friendly Gibbername. Fortunately, we can use `gibbercode`, a crate that encodes a pair of numbers into a gibberish string using the consonants for the first number and the vowels for the second.

{% code overflow="wrap" lineNumbers="true" %}

```rust
use melstructs::{Address, BlockHeight, CoinData, CoinValue, Denom, Transaction, TxHash};

/// Decodes a gibbername into a blockchain location.
fn decode_gibbername(gname: &str) -> anyhow::Result<(BlockHeight, u32)> {
    let (height, index) = gibbercode::decode(gname);
    Ok((BlockHeight(height as u64), index as u32))
}

/// Encodes the given height and index into a gibbername.
fn encode_gibbername(height: BlockHeight, index: u32) -> anyhow::Result<String> {
    Ok(gibbercode::encode(
        u128::try_from(height.0)?,
        u128::try_from(index)?,
    ))
}
```

{% endcode %}

### Validating the start transaction

Once we have the blockchain location, we need to retrieve the start transaction. This can be done using `melprot`'s `Snapshot::get_transaction_by_posn()` function.

The start transaction should have a `data` field that says `"gibbername-v1"`, as well as one, and just one, output with denomination `Denom::NewCustom`, and that output must have value `1`. This is the way we ensure that a given Gibbername is actually valid.

{% code overflow="wrap" lineNumbers="true" %}

```rust
/// Gets and validates the starting transaction of the gibbername chain.
/// Validation involves checking the transaction for the following properties:
/// 1. The `data` field says "gibbername-v1"
/// 2. The transaction has a single output with the [themelio_structs::Denom::NewCoin] denomination
///    with a value of 1
async fn get_and_validate_start_tx(
    client: &melprot::Client,
    gibbername: &str,
) -> anyhow::Result<(BlockHeight, TxHash)> {
    let (height, index) = decode_gibbername(gibbername).expect("failed to decode {gibbername}");
    let snapshot = client.snapshot(height).await?;
    let txhash = snapshot.get_transaction_by_posn(index as usize).await?;

    // validate the transaction now
    if let Some(txhash) = txhash {
        let tx = snapshot
            .get_transaction(txhash)
            .await?
            .expect("expected transaction to exist, because txhash exists");

        // check the data
        if &tx.data[..] != b"gibbername-v1" {
            anyhow::bail!("invalid data in the start transaction: {:?}", tx.data);
        }

        let new_outputs = tx
            .outputs
            .iter()
            .filter(|output| output.denom == Denom::NewCustom)
            .collect::<Vec<&CoinData>>();
        if new_outputs.len() == 1 && new_outputs[0].value == CoinValue(1) {
            Ok((height, tx.hash_nosigs()))
        } else {
            anyhow::bail!("invalid start transaction outputs");
        }
    } else {
        anyhow::bail!("could not find starting transaction for the given gibbername: {gibbername}");
    }
}
```

{% endcode %}

### Traversing the Catena chain

Finally, we can traverse the Catena chain to get the coin containing the final binding:

{% code overflow="wrap" lineNumbers="true" %}

```rust
use anyhow::Context;
use futures_util::StreamExt;

async fn traverse_catena_chain(
    client: &melprot::Client,
    start_height: BlockHeight,
    start_txhash: TxHash,
) -> anyhow::Result<CoinData> {

    // First, we get a collection of transactions from our starting height and txhash.
    // We also include a closure that tells us to look for the transaction output that follow our Gibbername rules (a Denom that's either Custom(<start_txhash>) or NewCustom)
    let traversal = client
        .traverse_fwd(start_height, start_txhash, move |tx: &Transaction| {
            tx.outputs.iter().position(|coin_data| {
                (tx.hash_nosigs() == start_txhash && coin_data.denom == Denom::NewCustom)
                    || coin_data.denom == Denom::Custom(start_txhash)
            })
        })
        .expect("failed to traverse forward")
        .collect::<Vec<Transaction>>()
        .await;

    // If the traversal is empty, it means either:
    // 1. The current height and txhash represent the end of the traversal
    // 2. We couldn't find anything for the given height and txhash
    if traversal.is_empty() {
        let snap = client.snapshot(start_height).await?;
        let tx = snap
            .get_transaction(start_txhash)
            .await?
            .context("No transaction with given hash")?;
        let coin = tx
            .outputs
            .iter()
            .find(|coin| coin.denom == Denom::NewCustom);

        match coin {
            Some(coin_data) => return Ok(coin_data.clone()),
            None => anyhow::bail!("No valid gibbercoins found"),
        }
    }

    // Return the last coin in the traversal if it exists
    let last_tx = traversal.last().expect("the traversal is empty");
    if let Some(last_tx_coin) = last_tx
        .outputs
        .iter()
        .find(|coin_data| coin_data.denom == Denom::Custom(start_txhash))
    {
        Ok(last_tx_coin.clone())
    } else {
        anyhow::bail!("the name was permanently deleted");
    }
}

```

{% endcode %}

We can now easily build the gibbername lookup function!

{% code overflow="wrap" lineNumbers="true" %}

```rust
/// Returns the data bound to the given gibbername if there is any.
pub async fn lookup(client: &melprot::Client, gibbername: &str) -> anyhow::Result<String> {
    let (start_height, start_txhash) = get_and_validate_start_tx(client, gibbername).await?;
    let last_coin = traverse_catena_chain(client, start_height, start_txhash).await?;
    let binding = String::from_utf8_lossy(&last_coin.additional_data);

    Ok(binding.into_owned())
}
```

{% endcode %}

## Registering names

Registering names is a little different: we need to *send* a transaction into the blockchain rather than just reading existing data.

One possible way is to craft a transaction inside our library and send it by directly calling an RPC method on a full node (through something like `melprot::Client::raw_rpc()`). But this is hard, because we must somehow get hold of $MEL to pay transaction fees (possibly by asking the user to send money to some address?). Furthermore, even once we have $MEL, managing the money and the private keys securing it difficult, security-critical task.

Instead, we **ask the user's wallet to send a transaction for us**, and we simply wait until the user finishes doing so. In summary, here are the steps to register a new gibbername:

### Prompt and wait for the transaction

We can now write a function to send the transaction and wait for it to commit in the blockchain.

{% code overflow="wrap" lineNumbers="true" %}

```rust
pub async fn register(
    client: &melprot::Client,
    address: Address,
    initial_binding: &str,
    wallet_name: &str,
) -> anyhow::Result<String> {
    let height = client.latest_snapshot().await?.current_header().height;
    let cmd = register_name_cmd(wallet_name, address, initial_binding)?;
    println!("Send this command with your wallet: {}", cmd);

    // scan through all transactions involving this address, starting at the block height right before we asked the user to send the transacton
    let mut stream = client.stream_transactions_from(height, address).boxed();
    while let Some((transaction, height)) = stream.next().await {
        if &transaction.data[..] == b"gibbername-v1" {
            let txhash = transaction.hash_nosigs();
            let (posn, _) = client
                .snapshot(height)
                .await?
                .current_block()
                .await?
                .abbreviate()
                .txhashes
                .iter()
                .enumerate()
                .find(|(_, hash)| **hash == txhash)
                .expect("No transaction with matching hash in this block.");

            let gibbername = encode_gibbername(height, posn as u32)?;
            return Ok(gibbername);
        }
    }
    unreachable!()
}
```

{% endcode %}

```rust
// A small helper function to create the wallet command for registering a name.
fn register_name_cmd(
    wallet_path: &str,
    address: Address,
    initial_binding: &str,
) -> anyhow::Result<String> {
    let cmd = format!(
        "melwallet-cli --wallet-path {} send --to {},{},{},\"{}\" --hex-data {}",
        wallet_path,
        address,
        0.000001,
        "\"(NEWCUSTOM)\"",
        hex::encode(initial_binding),
        hex::encode("gibbername-v1")
    );

    Ok(cmd)
}
```

When this function is called, the user will be prompted to manually send a transaction with our wallet CLI: `melwallet-cli`. We will continuously stream incoming transactions until we find the one we sent. We are now able to register a name with an arbitrary binding! :rocket:

## Transferring names

Transferring names is left as an exercise to the reader.

{% hint style="info" %}
**Hint**: you'll need to construct a wallet to extend the Catena chain and prompt the user, just like with registration. If you're truly stuck, there's always [our GitHub example](https://github.com/mel-project/gibbername) code :smile:
{% endhint %}


# Use

Now that we've finished writing our `gibbername` crate, we'll demonstrate actually using it in a project. We will build `gibbername-cli`, a trivial wrapper around the library that lets you look up and register names on the command line. Using it willl look something like

```shell-session
gibbername-cli lookup tofnal-seh
hello world my dudes this is what's bound to the name lol
```

You can find a complete example in our [GitHub repo](https://github.com/mel-project/gibbername-cli).

## Project setup

Let's start by creating a new binary crate:

```shell
cargo new gibbername-cli
cd gibbername-cli
```

We add `melprot`, `melstructs`, `anyhow` for error handling,`argh` for lightweight argument parsing, and `futures-lite` for bare-bones async support:

```toml
cargo add melprot melstructs anyhow argh futures-lite
```

We also need to add a dependency on Gibbername itself. This will be a "path" dependency to wherever, locally, you put the Gibbername crate:

```toml
[dependencies]
anyhow = "1.0.69"
argh = "0.1.10"
futures-lite = "1.12.0"
gibbername = { path = "../gibbername" }
melprot = "0.13.3"
melstructs = "0.3.2"
```

## Writing the main function

We write a basic scaffold that parses the arguments with `argh`:

```rust
se argh::FromArgs;
use futures_lite::future::block_on;
use melstructs::{Address, NetID};

#[derive(FromArgs, PartialEq, Debug)]
/// Look up a name in the Gibbername registry.
struct Cli {
    #[argh(option, description = "either 'mainnet' or 'testnet'")]
    network: NetID,
    #[argh(subcommand)]
    command: Command,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum Command {
    Lookup(Lookup),
    Register(Register),
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "lookup")]
/// Lookup what is bound to a name
struct Lookup {
    #[argh(positional)]
    name: String,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "register")]
/// Register a name
struct Register {
    #[argh(option, description = "mel address of the gibbername owner")]
    owner: Address,

    #[argh(option, description = "data to be bound to the gibbername")]
    binding: String,

    #[argh(option, description = "path to the wallet sending the transaction")]
    wallet_path: String,
}

fn main() -> anyhow::Result<()> {
    env_logger::init();
    let args: Cli = argh::from_env();
    // keep around a client
    let client = block_on(melprot::Client::autoconnect(args.network))?;
    match args.command.as_ref() {
        Command::Lookup(lookup) => {
            todo!()
        }
        Command::Register(register) => {
            todo!()
        }
    };
    Ok(())
}
```

## Filling in the functionality

Now that we have a basic scaffold, filling in the functionality is incredibly easy:

```rust
use futures_lite::future::block_on;

fn main() -> anyhow::Result<()> {
    let args: Cli = argh::from_env();
    // keep around a client
    let client = block_on(
        melprot::Client::autoconnect(NetID::Testnet)
    )?;

    match args.command {
        Command::Lookup(lookup) => {
            // we don't need a futures runtime, block_on is fine
            let gname = block_on(gibbername::lookup(&client, &lookup.name))?;
            println!("{gname}");
        }
        Command::Register(register) => {
            // gibbername will prompt the user
            let name = block_on(gibbername::register(&client, register.owner, &register.binding, &register.wallet_name))?;
            println!("registered {:?}", name);
        }
    };
    Ok(())
}
```

## Testing

We now have a complete program! We can test run it with `cargo run`:

<pre class="language-shell-session"><code class="lang-shell-session"><strong>cargo run -- --network mainnet register --owner x7v9tegt6b99xv9t6e56kabap3ych5htw83wa69z0shwa7ms3xbkn7 --binding "hello world" --wallet-path ./alice.json
</strong>Send this command with your wallet: melwallet-cli --wallet-path ./alice.json send --to x7v9tegt6b99xv9t6e56kabap3ych5htw83wa69z0shwa7ms3xbkn7,0.000001,"(NEWCUSTOM)","68656c6c6f20776f726c64" --hex-data 6769626265726e616d652d7631
</code></pre>

Now, run the `melwallet-cli` command which will register our gibbername:

<pre><code><strong>melwallet-cli --wallet-path ./alice.json send --to x7v9tegt6b99xv9t6e56kabap3ych5htw83wa69z0shwa7ms3xbkn7,0.000001,"(NEWCUSTOM)","68656c6c6f20776f726c64" --hex-data 6769626265726e616d652d7631
</strong>registered "segnet-tes"
</code></pre>

Finally, we can look up the binding we set in our `register` command using `lookup`:

<pre><code><strong>cargo run -- --network mainnet lookup segnet-tes
</strong>hello world
</code></pre>


# Next steps

## What did we just do?

We just finished building **Gibbername**, a simple on-chain naming system. We built a library and simple command-line tool that lets you register, transfer, and look up "gibbernames" like `goltor-rulnuq-keh` from any Rust program.

Most importantly, this whole process is entirely trustless! A malicious RPC network or full node is unable to lie to a Gibbername client at all.

Hopefully, you also got a taste of how different Mel's off-chain composability is from the current Web3 paradigm. Instead of writing a smart contract with an on-chain API that other on-chain code calls, you designed an on-chain data structure that *off-chain* code maintains and looks up. This then enables you to write apps that integrate Gibbername's decentralized security without writing a single line of on-chain smart contract code (something that you can't really do with ENS and the like!)

## Possible improvements

Gibbername, as it is, is close to the simplest possible useful protocol we can build on Mel. An actual, production naming system that could compete with DNS and the like would need a few more features. Here we sketch how they can be implemented:

### Off-chain data storage

Right now, the entire binding is stored on the Mel blockchain. This is not all that efficient, since blockchain space is pretty expensive. Furthermore, it can be slow to follow the very long Catena chains that would result from a name that has been rebound many different times.

We can move more data off-chain to solve both problems:

* On-chain, we bind to the *hash* of the binding rather than the binding itself.
* Off-chain, we use an insecure decentralized key-value mapping, like a DHT, to map each gibbername to a *proof of on-chain binding*, consisting of three items:
  * The initial on-chain transaction, as well as a Merkle *proof of inclusion* that the blockchain location represented by the gibbername truly maps to this transaction
  * The *last* on-chain transaction in the Catena chain, along with a proof that the `Denom::Custom(...)` output is unspent.
    * We do not need any transactions in between, since there could not possibly be another unspent output with the same Denom, since there's only 1 in total produced by the first transaction.
  * The contents of the binding itself, which must hash to the on-chain binding in the output of the last on-chain transaction.

In such a system, lookups can *entirely be done off-chain* and massively scale. Bindings can also be arbitrarily large without burdening the blockchain.

### Human-readable names

Instead of using blockchain locations as the name, we can use an on-chain data structure to keep track of human-readable names. This data structure will be a certain "shape" in the coin graph, just like a Catena chain, but encoding a key-value graph instead (e.g. [Bitforest](https://rboutaba.cs.uwaterloo.ca/Papers/Conferences/2018/DongCNSM18.pdf)). Upholding this invariant would require writing a Melodeon covenant.

### Better registration UX

Once we have mature GUI wallets with "wallet URI" support, as well as immutable frontend hosting, we will be able to write a simple webpage where people can manage their gibbername names.


# Wallets

Learn about Mel wallets and how to get started using them.

A wallet is a fundamental tool in the Mel ecosystem. It allows users to buy, sell, store, and swap tokens.


# Setup and installation

A short guide on how to set up and install our wallet CLI.

## Prerequisites

* A working internet connection
* The latest Rust toolkit, including the `cargo` command

## Install melwallet-cli

```shell-session
cargo install --locked melwallet-cli
```


# Sending money

A simple tutorial on how to set up and interact with Mel wallets.

This is a basic guide to `melwallet-cli`, Mel's reference implementation CLI wallet. We will be funding two testnet wallets and sending money from one to the other.

## Setup and installation

Make sure you have the wallet installed. If not, follow [this](#setup-and-installation) short guide.

## Create wallets for Alice and Bob

In a terminal, create two *testnet* wallets at your selected path:

```shell-session
melwallet-cli --wallet-path ./alice.json create --network testnet
melwallet-cli --wallet-path ./bob.json create --network testnet
```

{% hint style="info" %}
The wallets with their secrets are stored as *unencrypted* json documents on disk. Users and applications should take care to encrypt as needed.
{% endhint %}

## Fund Alice's wallet <a href="#fund-wallet" id="fund-wallet"></a>

Let's use the faucet to print testnet MEL to fund our new testnet wallets. This command sends 1000 MEL to wallet `alice` and waits until the transaction is confirmed:

```shell-session
melwallet-cli --wallet-path ./alice.json send-faucet --wait
```

## Send some money to Bob <a href="#send-funds" id="send-funds"></a>

Now, we transfer some MEL from alice to bob. First, obtain bob's address using

```shell-session
melwallet-cli --wallet-path ./bob.json summary
```

You should get output similar to

```
Network:  testnet
Address:  t7v9tegt6bm6dv9t6e56ktdap3ych5htw83wa69z0shwa7nt3xbkn0
Balances:
```

Send the money to bob:

```shell-session
melwallet-cli --wallet-path ./alice.json send --to <BOB_ADDRESS>,500.0 --wait
```

This command sends `500.0` MEL from alice to bob and waits for the transaction to confirm. When it returns, you have successfully sent MEL to bob!

## Further reading

Sending a transaction is just one of the many things you can do with `melwallet-cli`. For more information, check it out on [GitHub](https://github.com/mel-project/melwallet-client).


# Swapping tokens

A guide on swapping tokens on Mel.

## Prerequisites

In [the last section](/developer-guides/using-wallets/getting-started) we sent wallet `bob` some MEL. In this section we'll use wallet `bob` to swap some tokens. Make sure you have access to at least 500 MEL.

{% hint style="info" %}
Fees, exchange rates, and other numbers in this guide are **entirely fictional**!
{% endhint %}

To see how much MEL `bob` has:

<pre class="language-shell-session"><code class="lang-shell-session"><strong>melwallet-cli --wallet-path ./bob.json summary
</strong>
Network:  testnet
Address:  t7v9tegt6bm6dv9t6e56ktdap3ych5htw83wa69z0shwa7nt3xbkn0
Balances:
500.00000 MEL
</code></pre>

## Swapping tokens <a href="#swapping-coins" id="swapping-coins"></a>

Unlike other blockchains where this functionality typically exists in a programmable smart contract, Mel features a built-in, Uniswap-like decentralized exchange (DEX) called **Melswap**.

{% hint style="info" %}
We embedded a rudimentary DEX into the L1 not primarily for convenience, but as a trustless price oracle for designing on-chain logic; it is also an important component of the Melmint algorithm that stabilizes MEL.
{% endhint %}

With Melswap, any user can instantly swap one token for another for a fixed pool fee of 0.5%. Using `melwallet-cli`, we swap 100 MEL for some SYM at the market rate:

<pre class="language-shell-session"><code class="lang-shell-session"><strong>melwallet-cli --wallet-path ./bob.json swap --value 100.0 --from MEL --to SYM --wait
</strong>
SWAPPING
From:  100.000000 MEL
To:    50.000000  SYM  (approximate)
Fee:     0.000000 MEL
Proceed? [y/N] y

..................

Transaction 3717d9d6a93f2e5c4c420745dccbb72d9ed109285362f6a45785e6f73cd8ef58 confirmed!
</code></pre>

<pre class="language-shell-session"><code class="lang-shell-session"><strong>melwallet-cli --wallet-path ./bob.json summary
</strong>
Network:  testnet
Address:  t7v9tegt6bm6dv9t6e56ktdap3ych5htw83wa69z0shwa7nt3xbkn0
Balances:
400.00000 MEL
100.00000 SYM
</code></pre>

### Pools

In the above trade, we interacted with a **liquidity pool**: a collections of two kinds of assets, in this case MEL and SYM, deposited on-chain. Liquidity pools provide constant-product DEXes, like Melswap, with always-available buyers and sellers, via an exchange rate that automatically adjusts to satisfy any trade without running out of assets in the pool.

{% hint style="info" %}
Constant-product swapping pools are most notably implemented by Uniswap, and the [Uniswap v2 documentation](https://docs.uniswap.org/contracts/v2/concepts/protocol-overview/how-uniswap-works) remains the best guide to understanding them further.
{% endhint %}

To see the current exchange rate and liquidity of any given pool:

<pre class="language-shell-session"><code class="lang-shell-session"><strong>melwallet-cli --wallet-path ./bob.json pool MEL/SYM
</strong>
1 MEL  = 0.5000000000000000 SYM
1 SYM  = 2.0000000000000000 MEL
</code></pre>

{% hint style="warning" %}
A constant-product pool like Melswap works to ensure all trades can be satisfied. This means that trades without sufficient liquidity available may receive **extremely** bad prices.
{% endhint %}

### Providing liquidity

Where does all the liquidity sitting in the pool come from? Melswap incentivizes users to add liquidity to pools by depositing tokens in the pool in exchange for **liquidity tokens**. Liquidity tokens are unique in that they reflect an ownership of a proportion of the entire pool, instead of an individual token. Let's deposit a total value of 100 MEL in liquidity into the MEL/SYM pool:

<pre class="language-shell-session" data-overflow="wrap"><code class="lang-shell-session"><strong>melwallet-cli --wallet-path ./bob.json liq-deposit 0.0 SYM 100.0 MEL --wait
</strong>
Proceed? [y/N] y
..................
Transaction 19b882d37f66cce058dea501c2acffe1cdac8b00e7424e27ad92c864f27ba56d confirmed!
</code></pre>

`bob` now has 1 liquidity token for the MEL/SYM pool, called `CUSTOM-526bd177e93a854e08216aff6b48cf7f3ae7b4cbd202fdfde39271d1ad90a3bd`.

<pre class="language-shell-session"><code class="lang-shell-session"><strong>melwallet-cli --wallet-path ./bob.json summary
</strong>
Network:      testnet
Address:      t11n9ynz8jhcd1k7h6jx4pvsc4m2qvwjhdp5mx03ega05hkcts8j9g
Balance:      349.50000   MEL
              25.000000   SYM
              1.0000000   CUSTOM-526bd177e93a854e08216aff6b48cf7f3ae7b4cbd202fdfde39271d1ad90a3bd
Staked:       0.000000    SYM
</code></pre>


# Getting tokens

How to acquire Mel-native tokens.

Acquiring **"mainnet"** tokens:

* Run a [`melminter`](/developer-guides/getting-tokens/using-melminter) instance - this rewards you with ERG, which can be immediately swapped for other tokens in the liquidity pools (e.g. MEL, SYM)
* If you already have some MEL, SYM, or ERG, you can swap them for other tokens using [Melswap](/developer-guides/using-wallets/melswap-guide)

Acquiring **testnet** tokens: use the [faucet functionality](/developer-guides/using-wallets/getting-started#fund-wallet).

{% hint style="danger" %}
Our native tokens are currently **not** listed on any exchange yet. Be aware of possible scams!
{% endhint %}


# Melmint overview

This is a brief, high-level introduction to Melmint.

{% hint style="info" %}
The wiki has a [more in-depth discussion of MEL and Melmint](/concepts/melmint).
{% endhint %}

## Introduction

Melmint is the our key mechanism for stabilizing MEL, Mel's base currency. MEL avoids the volatile price of traditional cryptocurrencies like BTC and ETH, making it a much better store of value and unit of account.

But, unlike "stablecoins", MEL does not rely on any external trust in fiat assets or oracles. Instead, Melmint is an oracle-free system that keeps the value of 1 MEL around **1 DOSC**.

### **What is a DOSC?**

A “DOSC” is a “day of sequential computation”. It’s defined as the *cost of running a sequential computation for 24 hours, using the fastest processor available*.

For example, a DOSC in the year 2000 is the cost of occupying the fastest single CPU core *available in 2000* for 24 hours, while a DOSC in the year 2021 is the cost of doing the same with a 2021 processor.

### What makes DOSC a good peg target?

* It has a relatively stable purchasing power. Empirically, the “fastest processor” typically costs about the same, despite its performance drastically increasing over time. We explore this further in our [DOSC analysis data](https://github.com/Mellabs/dosc-analysis). There are also deeper *a priori* reasons why [processor time is a good long-term measure of value](https://forum.mel.org/t/some-thoughts-on-melmint-stability/29).
* More importantly, it can be measured through a sequential proof-of-work on-chain by an autonomous mechanism with full endogenous trust. No oracle needs to be trusted to tell us how much a DOSC is.

## Participating in Melmint

### Contribute CPU measurements

To participate in Melmint, you can [run your own](/developer-guides/getting-tokens/using-melminter) instance of `melminter`, a convenient CLI that turns CPU computation into MEL.

Though it turns computation into money, `melminter` is **not** a "miner" and does not help secure the network. Instead, it *bids* for MEL \_\_ using \_computation\_, contributing information about the current price of computation to the network. This then drives the Melmint mechanism to keep the 1 MEL = 1 DOSC peg.

### Make arbitrage trades

Melmint's stability depends on a community of traders profiting from arbitrage between the MEL/SYM, ERG/SYM, and ERG/MEL Melswap pools. Learn more in the [article on Melmint arbitrage](/developer-guides/getting-tokens/melmint-arbitrage)!

## Further Reading

This was just a quick overview of Melmint. The complete guide on how MEL is stabilized, along with what happens under the hood, can be found [here](/concepts/melmint) in the conceptual documentation.


# Using melminter

This page shows how to participate in Melmint with the melminter CLI.

## Installation and Setup

Ensure that you have an up-to-date version of `melminter` installed:

```shell-session
cargo install --locked melminter
```

You will need:

* A small amount of MEL in your wallet (see setup instructions [here](/developer-guides/using-wallets/getting-started)). This is because Melmint transactions are required to pay transaction fees, just like every other transaction.

{% hint style="info" %}
If you simply want to try this out on the testnet, you can acquire testnet MEL yourself via a faucet transaction, as shown [here](/developer-guides/using-wallets/getting-started#fund-wallet).

If you wish to participate in mainnet melminting, please ask for some MEL in the #mel channel of our [Discord server](https://discord.com/invite/qfg35paESn).
{% endhint %}

## Running melminter

```shell-session
melminter --payout <payout-wallet-address>
```

The first time you run `melminter`, it will ask you to send a particular address a small amount of MEL in order to start. This is so that it can pay initial transaction fees. Send that money, and after around 30 seconds you'll see a nice TUI show up:

<figure><img src="/files/tb8IpzbhS6PGzKsQ2f78" alt=""><figcaption></figcaption></figure>

Running `melminter` will generate ERG, a temporary token representing computation, and immediately exchange it for MEL. Note the *daily return* line in the terminal output, which predicts how much computational work (in DOSC) the minter will do in 24 hours, as well as how much MEL that will buy.

## Caveats

Bidding for MEL with computation is not always profitable. Because of the mechanics of Melmint, **minting is very unlikely to be profitable** unless you either have a top-of-the-line CPU and cheap electricity, or Melmint is off-peg. This is because Melmint is not a proof-of-work consensus system, but rather a *pegging arbitrage* system that is only really used to restore the MEL/DOSC .

Transient volatility in the MEL/ERG exchange rate may also affect profitability.

`melminter` makes no attempt at guessing whether or not minting is profitable.


# Melmint arbitrage

How to use melminter to (hopefully) profit via arbitrage.

## What is arbitrage?

Arbitrage is:

> The buying and selling of some asset (e.g. currency, securities, commodities, etc) in different markets to take advantage of differing prices for the same asset

In our case, we have multiple "markets", or liquidity pools, that contain asset pairs, such as MEL/SYM or MEL/ERG, and SYM/ERG. The Melmint mechanism [maintains the MEL/SYM pair](/concepts/melmint), but does not interact with the other asset pairs.

In order to maintain the other pairs, we'll need YOU to do arbitrage and hopefully make some money.

<img src="/files/QiOybA0Uq8IG1JyqV9fS" alt="" data-size="original">

## Using melwallet CLI to arbitrage

### Prerequisites

You'll need a wallet containing funds. [Here](/developer-guides/using-wallets/getting-started) is a guide on how to set that up on the testnet.

### Time for some arbitrage :moneybag:

```shell-session
melwallet-cli --wallet-path <path to wallet> autoswap <value>  
```

Here, `<value>` is the amount of MEL that you want to automatically swap for arbitrage.

This command will automatically execute trades on the "triangular" MEL/SYM/ERG pairs.


# Run a full node

**Full nodes** replicate every consensus-confirmed block, validating their contents and ensuring network security while providing a local cache of the entire blockchain state. Running a full node helps contribute to the security and performance of the network.

**Melnode** is the reference implementation of a Mel full node. This guide will teach you how to run Melnode.


# Melnode quick start

In this section, you will learn how to use melnode, Mel's reference node implementation.

## Setup and Installation

### Hardware requirements

#### Minimum

* 1-core CPU
* 4 GB of RAM
* at least 200 GB of free storage (SSD not necessary)
* 10 Mbps download Internet service

#### Recommended

* 4+ core CPU
* 16 GB of RAM
* 200+ GB of free storage on a fast device (SSD, RAID array, etc)
* 50+ Mbps up/download Internet service

### Install Rust and Cargo

For security reasons, until we have reliable, reproducible build infrastructure, we stick to releasing source code and do not distribute any official binary packages.

Fortunately, Rust's package manager, Cargo, is *very* easy to use, likely easier than whichever package manager you are already accustomed to.

Follow the [instructions](https://doc.rust-lang.org/cargo/getting-started/installation.html) from the official Cargo Book to get started. Make sure that the `cargo` command is available and of the latest version:

<pre class="language-shell-session"><code class="lang-shell-session"><strong>cargo version
</strong>cargo 1.76.0 (c84b36747 2024-01-18)
</code></pre>

## Compile and install melnode

Simply run the following command:

```shell-session
cargo install --locked melnode
```

{% hint style="info" %}
Don't forget the `--locked` parameter! That ensures that all dependencies are locked to the specific version we specify, which can sometimes be important for correct functionality.
{% endhint %}

This should kick off a fairly long build process, but eventually you should see something like this, indicating that `melnode` has been installed successfully:

```shell-session
   Compiling Mel-bootstrap v0.6.1
   Compiling imbl v1.0.1
   Compiling lz4_flex v0.8.2
   Compiling arc-swap v1.5.1
   Compiling clone-macro v0.1.0
   Compiling jemallocator v0.3.2
   Compiling jemallocator-global v0.3.2
   Compiling rusqlite v0.26.3
   Compiling boringdb v0.4.1
   Compiling melnode v0.14.0
    Finished release [optimized] target(s) in 1m 29
```


# Basic replica node

Running a replica node with melnode.

**Replica nodes** simply validate and replicate blocks that the network has already produced. They are the most common type of full node, and running one does not require staking anything.

## On the mainnet

### Starting melnode

Running the `melnode` command without any arguments starts an instance running on the mainnet.

```shell-session
melnode
```

You will see output looking like this:

```shell-session
[2022-12-12T16:40:48Z INFO  melnode] melnode v0.13.2 initializing...
[2022-12-12T16:40:48Z DEBUG melnode::args] database opened at "/home/user/.melnode/"
[2022-12-12T16:40:48Z INFO  melnode::storage::storage] HIGHEST AT 0
[2022-12-12T16:40:48Z DEBUG melnode::args] node storage opened
[2022-12-12T16:40:48Z INFO  melnode] bootstrapping with [185.177.126.98:41814]
[2022-12-12T16:40:48Z DEBUG melnode::protocols::node] starting to listen at 0.0.0.0:41814
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 1 of length 215 in 1.08ms (insert 9.54ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 2 of length 215 in 0.51ms (insert 0.26ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 3 of length 215 in 0.43ms (insert 0.21ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 4 of length 215 in 0.45ms (insert 0.22ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 5 of length 215 in 0.43ms (insert 0.24ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 6 of length 215 in 0.44ms (insert 0.23ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 7 of length 215 in 0.44ms (insert 0.24ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 8 of length 215 in 0.46ms (insert 0.18ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 9 of length 215 in 0.46ms (insert 0.15ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 10 of length 215 in 0.46ms (insert 0.16ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 11 of length 215 in 0.46ms (insert 0.16ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 12 of length 215 in 0.44ms (insert 0.25ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 13 of length 215 in 0.46ms (insert 0.20ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 14 of length 215 in 0.64ms (insert 0.25ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 15 of length 215 in 0.46ms (insert 0.22ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 16 of length 215 in 0.47ms (insert 0.13ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 17 of length 215 in 0.48ms (insert 0.13ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 18 of length 215 in 0.47ms (insert 0.23ms)
[2022-12-12T16:40:48Z DEBUG melnode::storage::storage] applied block 19 of length 215 in 0.48ms (insert 0.13ms)
```

{% hint style="warning" %}
There is an optional flag `--index-coins` that is recommended. Certain coin-related RPCs will be disabled if this flag is not set. Do note that the indexer will take up extra memory.
{% endhint %}

It will take *quite* a long time to synchronize all the blocks from the network (usually 10+ hours as of April 2024).

### Participating in peering

{% hint style="warning" %}
To participate in peering, you must have a publicly reachable IP address. Most home internet setups do not give you a public IPv4 address!
{% endhint %}

By default, `melnode` doesn't do much other than downloading blocks. The default listening port is `localhost:41814`: since this is on localhost, no other computers can connect to the node.

To actually contribute to block propagation on the network, you need to expose `melnode` to other networks:

```shell-session
melnode --listen [::1]:41814 --advertise auto
```

We add two flags:

* `--listen [::1]:41814` listens on port 41814 on all network interfaces
* `--advertise auto` automatically guesses our public IP address for incoming connections on the P2P network

If this works, you should soon see output like:

```shell-session
[2022-12-12T16:40:48Z DEBUG melnode::network] incoming connection from 100.64.3.2!
```

indicating that you are helping other nodes connect to the network.

## On the testnet

### Basic functionality

To replicate testnet blocks, add `--network testnet` to any `melnode` command:

```shell-session
melnode --network testnet
```

### Faucets and staking

A distinct feature of the testnet is that **faucets** can be used to generate "free money", which can then be used to test consensus and staking (future feature).


# Setting up a local simnet

Learn how to run your own local "simnet" node.

## Prerequisites

Make sure you have the required hardware and dependencies installed. Follow this [guide](/developer-guides/run-a-full-node/melnode-quick-start) if you haven't already.

## Setting up a local simnet

For local development and testing, we can configure a local "simnet", or a fake network on our local computer.

The easiest way to do so is with our [`melsimnet`](https://github.com/mel-project/melnode/blob/master/src/bin/melsimnet.rs) binary. In the `melnode` directory:

```shell-session
cargo run --bin melsimnet -- create -s 1. -s 2. -s 3. -s 4.
```

Running this command will generate several (4 in this case) files and scripts to run the staker nodes in your custom local network. This means that staker 1 will have voting power equivalent to 1 SYM and staker 2 will have 2 SYM, etc.

Let's go through what this all means:

1. `run-staker-*.sh` - run an individual staker node
2. `run-all.sh` - run all of the staker nodes on a custom local network
3. `staker-*.yaml*` - defines the config for an individual staker node (explained below)
4. `genesis.yaml` - defines the genesis config for the custom local network (explained below)

After running some (or all) of the nodes, you'll be able to interact with the nodes via `melwallet-client`, `melminter`, or even direct HTTP calls.

```shell-session
./run-all.sh
```

Should produce logs like:

```
[2024-05-11T14:28:09Z INFO  melnode] melnode v0.20.7 initializing...
[2024-05-11T14:28:09Z DEBUG melnode::storage::storage] about to sqlite
[2024-05-11T14:28:09Z DEBUG melnode::storage::storage] sqlite initted
[2024-05-11T14:28:09Z DEBUG melnode::storage::storage] about to mesha
[2024-05-11T14:28:09Z DEBUG melnode::args] node storage opened
[2024-05-11T14:28:09Z INFO  melnode] bootstrapping with [127.0.0.1:2000]
[2024-05-11T14:28:09Z DEBUG melnode::node] starting to listen at 127.0.0.1:2000
[2024-05-11T14:28:19Z DEBUG melnode::staker] starting consensus for 1...
[2024-05-11T14:28:19Z WARN  melnode::staker] mempool not at the right height, trying again
[2024-05-11T14:28:29Z DEBUG melnode::staker] starting consensus for 1...
[2024-05-11T14:28:29Z DEBUG melstf::state] changing fee multiplier 100 by 1
[2024-05-11T14:28:29Z DEBUG melnode::staker] proposed state has 0 transactions
[2024-05-11T14:28:32Z DEBUG melnode::staker] 1/127.0.0.1:5000 DECIDED on a block with 240 bytes within 3.155822014s
[2024-05-11T14:28:32Z DEBUG melstf::state] applied a batch of 0 txx to #<c99d36b369d0fc1bd494b84db635c5964e8359fafff00a1732d19090c3595e41> => #<c99d36b369d0fc1bd494b84db635c5964e8359fafff00a1732d19090c3595e41>
[2024-05-11T14:28:32Z DEBUG melstf::state] changing fee multiplier 100 by 1
[2024-05-11T14:28:32Z DEBUG melnode::storage::storage] applied block 1 / 64e3f33aa793f118ef09fa8aa72a7f6b7b5831dba1f8052d8ac1506e04883a09 in 5.01ms (history insertion 2.42ms)
[2024-05-11T14:28:32Z DEBUG melnode::staker] 1/127.0.0.1:5000 COMMITTED the newly decided block within 3.164806678s
```

### melwallet-cli, melminter

To use melwallet or melminter on your local simnet, first set the `MELBOOTSTRAP` environment variable to a hard-coded block height and header hash to bootstrap clients on this network:

```
export MELBOOTSTRAP=<network-name>:<block-height>:<header-hash>
```

You can find all the information needed from the node logs. From the logs above, you can set:

```
export MELBOOTSTRAP=custom02:1:64e3f33aa793f118ef09fa8aa72a7f6b7b5831dba1f8052d8ac1506e04883a09
```

To use the wallet, run `melwallet-cli` with the `--bootstrap` flag to specify the socket address for connecting to the local node:

```
melwallet-cli --wallet-path my-wallet.json --bootstrap 127.0.0.1:2000 create --network custom02
```

Similarly with `melminter`:

```
melminter --bootstrap 127.0.0.1:2000 --payout <wallet-address>
```

Local simnets all support faucet transactions:

```
melwallet-cli --wallet-path my-wallet.json --bootstrap 127.0.0.1:2000 send-faucet --wait
```

### Custom genesis configuration

This is only needed to start our own custom network, `melnode` accepts a YAML config file similar to the following:

```yaml
network: custom02 # anything from custom02..custom08
# specifies the "initial stash" of money in the genesis block
init_coindata:
  # what address gets the initial supply of money
  covhash: t5xw3qvzvfezkb748d3zt929zkbt7szgt6jr3zfxxnewj1rtajpjx0
  # how many units (in millionths)
  value: 1000000
  # denomination
  denom: MEL
  # additional data in the UTXO, as a hex string
  additional_data: ""
# specifies all the stakers with consensus power.
# we need to specify ourselves in order to produce any blocks; "Mel-crypttool generate-ed25519" (install via cargo) can generate a keypair for us
stakes:
  deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef:
    pubkey: 4ce983d241f1d40b0e5b65e0bd1a6877a35acaec5182f110810f1276103c829e
    e_start: 0
    e_post_end: 100000 # essentially never end the stake
    syms_staked: 10000 # does not matter
# Initial fee pool
init_fee_pool: 10000
```

### Custom staker configuration

If we want to run a local custom staker node, `melnode` accepts a YAML config file:

```yaml
# secret key; must correspond to "stakes.dead[...]beef.pubkey" in the network config
signing_secret: 5b4c8873cbdb089439d025e9fa817b1df1128231699131c245c0027be880d4d44ce983d241f1d40b0e5b65e0bd1a6877a35acaec5182f110810f1276103c829e
# address for staker-network communication, this can be arbitrary
listen: 127.0.0.1:20000
# must be same as "listen"
bootstrap: 127.0.0.1:20000
# where block rewards are sent
payout_addr: t5xw3qvzvfezkb748d3zt929zkbt7szgt6jr3zfxxnewj1rtajpjx0
# vote for this fee multiplier (higher values charge more fees)
target_fee_multiplier: 10000
```


# Szaldi guide

Szaldi: the trustless Mel->Ethereum light-client relay.

{% hint style="warning" %}
Szaldi is under heavy development and **not** yet ready for public use.

Both Szaldi and these docs are WIP and **following them will not work right now.**
{% endhint %}

Szaldi is a **Mel/Ethereum relay contract**. It is essentially trustless and based on light-client verification on both sides.

Szaldi enables the transfer of Mel-native assets like MEL and SYM to Ethereum (or any other EVM chain) and back. This allows usage of Mel assets in the Ethereum ecosystem — for example, wMEL (wrapped MEL) can easily be plugged into the existing DeFi ecosystem as a novel, low-volatility asset.

Szaldi is 100% autonomous and decentralized. It's not a custodial bridge where you have to trust the bridge operators, nor do we rely on an external set of validators. Our relay leverages the native security of both underlying chains.

The functionality of the relay is simple:

* **Wrapping assets** from Mel to Ethereum: Mel assets (e.g. MEL) are locked up into a special covenant. A light-client proof of the locking Mel transaction is then submitted to an Ethereum smart contract, which then prints ERC-1155 tokens (e.g. wMEL).
* **Unwrapping assets** like wMEL on Ethereum back to Mel: ERC-1155 wrapped tokens are burnt with the Ethereum smart contract. A light-client proof of the burn transaction is then used to unlock the locked assets on the Mel side.

In the next section we will look at step-by-step instructions on how we can use Szaldi to move our Mel assets to the Ethereum network and after we will take a deeper look at Szaldi's architecture and design.


# Bridge your coins

A step-by-step guide to transferring Mel coins to Ethereum using Szaldi via our client implementation, Szaldi-cli.

To safely and conveniently streamline interaction with Szaldi, a client has been implemented in Rust which abstracts away the complexity of querying the chain state and crafting compliant transactions on both networks. It is packaged as a simple-to-use CLI application whose source code can be viewed [here](https://github.com/Mellabs/bridge-cli).

## Moving Mel coins to Ethereum

In order to mint your Mel coins as tokens on Ethereum, you must first lock your coins up on the Mel network and then send a proof of the lock transaction to the Ethereum network. `Szaldi-cli` takes care of abstracting the entire process away using an interactive CLI session which will guide you through the bridging process, one step at a time.

<pre class="language-shell-session"><code class="lang-shell-session"><strong>Szaldi-cli to-ethereum -t &#x3C;Mel-wallet-name> -e &#x3C;ethereum-wallet-dir>
</strong>
Welcome to Szaldi-cli! I'll help guide you through the bridging process.

First, what value and denomination of tokens do you want to bridge to Ethereum?
<strong>14000.0 SYM
</strong>
You are choosing to bridge 14000.0 SYM from Mel to Ethereum.
The total Ethereum fees will be 0.07273046 ETH.
Do you wish to proceed? (y/n):
<strong>y
</strong>
Bridging your coin, this process may take a couple of minutes.
................................
Success! Your tokens were successfully minted with transaction hash 0xc4408a86465c500c8eea7ded6b2c3c1d9d505470f6587473ca1342073c00d676
</code></pre>

## Moving Ethereum tokens back to Mel

{% hint style="info" %}
**Note**: Szaldi currently supports moving Mel coins to Ethereum and back, but not the other way around (i.e. it can move wrapped MEL tokens from Ethereum back to Mel, but it cannot move ETH to Mel).
{% endhint %}

To move your assets from Ethereum back to Mel, you must choose a coin to unlock, burn the equivalent amount on the Ethereum network, and provide the Mel network with a proof of this burn. To automate this process, we can use an interactive `Szaldi-cli` session which will safely walk you through the process.

<pre class="language-shell-session"><code class="lang-shell-session"><strong>Szaldi-cli to-Mel -e &#x3C;ethereum-wallet-dir> -t &#x3C;Mel-wallet-name>
</strong>
Welcome to Szaldi-cli! I'll help guide you through the bridging process.

First, let me query Szaldi for locked coins. This might take a few seconds.
....
Okay, choose one of the following locked coins to unlock:
(1) 14000.0 SYM
(2) 34343434343.34343 MEL
(3) 3.14 CUSTOM-ab18c283da41e5cd87e91b5f142e7f4da5c29014c3568140a25e1fe67bceb6c6
Choose between coins 1-3:
<strong>1
</strong>
You are choosing to bridge 14000.0 SYM from Ethereum to Mel.
The total Mel fees will be 12.273046 MEL.
Do you wish to proceed? (y/n):
<strong>y
</strong>
Bridging your tokens, this process may take a couple of minutes.
...................
Success! Your coin was successfully unlocked with transaction hash 0x4262932c3c65a83ad1d4bcbcb3aef906c76cd9eaa3fb98b5fde7d0ccc88e089a
</code></pre>

As we can see, the bridging process to and from Mel has been made as convenient as possible for end users. Now that we know how to interact with Szaldi using `Szaldi-cli`, let's take a deeper look at how everything actually works in the next section.


# Architectural overview

A high-level overview of the Szaldi design.

As we mentioned earlier, Szaldi is made up of two complementary components, a Mel covenant and a set of Ethereum smart contracts. Both of these components work together to enable the transfer of assets on Mel to Ethereum securely.

## From Mel to Ethereum

<figure><img src="/files/8H0URflvUPojC5hjyeCO" alt=""><figcaption><p>Diagram of the freeze and mint process.</p></figcaption></figure>

Here we see that moving assets from Mel to Ethereum requires four steps:

1. Sending a transaction to the Szaldi covenant which essentially locks the transferred Mel coin.
2. Requesting the appropriate information from a Mel node in order to get proof of the locking transaction.
3. Submitting proof of the locking transaction to the Ethereum smart contracts to be processed.
4. After verification by the Ethereum smart contracts, your frozen coin will be minted as Ethereum tokens.

## From Ethereum back to Mel

<figure><img src="/files/EbtMj3mqopeyDSMVjuwc" alt=""><figcaption><p>Diagram of the burn and thaw process.</p></figcaption></figure>

The process for moving your tokenized assets from Ethereum back to Mel is very similar:

1. Sending a transaction to the Szaldi smart contracts which burns the equivalent amount of tokens as the coin you are attempting to unlock.
2. Requesting the appropriate information from an Ethereum node in order to get proof of the token burn.
3. Sending the proof of burn to the Mel covenant to be processed.
4. After verification by the Mel covenant, your frozen coin will be unlocked and sent to your Mel wallet.

## Next steps

In this guide, we learned about the function and architecture of Szaldi and how it is powered by the native security of both Mel and Ethereum. In the next section we will learn how we can help strengthen the security of the Mel network ourselves by participating in staking.


# Yellow Paper

{% hint style="info" %}
A formal Mel yellow paper is still WIP as the current betanet settles down.

The [yellow paper of the v1 betanet is available on the old documentation website](https://ancient-docs.melproject.org/specifications/yellow/), but some details may be out of date.
{% endhint %}


# Frequently asked questions

This is your one-stop shop for all commonly asked questions.

{% hint style="info" %}
This FAQ is intended to be perpetually WIP. Feel free to add your own Q\&A's in a pull request!
{% endhint %}

### What is Mel?

Mel is a minimal, governance-free L1 blockchain whose core vision consists of enabling a future ecosystem of secure, composable, off-chain dapps. Learn more in our [intro](/).

### What are the considerations for decentralization, security, and scalability?

In accordance with Mel's core values of decentralization and trustlessness, the core security of the protocol is in the hands of stakers, for which there is no minimum staking amount and low hardware requirements, reducing the barrier to entry. Additionally, though stakers in other chains are often assumed to be honest (and therefore not prone to collusion), Mel eschews these assumptions and instead uses the rigorous consensus algorithm Synkletos, which operates under the assumption that stakers *will* collude, and bakes this into its own security.

Mel's philosophy of focusing on off-chain, composable dapps is central to its scaling strategy. This is made possible through the MelVM, a non-Turing-complete virtual machine that nevertheless is able to compute all primitive recursive functions and enables attaching sophisticated covenants to coins. This empowers scaling strategies crucial to global adoption, such as full nodes with limited storage space and light clients that can securely verify much more information than conventional techniques like Bitcoin’s SPV allows, while at the same time avoiding the pitfalls of stateful smart contracts.

### How does MEL stabilize itself?

MEL is cryptographically pegged to a DOSC (day of sequential computation) using the Melmint algorithm. The DOSC was chosen because it has a relatively stable purchasing power and because it is trustlessly measurable through a sequential proof of work. This, combined with a protocol-internal Uniswap-style automated market maker (AMM), provides incentives which allow MEL to self-stabilize. Get a more in depth view of the Melmint algorithm [here](/developer-guides/getting-tokens/minting-mel-with-melminter).

### How is MEL different from other stablecoins like USDC or DAI?

Apart from not requiring any trust in centralized entities (like USDC), MEL differentiates itself from the crowd by not only being decentralized (like DAI), but by *also* not being pegged to any fiat currencies, which themselves are subject to centralized influence and manipulation.

### What are the risks of putting my money into Mel? What are the failure scenarios for the network?

There are a couple of failure scenarios which we can imagine with regard to the Melmint algorithm:

* A drastic change in DOSC value would cause MEL to lose its stable purchasing power, although historically this has not happened and is unlikely to in the future due to the definition of a DOSC in terms of *time* rather than *amount* of computation.
* A sudden decrease in Mel market sentiment, in say, a general cryptocurrency crash, could result in an extremely rare scenario where a large amount of SYM or MEL is simultaneously panic-sold; this would threaten the basis of the Melmint peg but is unlikely to completely dump MEL due to Melmint's design. This is especially because, unlike users of USD stablecoins, MEL users never expected zero exchange-rate risk and are unlikely to completely dump MEL due to a temporary depeg. The economic impact of such a depeg is likely to be around the same order of magnitude as a fiat “currency crisis” — bad, but not catastrophic. Once sufficient liquidity returns to the Melswap MEL/SYM market, the peg will gradually be restored.

### How much does it cost to run a staker node? Is it profitable?

There is no minimum amount of SYM which needs to be staked in order to participate in consensus. Profit from staking comes from transaction fees present in each block. More information on staking can be found [here](https://github.com/themeliolabs/documentation/blob/master/resources/broken-reference/README.md).

### How can I get some MEL?

Currently, you can only acquire MEL by running a `melminter` instance or by swapping SYM or ERG via Melswap. Get more information about acquiring tokens [here](/developer-guides/getting-tokens).


# MelVM spec

{% hint style="info" %}
MelVM will be undergoing some significant updates in the near future, most notably merging in [work on Turing completeness](https://forum.melproject.org/t/making-melvm-turing-complete/72).

Until then, please see the [old spec](https://ancient-docs.melproject.org/specifications/melvm-specification/), which is currently live on the devnet.
{% endhint %}


