Contents:
Library ConCert.Examples.Crowdfunding.Crowdfunding
We develop a deep embedding of a crowdfunding contract and prove some of its functional correctness properties using the corresponding shallow embedding
From ConCert.Embedding Require Import Ast.
From ConCert.Embedding Require Import Notations.
From ConCert.Embedding Require Import PCUICTranslate.
From ConCert.Embedding Require Import Prelude.
From ConCert.Embedding Require Import SimpleBlockchain.
From ConCert.Embedding Require Import TranslationUtils.
From ConCert.Examples.Crowdfunding Require Import CrowdfundingData.
From Coq Require Import String.
From MetaCoq.Template Require Import All.
Import MCMonadNotation.
Import BaseTypes.
Open Scope list.
Import Prelude.Maps.
Note that we define the deep embedding (abstract syntax trees) of the data structures and programs using notations. These notations are defined in Ast.v and make use of the "custom entries" feature.
Brackets like [\ \] delimit the scope of data type definitions and like [| |] the scope of programs
The crowdfunding contract
AST of the init function
Module Init.
Import CrowdfundingData.Notations.
Definition crowdfunding_init : expr :=
[| \c : SCtx => \dl : Nat => \g : Money => mkState 0z MNil dl (ctx_from c) False g |].
MetaCoq Unquote Definition init :=
(expr_to_tc Σ' (indexify nil crowdfunding_init)).
(* Check init. *)
End Init.
Import CrowdfundingData.Notations.
Definition crowdfunding_init : expr :=
[| \c : SCtx => \dl : Nat => \g : Money => mkState 0z MNil dl (ctx_from c) False g |].
MetaCoq Unquote Definition init :=
(expr_to_tc Σ' (indexify nil crowdfunding_init)).
(* Check init. *)
End Init.
AST of the receive function
We specialise some polymorphic constructors to avoid writing types all the time
Notation "'#Just' a" := [| {eConstr (Utils.to_string_name <% option %>) "Some"} {eTy [! Result!]} {a}|]
(in custom expr at level 0,
a custom expr at level 1).
Notation "'#Pair' a b" := [| {eConstr Prod "pair"}
{eTy (tyInd State)}
{eTy actions_ty} {a} {b} |]
(in custom expr at level 0,
a custom expr at level 1,
b custom expr at level 1).
Notation "'#Nothing'" := (eApp (eConstr (Utils.to_string_name <% option %>) "None") (eTy [!Result!]))
(in custom expr at level 0).
Definition SCtx := Utils.to_string_name <% SimpleContractCallContext_coq %>.
Definition SChain := Utils.to_string_name <% SimpleChain_coq %>.
Definition crowdfunding : expr :=
[| \chain : SChain => \c : SCtx => \m : Msg => \s : State =>
let bal : Money := balance s in
let now : Nat := cur_time chain in
let tx_amount : Money := amount c in
let sender : Address := ctx_from c in
let own : Address := owner s in
let accs : Map := donations s in
case m : Msg return Maybe Result of
| GetFunds ->
if (own ==n sender) && (deadline s <n now) && (goal s <= bal) then
#Just (#Pair (mkState 0z accs own (deadline s) True (goal s))
[Transfer bal sender])
else #Nothing : Maybe Result
| Donate -> if now <=n deadline s then
(case (mfind accs sender) : Maybe Money return Maybe Result of
| Just v ->
let newmap : Map := madd sender (v + tx_amount) accs in
#Just (#Pair (mkState (tx_amount + bal) newmap own (deadline s) (done s) (goal s))
Nil)
| Nothing ->
let newmap : Map := madd sender tx_amount accs in
#Just (#Pair (mkState (tx_amount + bal) newmap own (deadline s) (done s) (goal s))
Nil))
else #Nothing : Maybe Result
| Claim ->
if (deadline s <n now) && (bal < goal s) && (~ done s) then
(case (mfind accs sender) : Maybe Money return Maybe Result of
| Just v -> let newmap : Map := madd sender 0z accs in
#Just (#Pair (mkState (bal-v) newmap own (deadline s) (done s) (goal s))
[Transfer v sender])
| Nothing -> #Nothing)
else #Nothing : Maybe Result
|].
MetaCoq Unquote Definition receive :=
(expr_to_tc Σ' (indexify nil crowdfunding)).
End Receive.
End CrowdfundingContract.
(in custom expr at level 0,
a custom expr at level 1).
Notation "'#Pair' a b" := [| {eConstr Prod "pair"}
{eTy (tyInd State)}
{eTy actions_ty} {a} {b} |]
(in custom expr at level 0,
a custom expr at level 1,
b custom expr at level 1).
Notation "'#Nothing'" := (eApp (eConstr (Utils.to_string_name <% option %>) "None") (eTy [!Result!]))
(in custom expr at level 0).
Definition SCtx := Utils.to_string_name <% SimpleContractCallContext_coq %>.
Definition SChain := Utils.to_string_name <% SimpleChain_coq %>.
Definition crowdfunding : expr :=
[| \chain : SChain => \c : SCtx => \m : Msg => \s : State =>
let bal : Money := balance s in
let now : Nat := cur_time chain in
let tx_amount : Money := amount c in
let sender : Address := ctx_from c in
let own : Address := owner s in
let accs : Map := donations s in
case m : Msg return Maybe Result of
| GetFunds ->
if (own ==n sender) && (deadline s <n now) && (goal s <= bal) then
#Just (#Pair (mkState 0z accs own (deadline s) True (goal s))
[Transfer bal sender])
else #Nothing : Maybe Result
| Donate -> if now <=n deadline s then
(case (mfind accs sender) : Maybe Money return Maybe Result of
| Just v ->
let newmap : Map := madd sender (v + tx_amount) accs in
#Just (#Pair (mkState (tx_amount + bal) newmap own (deadline s) (done s) (goal s))
Nil)
| Nothing ->
let newmap : Map := madd sender tx_amount accs in
#Just (#Pair (mkState (tx_amount + bal) newmap own (deadline s) (done s) (goal s))
Nil))
else #Nothing : Maybe Result
| Claim ->
if (deadline s <n now) && (bal < goal s) && (~ done s) then
(case (mfind accs sender) : Maybe Money return Maybe Result of
| Just v -> let newmap : Map := madd sender 0z accs in
#Just (#Pair (mkState (bal-v) newmap own (deadline s) (done s) (goal s))
[Transfer v sender])
| Nothing -> #Nothing)
else #Nothing : Maybe Result
|].
MetaCoq Unquote Definition receive :=
(expr_to_tc Σ' (indexify nil crowdfunding)).
End Receive.
End CrowdfundingContract.