Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions website/docs/guides/adversarial.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ For an adversarial attack to pull off this time-sensitive attack, he would requi

### Late Double Spends

In the case of an late double spend (which does not try to exploit a race condition) the adversarial actor need help from a miner.
In the case of a late double spend (which does not try to exploit a race condition) the adversarial actor need help from a miner.
Either the adversarial actor needs to convince the miners to abandon their first seen rule or he needs to be mining himself to be able to construct his own block.

:::caution
Expand Down Expand Up @@ -100,7 +100,7 @@ Adversarial analysis should take into account that "first-seen rule" is just a c
### Specialized Block-Builders


As described in the section on "stale-state arbitrage" economic actors ay be incentivized to strategically create a competing transaction chain which takes advantage of an older price state/ratio which has not yet been confirmed in the blockchain. Although miners are not specialized in the optimal construction of DeFi transactions in a block, miner would over time be likely to team up with teams/companies creating this type of software for them.
As described in the section on "stale-state arbitrage" economic actors may be incentivized to strategically create a competing transaction chain which takes advantage of an older price state/ratio which has not yet been confirmed in the blockchain. Although miners are not specialized in the optimal construction of DeFi transactions in a block, miner would over time be likely to team up with teams/companies creating this type of software for them.

:::note
Ethereum with its large amount of MEV has already seen the emergence of specialized 'block builder' as a new class of relevant economic actors separate from the block proposer (who signs the block).
Expand Down
88 changes: 65 additions & 23 deletions website/docs/guides/cashtokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,31 @@ and their equivalent for outputs:
- **`bytes tx.outputs[i].nftCommitment`** - NFT commitment data of a specific output
- **`int tx.outputs[i].tokenAmount`** - Amount of fungible tokens of a specific output.

## CashTokens Use cases

The Jedex has a section on novel "[demonstrated concepts](https://github.com/bitjson/jedex#demonstrated-concepts)" enabled by CashTokens. The Jedex overview serves as the best reference to-date for the new possibilities enabled by CashTokens.

:::tip
The [Jedex demo](https://github.com/bitjson/jedex) also introduces very advanced concepts on multi-threading and MEV avoidance through batching. This core feature of 'joint-execution' is how the DEX got its name.
:::

Below we'll create a short list of the use cases which will be the most important to know about:

- **Covenant tracking tokens** - this is what enables unique authentication of contract deployments
- **Commitment-based state management** - this is what `mutable` nfts are extremely useful for
- **Depository covenants/token pools** - which we would call token sidecars
- **Role tokens** - these are authentication tokens for admins
- **Token-unlocked covenants** - this concept has also been called "pay-to-nft"
- **Redeemable NFTs** - `immutable` nfts can carry state as a receipt which can be returned later for payout
- **Coupled covenants/logic offloading** - which we would call sidecar functions
- **Spin-off covenants** - the idea that contract create regular helper contracts to perform some task

## CashTokens Gotchas
There are a few important "gotchas" to be aware of when developing with CashTokens in smart contracts for the first time.
There are a few important "gotchas" to be aware of when developing with CashTokens in smart contracts for the first time. We'll separate them on gotchas on the contract side, and gotchas on the transaction building side.

### Contract Gotchas

#### 1) tokenCategory contains the nft-capability
#### tokenCategory contains the nft-capability
```solidity
bytes tx.inputs[i].tokenCategory
```
Expand All @@ -73,37 +94,37 @@ When accessing the `tokenCategory` through introspection the result returns `0x`
If you want to check for an NFT using introspection, you have either split the `tokenCategory` from the `capability` or check the concatenation of the `tokenCategory` and `capability`.

```solidity
// Constructor parameters: providedCategory
// Constructor parameters: providedCategory

// Extract the separate tokenCategory and capability
bytes32 tokenCategory, bytes capability = tx.inputs[0].tokenCategory.split(32);
// Extract the separate tokenCategory and capability
bytes32 tokenCategory, bytes capability = tx.inputs[0].tokenCategory.split(32);

// Check that the NFT is the correct category and has a "minting" capability
require(providedCategory == tokenCategory);
require(capability == 0x02);
// Check that the NFT is the correct category and has a "minting" capability
require(providedCategory == tokenCategory);
require(capability == 0x02);

// Alternatively:
// Alternatively:

// Check by concatenating the providedCategory and capability
require(tx.inputs[0].tokenCategory == providedCategory + 0x02);
// Check by concatenating the providedCategory and capability
require(tx.inputs[0].tokenCategory == providedCategory + 0x02);
```

#### 2) tokenCategory encoding
#### protect the minting capability

The `tokenCategory` introspection variable returns the tokenCategory in the original unreversed order, this is unlike wallets and explorers which use the reversed byte-order. So be careful about the byte-order of `tokenCategory` when working with BCH smart contracts.
If a covenant contains a `minting` NFT then all outputs should be carefully accounted for in the contract logic to not accidentally allow to mint extra new NFTs.

```ts
// when using a standard encoded tokenId, reverse the hex before using it in your contract
const contract = new Contract(artifact, [reverseHex(tokenId)], { provider })
```

It is not recommended to do the byte-reversal in script, because this adds extra unnecessary overhead to the script.
For a variable number of outputs you could use the following construction:
```solidity
// NOT THIS
require(tx.inputs[0].tokenCategory == providedTokenId.reverse());
// Optionally create bch-change output at outputIndex 5
if (tx.outputs.length > 5) {
require(tx.outputs[5].tokenCategory == 0x, "Invalid BCH change output - should not hold any tokens");
}

// Don't allow more outputs to prevent minting extra NFTs
require(tx.outputs.length <= 6, "Invalid number of outputs - should have 6 at most");
```

#### 3) "invisible" empty nfts
#### "invisible" empty nfts
Because the nft-capability has no separate introspection item, and nothing is appended to the `tokenCategory` in case of capability `none`, empty nfts can be "invisible" when combined with fungible tokens.

First let's consider the case where a UTXO only holds an empty NFT:
Expand Down Expand Up @@ -134,7 +155,28 @@ This means that a covenant UTXO holding both a minting NFT and the fungible toke
The easiest way to prevent issues with "junk" empty NFTs is to check that only NFTs with non-empty commitments can be interacted with in the contract system.
:::

#### 4) Explicit vs implicit burning
### Transaction Building Gotchas

#### tokenCategory encoding

The `tokenCategory` introspection variable returns the tokenCategory in the original unreversed order, this is unlike wallets and explorers which use the reversed byte-order. So be careful about the byte-order of `tokenCategory` when working with BCH smart contracts.

```ts
// when using a standard encoded tokenId, reverse the hex before using it in your contract
const contract = new Contract(artifact, [reverseHex(tokenId)], { provider })
```

#### Combined BCH + CashTokens UTXOs

Most end-user CashTokens wallets expect CashTokens UTXOs to only hold a tiny amount of BCH like 1000 sats. Deviating from the expectation might cause unforeseen problems with user's wallets.

:::tip
You can hard code in your contract that any user token output should have exactly `1000` sats, this avoids possible complicating freedom during transaction building.
:::

However when constructing a transaction with user owned UTXOs, you should always make sure to check whether you handle the edge case of users with combined BCH + CashTokens UTXOs correctly in change output handling both for BCH and the tokens.

#### Explicit vs implicit burning

CashTokens can be burned explicitly by sending them to an OP_RETURN output, which is provably unspendable. CashTokens can also be burned implicitly, by including them in the inputs but not the outputs of a transaction. Always be mindful when adding token-carrying inputs to not forget to add the tokens in the outputs, otherwise they will be considered as an implicit burn.

Expand Down
3 changes: 1 addition & 2 deletions website/docs/guides/covenants.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,9 @@ All outputs of the `PooledFunds` contract need to be carefully controlled in the
With contracts holding minting NFTs, all outputs need to be carefully controlled in the covenant contract code, so no additional (minting) NFTs can un-intentionally be created in other outputs.
:::


## Conclusion
We have discussed the main uses for covenants as they exist on Bitcoin Cash today. We've seen how we can achieve different use cases by combining transaction output restrictions to `P2SH` and `P2PKH` outputs. We also touched on more advanced subjects such as keeping local state in NFTs. Covenants and CashTokens are the **main differentiating factor** for BCH smart contracts when compared to BTC, while keeping the same **efficient, atomic verification**.

Keeping local state in NFTs and issuing NFTs as receipts are two strategies which can be used to create much more sophisticated decentralized applications such as the AMM-style DEX named [Jedex](https://blog.bitjson.com/jedex-decentralized-exchanges-on-bitcoin-cash/).
Keeping local state in NFTs and issuing NFTs as receipts are two strategies which can be used to create much more sophisticated decentralized applications. You can read more of these advanced CashTokens use cases in our [dedicated guide](/docs/guides/cashtokens#cashtokens-usecases)!

[bitcoin-covenants]: https://fc16.ifca.ai/bitcoin/papers/MES16.pdf