-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
29 changed files
with
10,283 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# guessNumberLucid | ||
Off-Chain code with Lucid #plutarch #cardano | ||
|
||
|
||
|
||
|
||
|
||
Employ Lucid to interact with off-chain code. | ||
|
||
Employ blockfrost to connect to Cardano blockchain. | ||
|
||
|
||
|
||
|
||
|
||
## Plutarch On Chain code | ||
|
||
### Overview | ||
|
||
Plutarch is an eDSL in Haskell for writing on-chain scripts for Cardano. With some caveats, Plutarch is a [simply-typed lambda calculus](https://en.wikipedia.org/wiki/Simply_typed_lambda_calculus) (or STLC). Writing a script in Plutarch allows us to leverage the language features provided by Haskell while retaining the ability to compile to compact Untyped Plutus Core (or UPLC, which is an untyped lambda calculus). | ||
|
||
When we talk about “Plutarch scripts,” we are referring to values of type `Term (s :: S) (a :: PType)`. `Term` is a `newtype` wrapper around a more complex type, the details of which Plutarch end-users can ignore. A `Term` is a typed lambda term; it can be thought of as representing a computation that, if successfully evaluated, will return a value of type `a`. | ||
|
||
|
||
|
||
### Why Plutarch? | ||
|
||
Plutarch written validators are often significantly more efficient than Plutus Tx written validators. With Plutarch, you have much more fine gained control of the Plutus Core you generate, without giving up any type information. | ||
|
||
To put things into perspective, one validator script from a large production contract was rewritten in Plutarch, changed from Plutus Tx. Here's the comparison between the Plutarch script's execution cost compared to the Plutus Tx script's execution cost. These numbers were gathered by simulating the whole contract flow on a testnet: | ||
|
||
| Version | CPU | Memory | Script Size | | ||
| ------------------ | ----------- | ------- | ----------- | | ||
| PlutusTx (current) | 198,505,651 | 465,358 | 2013 | | ||
| Plutarch | 51,475,605 | 99,992 | 489 | | ||
|
||
|
||
|
||
[Reference]: https://github.com/Plutonomicon/plutarch-plutus#why-plutarch "Why Plutarch" | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
### guessNumber | ||
|
||
|
||
|
||
Here we start with Number guess game and the Cardano plutus onChain script is written in Plutarch. | ||
|
||
Below is snippet of onCHain code for : | ||
|
||
#### Datum and Redeemer | ||
|
||
```haskell | ||
data POurDatum (s :: S) = POurDatum (Term s (PDataRecord '[ "password" ':= PInteger ])) | ||
deriving stock (Generic) | ||
deriving anyclass (PlutusType, PIsData, PDataFields) | ||
|
||
instance DerivePlutusType POurDatum where | ||
type DPTStrat _ = PlutusTypeData | ||
|
||
instance PTryFrom PData POurDatum | ||
|
||
data POurRedeemer (s :: S) = POurRedeemer (Term s (PDataRecord '[ "password" ':= PInteger ])) | ||
deriving stock (Generic) | ||
deriving anyclass (PlutusType, PIsData, PDataFields) | ||
|
||
instance DerivePlutusType POurRedeemer where | ||
type DPTStrat _ = PlutusTypeData | ||
|
||
instance PTryFrom PData POurRedeemer | ||
``` | ||
|
||
|
||
|
||
#### Plutarch validator | ||
|
||
This is a simple validator where it matches the existing Datum number with Redeemer number, and if its equal then it unlocks the funds. Again this is a trivial example as we inline the Datum so its actually visible but ideally it should be hashed. | ||
|
||
```haskell | ||
pvalidateSmallChecks :: Term s (POurDatum :--> POurRedeemer :--> PScriptContext :--> PUnit) | ||
pvalidateSmallChecks = phoistAcyclic $ plam $ \datum redeemer _ctx -> unTermCont $ do | ||
-- ctxF <- pletFieldsC @'["txInfo"] ctx | ||
-- infoF <- pletFieldsC @'["signatories"] ctxF.txInfo | ||
datumF <- pletFieldsC @'["password"] datum | ||
redeemF <- pletFieldsC @'["password"] redeemer | ||
pure $ | ||
pif ( (redeemF.password) #== datumF.password ) | ||
(pconstant ()) | ||
perror | ||
|
||
pvalidateSmallChecksW :: Term s PValidator | ||
pvalidateSmallChecksW = phoistAcyclic $ plam $ \datum redeemer ctx -> | ||
let ourDatum :: Term _ POurDatum | ||
ourDatum = punsafeCoerce datum | ||
ourRedeemer :: Term _ POurRedeemer | ||
ourRedeemer = punsafeCoerce redeemer | ||
in popaque $ pvalidateSmallChecks # ourDatum # ourRedeemer # ctx | ||
``` | ||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
|
||
import { useState } from 'react' | ||
import { useStoreActions, useStoreState } from "../utils/store"; | ||
|
||
|
||
const NftCard = (props: any) => { | ||
const image = typeof (props.meta.image) === 'string' ? "https://ipfs.io/ipfs/" + props.meta.image.replace("ipfs://", "") : "" | ||
|
||
return ( | ||
<> | ||
<div className="card w-76 bg-base-300 shadow-xl m-5"> | ||
<figure className="px-10 pt-10"> | ||
<img src={image} alt="Shoes" className="rounded-xl" /> | ||
</figure> | ||
<div className="card-body items-center text-center"> | ||
<h2 className="card-title">{props.meta.name}</h2> | ||
<div className="card-actions"> | ||
</div> | ||
</div> | ||
</div> | ||
</> | ||
) | ||
} | ||
|
||
export default NftCard; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
|
||
import { useEffect } from 'react' | ||
import NftCard from './NftCard' | ||
|
||
const NftGrid = (props : any) => { | ||
useEffect(()=>{ | ||
console.log(props) | ||
},[props]) | ||
return ( | ||
<> | ||
<div className="grid grid-cols-4 gap-2"> | ||
{props.nfts.map((nft : any, index : Number) => { | ||
return <NftCard key={index} meta={nft} /> | ||
})} | ||
</div> | ||
</> | ||
|
||
) | ||
} | ||
|
||
export default NftGrid; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { Lucid, Blockfrost, C } from "lucid-cardano"; | ||
import { useState, useEffect } from 'react'; | ||
import { useStoreActions, useStoreState } from "../utils/store"; | ||
import initLucid from "../utils/lucid"; | ||
|
||
const WalletConnect = () => { | ||
// const [availableWallets, setAvailableWallets] = useState<string[]>([]) | ||
const walletStore = useStoreState(state => state.wallet) | ||
const setWallet = useStoreActions(actions => actions.setWallet) | ||
const availableWallets = useStoreState(state => state.availableWallets) | ||
const setAvailableWallets = useStoreActions(actions => actions.setAvailableWallets) | ||
|
||
const [connectedAddress, setConnectedAddress] = useState("") | ||
|
||
const loadWalletSession = async () => { | ||
if (walletStore.connected && | ||
walletStore.name && | ||
window.cardano && | ||
(await window.cardano[walletStore.name.toLowerCase()].enable()) | ||
) { | ||
walletConnected(walletStore.name) | ||
} | ||
} | ||
|
||
const walletConnected = async (wallet: string, connect: boolean = true) => { | ||
const addr = connect ? await (await initLucid(wallet)).wallet.address() : '' | ||
const walletStoreObj = connect ? { connected: true, name: wallet, address: addr } : { connected: false, name: '', address: '' } | ||
setConnectedAddress(addr) | ||
setWallet(walletStoreObj) | ||
} | ||
|
||
const selectWallet = async (wallet: string) => { | ||
if ( | ||
window.cardano && | ||
(await window.cardano[wallet.toLocaleLowerCase()].enable()) | ||
) { | ||
walletConnected(wallet) | ||
} | ||
} | ||
|
||
useEffect(() => { | ||
let wallets = [] | ||
if (window.cardano) { | ||
if (window.cardano.nami) wallets.push('Nami') | ||
if (window.cardano.eternl) wallets.push('Eternl') | ||
if (window.cardano.flint) wallets.push('Flint') | ||
loadWalletSession() | ||
} | ||
setAvailableWallets(wallets) | ||
}, []) | ||
|
||
return ( | ||
<> | ||
<div className="dropdown dropdown-end"> | ||
<label tabIndex={0} className="btn m-1">{connectedAddress != "" ? 'Connected' : 'Connect'}</label> | ||
<ul tabIndex={0} className="dropdown-content menu p-2 shadow bg-base-300 rounded-box w-52"> | ||
{availableWallets.map((wallet) => | ||
<li key={wallet} onClick={() => { selectWallet(wallet) }} ><a>{wallet}</a></li> | ||
)} | ||
</ul> | ||
</div> | ||
</> | ||
) | ||
} | ||
|
||
export default WalletConnect; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
|
||
/** @type {import('next').NextConfig} */ | ||
const nextConfig = { | ||
|
||
experimental: { | ||
outputStandalone: true, | ||
}, | ||
reactStrictMode: true, | ||
webpack: (config) => { | ||
config.experiments = { | ||
asyncWebAssembly: true, | ||
topLevelAwait: true, | ||
layers: true | ||
} | ||
return config | ||
} | ||
} | ||
|
||
module.exports = nextConfig |
Oops, something went wrong.