# Predicates
### David Mihal
<!-- Put the link to this slide here so people can follow -->
Slide: https://hackmd.io/@dmihal/predicates
---
## What the heck are predicates?
How do predicates work?
What can we use them for?
What are their limitations?
---
Are predicates fully unique to Fuel?
Not really...
---
| Physical (bearer) assets | Digital assets |
| -------- | -------- |
| Ownership means physical posession | Ownership means ability to move assets |
---
On blockchains: ownership is the ability to move an asset following the rules of the chain.
---
# Basic Bitcoin rules
For a given coin, the owner can sign a message allowing them to "spend" the coin and create new coins with different owners.
```graphviz
digraph UTXO {
node [shape=box, style="rounded,filled", fillcolor="#E8F6FF", fontname="Arial"];
edge [style=invis];
subgraph cluster_UTXO {
label = "UTXO";
labeljust = "l";
fontname = "Arial";
color = "#A9D0F5";
style = "rounded,filled";
fillcolor = "#D6EAF8";
UTXO [label="0.1 BTC\nOwner: 12higD...Wv"];
}
}
```
Known as "Pay to Public Key Hash" (P2PKH)
---
What if we could define our own rules?
---
## Pay to Script Hash (P2SH)
"Create" script
1. Create script using Bitcoin Script
2. Hash the bytecode
3. Send funds to address derived from hash
Spend script
Include script bytecode in hash
---
![](https://hackmd.io/_uploads/HJ6uqlLLh.png)
---
```typescript
OP_2
<key1.public_key>
<key2.public_key>
<key3.public_key>
OP_3
OP_CHECKMULTISIG
```
---
```typescript
OP_IF
<$(
<current_block_time> <delay_seconds>
OP_ADD
)>
OP_CHECKLOCKTIMEVERIFY OP_DROP
<trusted.public_key>
OP_CHECKSIGVERIFY
<1>
OP_ELSE
<2>
OP_ENDIF
<first.public_key> <second.public_key> <2>
OP_CHECKMULTISIG
```
---
First time in history that assets are owned by _code_
---
Fast forward to EthereumLand...
---
Ethereum smart contracts:
Bitcoin P2SH (immutable code that can own assets)
\+ more powerful VM
\+ on-chain code
\+ on-chain storage 💾
---
Forget, simple multisigs...
* Dynamic multisigs
* Social recovery
* Liquidity pools
* Lending markets
* Rollups
---
# The Problem...
![](https://hackmd.io/_uploads/rkH6hSSLn.png)
---
### Now to Fuelistan...
_(Фуелистан)_
---
# Original Fuel philosophy:
Combine the efficencies of Bitcoin with the expresivity and flexability of Ethereum
---
Simplicity of Bitcoin's stateless P2SH
\+ Expresivity of Ethereum's EVM
= Predicates!
---
Predicate is just an _address_
It's not created or deployed
It's only useful if it owns assets
Code is only revealed when trying to _take_ (spend) tokens from a predicate
---
# Free giveaway
```rust
predicate;
fn main() -> bool {
true
}
```
---
# Password-protected token
```rust
predicate;
use std::hash::sha256;
fn main(password: str[16]) -> bool
// sha256("Hello World ")
let expected_hash = 0x0a692e936c61cc37c9dc4517e88aa3604780b273fed61b7690d41efaa51fa03d;
sha256(password) == expected_hash
}
```
---
# New wallet signatures
```rust
predicate;
configurable {
PREDICATE_ADDR: b256 = ZERO_B256,
}
fn main(signature: B512) -> bool {
let evm_address: EvmAddress = EvmAddress::from(PREDICATE_ADDR);
let res = ec_recover_evm_address(signature, personal_sign_hash(tx_id()));
if res.is_ok() {
if evm_address == EvmAddress::from(res.unwrap().value) {
return true;
}
}
false
}
```
---
## Predicates are _stateless_
Can't access data stored on chain
* Can't read data from smart contracts
* Can't check the current date/time
* Can't read the block hash/number
_if a predicate evaluates to `true` then it will always evaluate to `true` in the future_
---
## What can a predicate access?
Anything included in the transaction!
* Predicate input parameters
* Input coins
* Output coins
* The transaction script
---
## Atomic Swap
"Create" order
```graphviz
digraph CoinMovement {
node [shape=circle, fontsize=12]
UserA [label="User A", shape=plaintext]
Coin [label="ETH"]
Predicate [label="Predicate", shape=plaintext]
UserA -> Coin
Coin -> Predicate
}
```
---
## Atomic Swap
```graphviz
digraph CoinMovement {
node [shape=circle, fontsize=12]
UserA [label="User A", shape=plaintext]
UserB [label="User B", shape=plaintext]
UserBOut [label="User B", shape=plaintext]
CoinA [label="ETH"]
CoinB [label="USDC"]
Predicate [label="Predicate", shape=plaintext]
Predicate -> CoinA
CoinA -> UserBOut
CoinB -> UserA
UserB -> CoinB
}
```
---
<!-- .slide: style="font-size: 20px;" -->
## Atomic Swap
```rust
predicate;
configurable {
ASSET_ID: ContractId = ContractId::from(0x0000000000000000000000000000000000000000000000000000000000000000),
RECEIVER: Address::from(RECEIVER_CONFIG),
}
fn main() -> bool {
// If the tx contains a single input from the receiver, cancel the order
if input_count() == 2u8 {
if input_owner(0).unwrap() == RECEIVER || input_owner(1).unwrap() == RECEIVER {
return true;
};
};
let output_index = 0; // Output 0 must pay receiver
let to = Address::from(__gtf::<b256>(output_index, GTF_OUTPUT_COIN_TO));
let asset_id = ContractId::from(__gtf::<b256>(output_index, GTF_OUTPUT_COIN_ASSET_ID));
let amount = output_amount(output_index);
(to == RECEIVER) && (amount == ASK_AMOUNT) && (asset_id == ASK_TOKEN)
}
```
---
# Enforcing script calls
![](https://hackmd.io/_uploads/S1kWlBIU2.png =200x200)
A predicate can read the transaction script bytecode
* Enforce the _entire_ bytecode matches
* Enforce that _part of_ the bytecode matches
Example:
* Whitelisting users
---
```mermaid
graph TD;
A[UTXO validation] --> B[Signature verification]
A[UTXO validation] --> C[Predicate validation]
B[Signature verification] --> D[Script execution]
C[Predicate validation] --> D[Script execution]
```
---
## Current Limitations
* Enforcing whole script breaks composability
* Enforcing partial script limits composability and is complicated to implement
* Want to change a parameter? Need a new predicate
* Want to change predicate? Need to send _all_ assets, plus update any smart contracts
* How do we know what predicates exist if code isn't public?
* Predicate announcement standard
---
## So... are predicates really stateless?
Can't access traditional smart-contract state, but UTXOs _are_ a form of state
_Example: What if we created a UTXO to represent a limit order?_
---
## We're just scratching the surface of what's possible with predicates...
![](https://hackmd.io/_uploads/BkiTjXUU3.png =300x200)
**Upcoming features:**
* Longer predicate code via loading contract bytecode
* Multi-asset support = easier data UTXOs
* "Observable" UTXOs
---
# Building with Predicates
---
## Get a Predicate
```rust
fn get_predicate(eth_address: &[u8; 20], provider: Provider) -> Predicate {
let padded_address = pad_address(eth_address);
let configurables = SimpleSigPredicateConfigurables::new()
.set_PREDICATE_ADDR(Bits256(padded_address));
let predicate_data = SimpleSigPredicateEncoder::encode_data(0);
let mut predicate: Predicate = Predicate::load_from(BIN_PATH)
.unwrap()
.with_data(predicate_data)
.with_configurables(configurables);
predicate.set_provider(provider);
predicate
}
```
---
## Send coins from Predicate
```rust=
let mut predicate = get_predicate(ð_address, wallet.provider().unwrap().clone());
let inputs = predicate
.get_spendable_resources(BASE_ASSET_ID, 10)
.await
.unwrap()
.into_iter()
.map(|resource| Input::resource_predicate(resource, predicate.code().to_vec(), UnresolvedBytes::default()))
.collect();
let outputs = predicate.get_asset_outputs_for_amount(wallet.address(), BASE_ASSET_ID, 10);
let signature = sign_message(ð_wallet).await;
let tx_builder = ScriptTransactionBuilder::prepare_transfer(inputs, outputs, TxParameters::default());
let tx = predicate.add_fee_resources(tx_builder, 10, None).await.unwrap();
let response = wallet.provider().unwrap().send_transaction(&tx).await.unwrap();
```
---
Predicates + UTXOs open up a new paradigm for parallelized blockchain applications
What can you build with predicates that wasn't previously possible?
---
# Questions?
{"metaMigratedAt":"2023-06-18T05:34:48.142Z","metaMigratedFrom":"YAML","title":"Predicates","breaks":true,"description":"View the slide with \"Slide Mode\".","contributors":"[{\"id\":\"614d3dfc-f939-4def-b3a0-c5f195aff96c\",\"add\":8974,\"del\":2832}]"}