Commit ee9e9870 authored by Alexandre de Alegria Junceiro Mascarenhas Monteiro's avatar Alexandre de Alegria Junceiro Mascarenhas Monteiro
Browse files

Merge branch 'master' into 'master'

SmartScribble 2.0 merge request

See merge request !9
parents 3623bb10 8b543a91
.stack-work/
.vscode/
*~
examples/*/*.hs
dist/*
dist-newstyle/*
.ghc.environment.x86_64-linux-8.6.5
examples/testfile.*
examples/Testfile.*
......@@ -55,14 +55,37 @@ To generate code for the local plutus use this sequence of commands:
### The syntax: ###
#### Defining a protocol:
```java
protocol <name> ( role <name> [, role <name> ]* ) {
protocol <name> ( (signed)? role <name> [, (signed)? role <name> ]* ) {
...
}
( individual protocol <name> ( <roleVar>:role ) {
...
} )?
```
*Example*:
```java
protocol PingPong (role P1, role P2) {
protocol PingPong (signed role P1, role P2) {
...
}
```
NOTE: If there is a `signed` role present in the protocol's definition, a set of keys must be specified for that role:
- `cabal run stable-playground <path_to_the_scribble_file> "<signed_role_name> = [hexchar_set [,hexchar_set]*]"`
*Example*:
- `cabal run stable-playground prot.scr "P1 = [abcdef,012345,6789ab]"`
#### Defining a individual protocol:
*Example*:
```java
protocol PingPong (signed role P1, role P2) {
...
}
individual protocol SubPingPong ( pet : P2 ){
...
}
```
......@@ -71,7 +94,7 @@ protocol PingPong (role P1, role P2) {
**Endpoint calls**:
```java
<endpoint_name> (<params>) from <role> ({
<endpoint_name> (<params>) from <role> ( [|<plutus_code>|] )? ({
<Trigger>*
})*;
```
......@@ -81,6 +104,46 @@ protocol PingPong (role P1, role P2) {
ping() from P1;
```
```java
ping() from P1 [|...|];
```
NOTE: individual protocols use the name assigned to a role instead of the role type.
*Example*:
```java
protocol PingPong (signed role P1, role P2) {
ping() from P1;
}
individual protocol SubPingPong ( pet : P2 ){
subping() from pet;
}
```
The role type in the individual protocol, `P2`, must be defined in the primary protocol.
**Shared interaction**:
```java
share <endpoint_name> (<params>) from <roleVar>:<role> ( [|<plutus_code>|] )? do <individual_protocol> (<roleVar>) ({
<Trigger>*
})*;
```
*Example*:
```java
protocol PingPong (signed role P1, role P2) {
ping() from P1;
share subping() from peet : P2 do SubPingPong (peet);
}
individual protocol SubPingPong ( pet : P2 ){
subpong() from pet;
}
```
NOTE: Shared interactions count has endpoint calls for the individual protocol.
**Recursion**:
```java
rec <label> {
......@@ -103,8 +166,7 @@ NOTE: We advise having an interaction before the rec loop, as the compiler was d
**Choice**:
```java
choice from <Role>{
Label1: { ... }
Label2: { ... }
(<label> ( [|<plutus_code>|] )? : { ... })+
}
```
......@@ -112,7 +174,7 @@ choice from <Role>{
```java
choice at Seller {
AcceptOrder:
AcceptOrder[| ... |]:
{itemSold (String) from Seller;}
RejectOrder:
{orderFailed () from Seller;}
......@@ -145,39 +207,26 @@ interrupt {
**Storage**:
```java
field <Type>(,<Type>)*;
field <id>:<Var>(,<id>:<Var>)*;
```
*Example*:
```java
field ByteString, Value;
field byteStringVariable:ByteString, valueVariable:Value;
```
By default, a `Value`field is also stored, and manages the funds in the contract. Changing the `Value` field creates a transaction between the user interacting and the contract.
By default, a `Value` field is also stored, and manages the funds in the contract. Changing the `Value` field creates a transaction between the user interacting and the contract.
**Trigger**:
*Temporal:*:
```hs
trigger slot cancelGame;
trigger cancelGame ( : [|<plutus_code>|] )? ;
```
*Example*:
```java
lock (String,Value) from Owner {
trigger slot cancelGame;
};
```
*Funds:*:
```java
trigger funds cancelGame;
```
*Example*:
```java
lock (String,Value) from Owner {
trigger funds cancelGame;
trigger cancelGame;
};
```
......@@ -190,4 +239,86 @@ Due to how Plutus on-chain code functions, we only support certain types (that P
- `Ada`
- `Slot`
- `TokenName`
- `POSIXTime`
\ No newline at end of file
- `POSIXTime`
- `Bool`
### Business logic auxiliary functions ###
For the business logic definition, we provide auxiliary functions to aid the programmer in the development:
- `returnOk`
- `returnOkWith`
- `returnOutputOk`
- `returnError`
- `printMsg`
- `printError`
**`returnOk`**:
This function is useful if the programmer wishes to keep all variables' values.
*Example*:
```java
ping() from P1 [|returnOk|];
```
**`returnOkWith`**:
This function allows changes in some of the variable's values
*Example*:
```
protocol PingPong (role P1) {
field var1:Integer,var2:Integer,var3:Integer;
ping(newV:Integer) from P1[|
returnOkWith var1 newV var3 stateVal mempty
|];
}
```
NOTE: The last value is a Plutus constraint that the `ping`'s transition applies to a transaction. In this example, `mempty` means there is no constraint.
**`returnOutputOk`**:
This function does the same as `returnOkWith` but is more pratical. We recommend this function, especially if there is a large number of variables in the `field`.
*Example*:
```
protocol PingPong (role P1) {
field var1:Integer,var2:Integer,var3:Integer;
ping(newV:Integer) from P1[|
returnOutputOk $ setVar2 newV output
|];
}
```
The setter functions depend on the `field` variables declared. In the example above, the compiler creates the following setters:
- `setVar1`
- `setVar2`
- `setVar3`
Regardless of the `field` variables, the compiler always creates this two setters:
- `setStateVal`: Updates the smart contract's funds.
- `setConstraint`: Defines the Plutus constraint the endpoint uses for a transaction.
**`returnError`**: This function returns the endpoint in case of an error.
*Example*:
```java
ping() from P1 [|
returnError "Hi! I failed somewhere so im going to return with this error message."
|];
```
**`printMsg` & `printError`**
These two functions print, respectively, a normal message and an error message.
*Example:*
```java
ping() from P1 [|
printMsg "This is a message."
returnOk
|];
```
```java
ping() from P1 [|
printError "This is an error message."
returnOk
|];
```
\ No newline at end of file
protocol GuessingGame (role Owner, role Player) {
field storedSecret:ByteString;
lock (secret:String, prize:Value) from Owner[|
returnOutputOk $ setStoredSecret (sha2_256 $ toBuiltin $ C.pack secret)
$ setStateVal prize output
|];
guess (playerGuess:String) from Player[|
let attempt = toBuiltin $ C.pack playerGuess
if attempt == storedSecret
then returnOutputOk $ setStateVal mempty output
else returnError "Wrong guess, try again!"
|];
}
\ No newline at end of file
protocol Auction (signed role Seller, role Buyer) {
field currBid:Value,lastBidder:PubKeyHash,asset:Integer;
initialise (initBid:Value, assetToSell:Integer) from Seller[|returnOutputOk $ setCurrBid initBid
$ setLastBidder noKey
$ setAsset assetToSell output|]{
trigger closeAuctionTrigger:[|time >= timeStamp + 10000|];
};
do{
rec Loop {
bid (newBid:Value) from Buyer[|
pkh <- ownPaymentPubKeyHash
if (newBid `V.gt`mempty) && (newBid `V.gt`currBid)
then returnOutputOk $ if (lastBidder == noKey)
then setCurrBid newBid
$ setLastBidder pkh
$ setStateVal newBid output
else setCurrBid newBid
$ setLastBidder pkh
$ setStateVal newBid
$ setConstraint (Constraints.mustPayToPubKey lastBidder currBid) output
else returnError "Invalid Bid!"
|];
Loop;
}
} interrupt {
closeAuctionTrigger () from Contract[|returnOk|];
}
collectFundsAndGiveRewards () from Seller[|returnOutputOk $ setConstraint (Constraints.mustPayToPubKey (head sellerId) stateVal)
$ setStateVal mempty output|];
}
\ No newline at end of file
protocol Bargain (signed role Seller, role Buyer){
field item:Integer,currOffer:Value;
putForSale(itemToSell:Integer) from Seller [|
printMsg "Waiting for offers...."
returnOutputOk $ setItem itemToSell
$ setCurrOffer zeroLovelace output |];
rec Deal{
proposeOffer(offerProposal:Value) from Buyer [|
if currOffer == mempty
then if currOffer `V.geq` offerProposal
then returnError "There is already a bigger offer"
else returnOutputOk $ setCurrOffer offerProposal output
else returnOutputOk $ setCurrOffer offerProposal output |];
choice at Seller {
acceptOffer [|printMsg "Offer was accepted!"
returnOk
|]:{
payForItem(offerPayment:Value) from Buyer [|
if offerPayment /= currOffer
then returnError "Given value is not equal to the accepted offer!"
else do
printMsg "Executing the payment!"
returnOutputOk $ setStateVal (stateVal+offerPayment) output|];
}
refuseOffer [|
printMsg "Offer was refused!"
returnOk
|]:{
Deal;
}
}
}
}
\ No newline at end of file
protocol Crowdfunding (role Contributor, signed role Owner){
init () from Owner[|printMsg "Starting campaign"
returnOk|];
rec Loop {
choice at Owner{
continue [|returnOk|]: {
contribute (contribution:Value) from Contributor[|printMsg "Collecting funds"
returnOutputOk $ setStateVal (stateVal + contribution) output|];
Loop;
}
closeCrowdfund [|returnOk|]: {
collectFunds () from Owner[|printMsg "Collecting funds"
returnOutputOk $ setConstraint (Constraints.mustPayToPubKey (head ownerId) stateVal)
$ setStateVal mempty output|];
}
}
}
}
\ No newline at end of file
protocol BuyerSeller (role Buyer, role Seller){
field Integer;
orderInit (Integer) from Buyer;
field item:Integer;
orderInit (orderedItem:Integer) from Buyer;
choice at Seller {
AcceptOrder:
{itemSold (Integer) from Seller;}
{itemSold (soldItem:Integer) from Seller;}
RejectOrder:
{failedOrder () from Seller;}
}
......
protocol PurchasingGoods (role Buyer, role Seller, role CreditAgency){
Order(String, String) from Buyer;
Order(good:String, credit:String) from Buyer;
CheckBuyerCredit(String) from Seller;
CheckBuyerCredit(credit:String) from Seller;
choice at CreditAgency {
ValidRequest: {
CreditConfirm(String) from CreditAgency;
GeneratePurchaseInvoice(String, String) from Seller;
CreditConfirm(credit:String) from CreditAgency;
GeneratePurchaseInvoice(good:String, credit:String) from Seller;
}
InvalidRequest: {
......
protocol Auction (role Seller, role Buyer) {
// The ByteString is supposed to simbolize the Token being auctioned, Value is the minimum allowed bid
field Value,ByteString;
initialise (Value, ByteString) from Seller{
trigger slot closeAuctionTrigger;
field minBid:Value,tokenInAuction:ByteString;
initialise (initBid:Value, token:ByteString) from Seller{
trigger closeAuctionTrigger;
};
do{
rec Loop {
bid (Value) from Buyer;
bid (newBid:Value) from Buyer;
Loop;
}
} interrupt {
......
protocol GuessingGame(role Owner, role Participant) {
field ByteString;
field secret:ByteString;
lock (String,Value) from Owner{
trigger funds closeGame;
lock (secret:String,prize:Value) from Owner{
trigger closeGame;
};
do {
rec Loop {
guess (String) from Participant;
guess (guessWord:String) from Participant;
Loop;
}
}
......
protocol Convo(role Participant) {
startConversation (String) from Participant{
trigger slot makeNoise;
startConversation (msg:String) from Participant{
trigger makeNoise;
};
do {
rec Loop {
greet (String) from Participant;
respond (String) from Participant;
greet (msg:String) from Participant;
respond (msg:String) from Participant;
Loop;
}
}
......
protocol GuessingGame(role Owner, role Participant) {
field ByteString;
field secret:ByteString;
ola() from Owner;
rec outside {
......
protocol PurchasingGoods (role Buyer, role Seller, role CreditAgency){
Order(String, String) from Buyer;
Order(good:String, credit:String) from Buyer;
CheckBuyerCredit(String) from Seller;
CheckBuyerCredit(credit:String) from Seller;
choice at CreditAgency {
ValidRequest: {
CreditConfirm(String) from CreditAgency;
GeneratePurchaseInvoice(String, String) from Seller;
CreditConfirm(credit:String) from CreditAgency;
GeneratePurchaseInvoice(good:String, credit:String) from Seller;
}
ValidRequest: {
......
protocol ChoiceGuessingGame (role Owner, role Player) {
// Save the secret and the prize in the contract
field ByteString;
field secret:ByteString;
// the owner locks the secret and deposits a prize
lock (String, Value) from Owner;
lock (secret:String, prize:Value) from Owner;
choice at Owner {
proceedWithGame: { // the owner chooses to receive a guess
guess (String) from Player;
guess (guessWord:String) from Player;
}
cancelGame: { // the owner chooses to cancel the game
}
......
protocol StraightLineGuessingGame (role Owner, role Player) {
// Save the secret and the prize in the contract
field ByteString;
field secret:ByteString;
// the owner locks the secret and deposits a prize
lock (String, Value) from Owner;
lock (secret:String, prize:Value) from Owner;
// the player makes a guess
guess (String) from Player;
guess (guessWord:String) from Player;
// the owner closes the game (no further guesses allowed)
closeGame () from Owner;
}
\ No newline at end of file
protocol RecGuessingGame (role Owner, role Player) {
// Save the secret and the prize in the contract
field ByteString;
field secret:ByteString;
// the owner locks the secret and deposits a prize
lock (String, Value) from Owner;
lock (secret:String, prize:Value) from Owner;
rec Loop {
choice at Owner {
proceedWithGame : { // the owner chooses to receive another guess
guess (String) from Player;
guess (guessWord:String) from Player;
Loop;
}
cancelGame : { // the owner wants to cancel the game
......
protocol Race (signed role Organizer, role Racer){
beginRace() from Organizer;
share startRunning() from rac : Racer do RacerProtocol(rac);
endRace() from Organizer;
}
individual protocol RacerProtocol (human : Racer){
rec KeepRunning{
choice at human {
run : {
KeepRunning;
}
finishRace : {}
}
}
}
\ No newline at end of file
protocol Supermarket (signed role Owner, role Client){
openMarket() from Owner[|returnOk|];
share begin() from cli : Client [|returnOk|] do BuyingProcess(cli);
closeMarket() from Owner[|returnOk|];
}
individual protocol BuyingProcess (marketClient : Client){
field cart:[Integer];
rec Browsing{
choice at marketClient{
keepBrowsing[|returnOk|]:{
pick(item:Integer) from marketClient[|
returnOutputOk $ setCart (item:cart) output
|];
Browsing;
}
stopBrowsing[|returnOk|]:{
pay(total:Value) from marketClient[|
let totalVal = Ada.lovelaceValueOf $ (foldl (\tot next -> tot+next) 0 cart) * 10000
if total `V.geq` totalVal
then returnOutputOk $ setStateVal (stateVal + totalVal) output
else returnError "Your payment does not cover the total of your cart!"
|];
}
}
}
}
\ No newline at end of file
protocol BabyDao (role Participant, role Owner){
// Map the participants with the ammount of money they have
// and a tuple for the pending transaction
field [(PubKeyHash, Value)],(PubKeyHash,Value);
field participants:[(PubKeyHash, Value)],pendingTrans:(PubKeyHash,Value);
beginDAO() from Participant;
rec Loop {
choice at Participant {
donate : {
sendFundsToDAO (Value) from Participant;
increaseBalance (Value) from Participant;
sendFundsToDAO (funds:Value) from Participant;
increaseBalance (funds:Value) from Participant;
}
withdraw : {
sendFundsToParticipant (Value) from Participant;
reduceBalance (Value) from Participant;
sendFundsToParticipant (funds:Value) from Participant;
reduceBalance (funds:Value) from Participant;
}
}
Loop;
......
protocol NFTMarket(role Provider, role Client) {
field Integer; // the ammount of NFTs still remaining in the contract
field nftS:Integer; // the ammount of NFTs still remaining in the contract
startContract () from Provider;
rec Loop {
createNFT (String, Integer) from Provider {
trigger slot nftSaleExpiresTrigger;
createNFT (nftName:String, nft:Integer) from Provider {
trigger nftSaleExpiresTrigger;
};
do {
rec Market {
checkNFTPrice () from Client;
buyNFT(Integer) from Client;
buyNFT(nft:Integer) from Client;
Market;
}
} interrupt {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment