{
  "note": "Every example compiles and its tests pass with the matching Elci version.",
  "examples": [
    {
      "name": "core-completion",
      "summary": "A function project: nested patterns, generic aliases, destructuring and structural equality.",
      "url": "https://github.com/bloxbean/elci-lang/tree/main/examples/core-completion",
      "files": {
        "elci.toml": "[project]\nsource-directories = [\"src\"]\ntarget = \"plutus-v3-pv11-uplc-1.1.0\"\njulc-version = \"0.1.0-pre20-ebaf028-SNAPSHOT\"\n\n[entrypoint]\nmodule = \"Main\"\nfunction = \"main\"\npurpose = \"function\"\nboundary = \"julc-strict-v1\"\n",
        "src/Main.elm": "module Main exposing (main)\n\n\ntype alias Box a =\n    { value : a, label : String }\n\n\ntype Choice a\n    = None\n    | Some a\n\n\nmeasure : Choice (List Int) -> Int\nmeasure choice =\n    case choice of\n        Some ([ first, second ] as items) ->\n            first + second + List.length items\n\n        Some [] ->\n            0\n\n        Some (_ :: _) ->\n            -1\n\n        None ->\n            -2\n\n\nunbox : ( Box Int, Int ) -> Int\nunbox ( { value }, extra ) =\n    value + extra\n\n\nsame : a -> a -> Bool\nsame left right =\n    left == right\n\n\nmain : Int\nmain =\n    let\n        boxed =\n            Box 4 \"four\"\n\n        { value } =\n            boxed\n\n        valuesMatch =\n            same [ value, 2 ] [ 4, 2 ]\n    in\n    if valuesMatch then\n        measure (Some [ value, 2 ]) + unbox ( boxed, 3 )\n\n    else\n        0\n"
      }
    },
    {
      "name": "custom-library",
      "summary": "Using a custom on-chain Java library packaged as a source JAR (library-jars), including a Java record type.",
      "url": "https://github.com/bloxbean/elci-lang/tree/main/examples/custom-library",
      "files": {
        "elci.toml": "[project]\nsource-directories = [\"src\"]\ntarget = \"plutus-v3-pv11-uplc-1.1.0\"\njulc-version = \"0.1.0-pre20-ebaf028-SNAPSHOT\"\nlibrary-jars = [\"build/pricing.jar\"]\n\n[entrypoint]\nmodule = \"Main\"\nfunction = \"main\"\npurpose = \"function\"\nboundary = \"julc-strict-v1\"\n\n[java-modules]\n\"Custom.Pricing\" = \"example.Pricing\"\n",
        "java/META-INF/plutus-sources/example/Pricing.java": "package example;\n\nimport java.math.BigInteger;\nimport org.julclang.stdlib.annotation.OnchainLibrary;\n\n@OnchainLibrary\npublic class Pricing {\n    public record Quote(BigInteger amount, boolean approved) {}\n\n    public static Quote quote(BigInteger amount) {\n        return new Quote(amount, true);\n    }\n\n    public static BigInteger total(Quote quote) {\n        return quote.amount();\n    }\n}\n",
        "README.md": "# Custom on-chain library\n\nFrom the repository root:\n\n```sh\nmkdir -p examples/custom-library/build\njar --create --file examples/custom-library/build/pricing.jar -C examples/custom-library/java .\n./gradlew installDist\nbuild/install/elci/bin/elci eval examples/custom-library\n```\n\nThe result is integer `42`. The native CLI accepts the same project and JAR:\n\n```sh\nbuild/native/elci eval examples/custom-library\n```\n\nThe JAR intentionally contains source only. Elci reads Java sources under\n`META-INF/plutus-sources/`, and Julc compiles the annotated library to PIR.\nIt does not load or execute JVM classes from the JAR. A normal compiled library\nJAR works too, provided it bundles those source resources and all required\ncustom type/library dependency sources.\n\n`Pricing.Quote` (or exposed `Quote`) is a nominal Java type. Its fields can be\nread, and values are created by the Java factory `Pricing.quote`. A structurally\nsimilar Elci record is not interchangeable with it.\n",
        "src/Main.elm": "module Main exposing (main)\n\nimport Custom.Pricing as Pricing exposing (Quote)\n\n\namount : Quote -> Int\namount quote =\n    quote.amount\n\n\nmain : Int\nmain =\n    amount (Pricing.quote 42)\n"
      }
    },
    {
      "name": "elci-library",
      "summary": "A library written in Elci in its own source directory, imported by the application like any module.",
      "url": "https://github.com/bloxbean/elci-lang/tree/main/examples/elci-library",
      "files": {
        "elci.toml": "[project]\nsource-directories = [\"src\", \"lib\"]\ntarget = \"plutus-v3-pv11-uplc-1.1.0\"\njulc-version = \"0.1.0-pre20-ebaf028-SNAPSHOT\"\n\n[entrypoint]\nmodule = \"Main\"\nfunction = \"main\"\npurpose = \"function\"\nboundary = \"julc-strict-v1\"\n",
        "lib/Finance/Pricing.elm": "module Finance.Pricing exposing (totalWithFee)\n\n\ntotalWithFee : Int -> List Int -> Int\ntotalWithFee fee prices =\n    subtotal prices + fee\n\n\nsubtotal : List Int -> Int\nsubtotal prices =\n    List.foldl (\\price total -> price + total) 0 prices\n",
        "README.md": "# A library written in Elci\n\n`lib/Finance/Pricing.elm` exports `totalWithFee` and keeps `subtotal` private.\nThe application in `src/Main.elm` imports the library normally. Both directories\nare listed in `elci.toml`; no Java module mapping or JAR is required.\n\nFrom the repository root:\n\n```sh\n./gradlew installDist\nbuild/install/elci/bin/elci eval examples/elci-library\n```\n\nThe result is integer `105`. The native CLI can run the same project:\n\n```sh\nbuild/native/elci eval examples/elci-library\n```\n\nShare the `lib` directory as source (for example in a Git repository), then add\nits path to the consuming project's `source-directories`. Module paths are\nrelative to that source root: `Finance.Pricing` must be `Finance/Pricing.elm`.\n",
        "src/Main.elm": "module Main exposing (main)\n\nimport Finance.Pricing as Pricing\n\n\nmain : Int\nmain =\n    Pricing.totalWithFee 5 [ 40, 60 ]\n"
      }
    },
    {
      "name": "escrow",
      "summary": "A buyer locks a payment for a seller, who is paid when the buyer approves; after a deadline the buyer may take it back:",
      "url": "https://github.com/bloxbean/elci-lang/tree/main/examples/escrow",
      "files": {
        "elci.toml": "[project]\nsource-directories = [\"src\"]\ntarget = \"plutus-v3-pv11-uplc-1.1.0\"\njulc-version = \"0.1.0-pre20-ebaf028-SNAPSHOT\"\n\n[validators.escrow]\nboundary = \"julc-strict-v1\"\nspend = \"Escrow.spend\"\n",
        "README.md": "# Escrow\n\nA buyer locks a payment for a seller, who is paid when the buyer approves; after a deadline\nthe buyer may take it back:\n\n- **Release**: the buyer signs, and the transaction pays the seller at least the price.\n- **Refund**: the buyer signs a transaction that runs entirely after the deadline.\n\nThe seller's payment must carry the escrow's output reference as its inline datum. Without\nthat tag, one payment could settle two escrows for the same seller in one transaction\n(double satisfaction). `doubleSatisfactionRejected` releases two escrows with one payment\nand fails; `paymentWithoutTagRejected` and `wrongTagRejected` show the tag is required.\n\nThe seller is identified by payment credential, so the buyer chooses the staking part of the\nseller's payment. A contract that must protect the seller's staking rights stores the\nseller's full address and compares it.\n\nIt uses `Tx.signedBy`, `Tx.outputsTo`, `Tx.inlineDatum`, `Tx.ownRef` and\n`Interval.isEntirelyAfter`.\n\n```sh\nelci test examples/escrow\nelci build examples/escrow\n```\n",
        "src/Escrow.elm": "module Escrow exposing (Action(..), Deal, spend)\n\n{-| A buyer locks a payment for a seller.\n\n  - **Release**: the buyer approves, and the seller is paid the price.\n  - **Refund**: after the deadline, the buyer takes the payment back.\n\nThe seller's payment must carry this escrow's output reference as its inline datum. Two\nescrows for the same seller spent in one transaction would otherwise be satisfied by a\nsingle payment (the \"double satisfaction\" attack).\n\n-}\n\nimport Interval\nimport Julc.Data as Data\nimport Julc.Ledger exposing (Credential(..), PubKeyHash, ScriptContext)\nimport Tx\nimport Value\n\n\ntype alias Deal =\n    { buyer : PubKeyHash\n    , seller : PubKeyHash\n    , price : Int\n    , deadline : Int\n    }\n\n\ntype Action\n    = Release\n    | Refund\n\n\nspend : Deal -> Action -> ScriptContext -> Bool\nspend deal action ctx =\n    case action of\n        Release ->\n            Tx.signedBy deal.buyer ctx && sellerPaid deal ctx\n\n        Refund ->\n            Tx.signedBy deal.buyer ctx && Interval.isEntirelyAfter deal.deadline ctx.txInfo.validRange\n\n\n{-| An output to the seller of at least the price, tagged with this escrow's reference.\n-}\nsellerPaid : Deal -> ScriptContext -> Bool\nsellerPaid deal ctx =\n    case Tx.ownRef ctx of\n        Just ref ->\n            List.any\n                (\\output ->\n                    (Value.lovelaceOf output.value >= deal.price)\n                        && (Tx.inlineDatum output == Just (Data.encode ref))\n                )\n                (Tx.outputsTo (PubKeyCredential deal.seller) ctx)\n\n        Nothing ->\n            False\n",
        "tests/EscrowTest.elm": "module EscrowTest exposing\n    ( buyerRefundsAfterTheDeadline\n    , doubleSatisfactionRejected\n    , paymentWithoutTagRejected\n    , refundBeforeTheDeadlineRejected\n    , refundIsLateEnough\n    , refundWithoutBuyerRejected\n    , releasePaysTheSeller\n    , releaseWithoutBuyerRejected\n    , underpaymentRejected\n    , wrongTagRejected\n    )\n\nimport Escrow exposing (Action(..), Deal)\nimport Julc.Data as Data\nimport Property exposing (Property)\nimport Scenario exposing (Scenario)\n\n\ndeal : Deal\ndeal =\n    { buyer = Scenario.key \"buyer\"\n    , seller = Scenario.key \"seller\"\n    , price = 25000000\n    , deadline = 1700000000000\n    }\n\n\nescrow : Int -> Scenario\nescrow index =\n    Scenario.spend \"escrow\" (Scenario.outRef \"escrow\" index) (Data.encode deal)\n\n\ntag : Int -> Data.Data\ntag index =\n    Data.encode (Scenario.outRef \"escrow\" index)\n\n\nrelease : Scenario\nrelease =\n    escrow 0\n        |> Scenario.redeemer (Data.encode Release)\n        |> Scenario.signedBy deal.buyer\n        |> Scenario.output (Scenario.toKey deal.seller deal.price |> Scenario.withDatum (tag 0))\n\n\nreleasePaysTheSeller : Scenario\nreleasePaysTheSeller =\n    release\n\n\nreleaseWithoutBuyerRejected : Scenario\nreleaseWithoutBuyerRejected =\n    escrow 0\n        |> Scenario.redeemer (Data.encode Release)\n        |> Scenario.output (Scenario.toKey deal.seller deal.price |> Scenario.withDatum (tag 0))\n        |> Scenario.expectFailure\n\n\nunderpaymentRejected : Scenario\nunderpaymentRejected =\n    escrow 0\n        |> Scenario.redeemer (Data.encode Release)\n        |> Scenario.signedBy deal.buyer\n        |> Scenario.output (Scenario.toKey deal.seller (deal.price - 1) |> Scenario.withDatum (tag 0))\n        |> Scenario.expectFailure\n\n\npaymentWithoutTagRejected : Scenario\npaymentWithoutTagRejected =\n    escrow 0\n        |> Scenario.redeemer (Data.encode Release)\n        |> Scenario.signedBy deal.buyer\n        |> Scenario.output (Scenario.toKey deal.seller deal.price)\n        |> Scenario.expectFailure\n\n\n{-| A payment tagged for another escrow does not settle this one.\n-}\nwrongTagRejected : Scenario\nwrongTagRejected =\n    escrow 0\n        |> Scenario.redeemer (Data.encode Release)\n        |> Scenario.signedBy deal.buyer\n        |> Scenario.output (Scenario.toKey deal.seller deal.price |> Scenario.withDatum (tag 1))\n        |> Scenario.expectFailure\n\n\n{-| Two escrows for the same seller released together with one payment, tagged for the\nfirst: the second is not paid for.\n-}\ndoubleSatisfactionRejected : Scenario\ndoubleSatisfactionRejected =\n    escrow 1\n        |> Scenario.input (Scenario.outRef \"escrow\" 0) (Scenario.toScript deal.price |> Scenario.withDatum (Data.encode deal))\n        |> Scenario.redeemer (Data.encode Release)\n        |> Scenario.signedBy deal.buyer\n        |> Scenario.output (Scenario.toKey deal.seller deal.price |> Scenario.withDatum (tag 0))\n        |> Scenario.expectFailure\n\n\nrefund : Int -> Scenario\nrefund validFrom =\n    escrow 0\n        |> Scenario.redeemer (Data.encode Refund)\n        |> Scenario.signedBy deal.buyer\n        |> Scenario.validFrom validFrom\n\n\nbuyerRefundsAfterTheDeadline : Scenario\nbuyerRefundsAfterTheDeadline =\n    refund (deal.deadline + 1)\n\n\nrefundWithoutBuyerRejected : Scenario\nrefundWithoutBuyerRejected =\n    escrow 0\n        |> Scenario.redeemer (Data.encode Refund)\n        |> Scenario.signedBy deal.seller\n        |> Scenario.validFrom (deal.deadline + 1)\n        |> Scenario.expectFailure\n\n\nrefundBeforeTheDeadlineRejected : Scenario\nrefundBeforeTheDeadlineRejected =\n    refund deal.deadline |> Scenario.expectFailure\n\n\n{-| A refund is accepted exactly when the transaction cannot run at or before the deadline.\n-}\nrefundIsLateEnough : Int -> Property\nrefundIsLateEnough offset =\n    let\n        start =\n            deal.deadline + modBy 2001 offset - 1000\n\n        scenario =\n            refund start\n    in\n    Property.scenario\n        (if start > deal.deadline then\n            scenario\n\n         else\n            Scenario.expectFailure scenario\n        )\n"
      }
    },
    {
      "name": "functional",
      "summary": "A function project: custom types and list traversal, run with elci eval.",
      "url": "https://github.com/bloxbean/elci-lang/tree/main/examples/functional",
      "files": {
        "elci.toml": "[project]\nsource-directories = [\"src\"]\ntarget = \"plutus-v3-pv11-uplc-1.1.0\"\njulc-version = \"0.1.0-pre20-ebaf028-SNAPSHOT\"\n\n[entrypoint]\nmodule = \"Main\"\nfunction = \"main\"\npurpose = \"function\"\nboundary = \"julc-strict-v1\"\n",
        "src/Main.elm": "module Main exposing (main)\n\n\ntype Tree\n    = Leaf Int\n    | Branch Tree Tree\n\n\ntotal : Tree -> Int\ntotal tree =\n    case tree of\n        Leaf amount ->\n            amount\n\n        Branch left right ->\n            total left + total right\n\n\nmain : Int\nmain =\n    [ Branch (Leaf 3) (Leaf 4), Leaf 5 ]\n        |> List.map total\n        |> List.foldl (\\amount sum -> amount + sum) 0\n"
      }
    },
    {
      "name": "marketplace",
      "summary": "A seller locks an NFT with a listing (seller and price in lovelace). Anyone may buy it by paying the seller the price less the marketplace's fee and paying the operator the fee, both tagged with the listing's output reference. The seller may cancel.",
      "url": "https://github.com/bloxbean/elci-lang/tree/main/examples/marketplace",
      "files": {
        "elci.toml": "[project]\nsource-directories = [\"src\"]\ntarget = \"plutus-v3-pv11-uplc-1.1.0\"\njulc-version = \"0.1.0-pre20-ebaf028-SNAPSHOT\"\n\n[validators.marketplace]\nboundary = \"julc-strict-v1\"\nparameters = [\"market\"]\nspend = \"Marketplace.spend\"\n",
        "README.md": "# NFT marketplace\n\nA seller locks an NFT with a listing (seller and price in lovelace). Anyone may buy it by\npaying the seller the price less the marketplace's fee and paying the operator the fee,\nboth tagged with the listing's output reference. The seller may cancel.\n\n- The tag keeps one pair of payments from buying two listings\n  (`onePaymentForTwoListingsRejected`, `untaggedPaymentRejected`).\n- An operator selling their own NFT is owed the whole price, in one tagged output\n  (`operatorSellingIsPaidInFull`).\n- A fee outside 0 to 10000 basis points rejects every purchase (`feeOutOfRangeRejected`,\n  `negativeFeeRejected`).\n- The buyer takes everything in the listing's output: the NFT, the lovelace the ledger\n  requires with it, and anything else the seller locked there. A marketplace that wants the\n  lovelace returned to the seller adds it to the seller's payment.\n- Payees are identified by payment credential, so the buyer chooses the staking part of\n  each payment.\n\nThe marketplace (operator and fee in basis points) is a deployment parameter:\n\n```sh\nelci test examples/marketplace\nelci build examples/marketplace\n```\n\nIt uses `Tx.ownRef`, `Tx.outputsTo`, `Tx.inlineDatum`, `Tx.signedBy` and `Value.lovelaceOf`,\nand exact integer arithmetic for the fee: `fee` rounds down. The property\n`buyingPaysExactly` checks, at any price and fee, that the exact split buys the NFT and one\nlovelace less to the seller does not.\n",
        "src/Marketplace.elm": "module Marketplace exposing (Action(..), Listing, Market, fee, spend)\n\n{-| An NFT marketplace. A seller locks an NFT with a listing; anyone may buy it by paying\nthe seller the price, less the marketplace's fee, and paying the operator the fee. The\nseller may cancel at any time.\n\nEach payment carries the listing's output reference as its inline datum, so one payment\ncannot settle two listings in the same transaction. The buyer takes everything in the\nlisting's output: the NFT, the lovelace the ledger requires with it, and anything else the\nseller locked there.\n\n-}\n\nimport Julc.Data as Data\nimport Julc.Ledger exposing (Credential(..), PubKeyHash, ScriptContext, TxOutRef)\nimport Tx\nimport Value\n\n\n{-| The marketplace, fixed when the script is deployed. The fee is in basis points, from 0 to\n10000; a script deployed with any other fee rejects every purchase.\n-}\ntype alias Market =\n    { operator : PubKeyHash\n    , feeBasisPoints : Int\n    }\n\n\n{-| A listing: who sells, and for how much lovelace.\n-}\ntype alias Listing =\n    { seller : PubKeyHash\n    , price : Int\n    }\n\n\ntype Action\n    = Buy\n    | Cancel\n\n\nspend : Market -> Listing -> Action -> ScriptContext -> Bool\nspend market listing action ctx =\n    case action of\n        Buy ->\n            case Tx.ownRef ctx of\n                Just ref ->\n                    let\n                        cut =\n                            fee market listing.price\n\n                        -- An operator selling their own NFT is owed the whole price in one payment.\n                        owed =\n                            if listing.seller == market.operator then\n                                listing.price\n\n                            else\n                                listing.price - cut\n                    in\n                    (market.feeBasisPoints >= 0)\n                        && (market.feeBasisPoints <= 10000)\n                        && paid listing.seller owed ref ctx\n                        && (cut == 0 || paid market.operator cut ref ctx)\n\n                Nothing ->\n                    False\n\n        Cancel ->\n            Tx.signedBy listing.seller ctx\n\n\n{-| The marketplace's fee, rounded down.\n-}\nfee : Market -> Int -> Int\nfee market price =\n    price * market.feeBasisPoints // 10000\n\n\n{-| Whether an output pays the key at least the amount, tagged with the listing's reference.\n-}\npaid : PubKeyHash -> Int -> TxOutRef -> ScriptContext -> Bool\npaid key amount ref ctx =\n    List.any\n        (\\output ->\n            (Value.lovelaceOf output.value >= amount)\n                && (Tx.inlineDatum output == Just (Data.encode ref))\n        )\n        (Tx.outputsTo (PubKeyCredential key) ctx)\n",
        "tests/MarketplaceTest.elm": "module MarketplaceTest exposing\n    ( buyPaysSellerAndOperator\n    , buyWithoutFeeRejected\n    , buyingPaysExactly\n    , cancelByOtherRejected\n    , cancelBySeller\n    , feeOutOfRangeRejected\n    , feeRoundsDown\n    , negativeFeeRejected\n    , onePaymentForTwoListingsRejected\n    , operatorSellingIsPaidInFull\n    , operatorSellingShortchangedRejected\n    , sellerShortchangedRejected\n    , untaggedPaymentRejected\n    )\n\nimport Julc.Data as Data\nimport Marketplace exposing (Action(..), Listing, Market)\nimport Property exposing (Property)\nimport Scenario exposing (Scenario)\n\n\nmarket : Market\nmarket =\n    { operator = Scenario.key \"operator\", feeBasisPoints = 250 }\n\n\nlisting : Listing\nlisting =\n    { seller = Scenario.key \"seller\", price = 100000000 }\n\n\ntag : Data.Data\ntag =\n    Data.encode (Scenario.outRef \"listing\" 0)\n\n\nbuy : Int -> Int -> Scenario\nbuy toSeller toOperator =\n    Scenario.spend \"marketplace\" (Scenario.outRef \"listing\" 0) (Data.encode listing)\n        |> Scenario.parameters [ Data.encode market ]\n        |> Scenario.redeemer (Data.encode Buy)\n        |> Scenario.output (Scenario.toKey listing.seller toSeller |> Scenario.withDatum tag)\n        |> Scenario.output (Scenario.toKey market.operator toOperator |> Scenario.withDatum tag)\n\n\nbuyPaysSellerAndOperator : Scenario\nbuyPaysSellerAndOperator =\n    buy 97500000 2500000\n\n\nbuyWithoutFeeRejected : Scenario\nbuyWithoutFeeRejected =\n    buy 97500000 2499999 |> Scenario.expectFailure\n\n\nsellerShortchangedRejected : Scenario\nsellerShortchangedRejected =\n    buy 97499999 2500000 |> Scenario.expectFailure\n\n\n{-| Two listings by one seller, bought together with one pair of payments tagged for the\nfirst: the second is not paid for.\n-}\nonePaymentForTwoListingsRejected : Scenario\nonePaymentForTwoListingsRejected =\n    Scenario.spend \"marketplace\" (Scenario.outRef \"listing\" 1) (Data.encode listing)\n        |> Scenario.parameters [ Data.encode market ]\n        |> Scenario.redeemer (Data.encode Buy)\n        |> Scenario.input (Scenario.outRef \"listing\" 0) (Scenario.toScript 2000000 |> Scenario.withDatum (Data.encode listing))\n        |> Scenario.output (Scenario.toKey listing.seller 97500000 |> Scenario.withDatum tag)\n        |> Scenario.output (Scenario.toKey market.operator 2500000 |> Scenario.withDatum tag)\n        |> Scenario.expectFailure\n\n\nuntaggedPaymentRejected : Scenario\nuntaggedPaymentRejected =\n    Scenario.spend \"marketplace\" (Scenario.outRef \"listing\" 0) (Data.encode listing)\n        |> Scenario.parameters [ Data.encode market ]\n        |> Scenario.redeemer (Data.encode Buy)\n        |> Scenario.output (Scenario.toKey listing.seller 97500000)\n        |> Scenario.output (Scenario.toKey market.operator 2500000)\n        |> Scenario.expectFailure\n\n\n{-| The operator selling their own NFT, paid in one output.\n-}\noperatorSells : Int -> Scenario\noperatorSells amount =\n    Scenario.spend \"marketplace\" (Scenario.outRef \"listing\" 0) (Data.encode { listing | seller = market.operator })\n        |> Scenario.parameters [ Data.encode market ]\n        |> Scenario.redeemer (Data.encode Buy)\n        |> Scenario.output (Scenario.toKey market.operator amount |> Scenario.withDatum tag)\n\n\noperatorSellingIsPaidInFull : Scenario\noperatorSellingIsPaidInFull =\n    operatorSells 100000000\n\n\noperatorSellingShortchangedRejected : Scenario\noperatorSellingShortchangedRejected =\n    operatorSells 97500000 |> Scenario.expectFailure\n\n\n{-| A purchase that pays the seller and operator what a fee of `basisPoints` would ask.\n-}\nbuyAtFee : Int -> Scenario\nbuyAtFee basisPoints =\n    let\n        charging =\n            { market | feeBasisPoints = basisPoints }\n\n        cut =\n            Marketplace.fee charging listing.price\n    in\n    Scenario.spend \"marketplace\" (Scenario.outRef \"listing\" 0) (Data.encode listing)\n        |> Scenario.parameters [ Data.encode charging ]\n        |> Scenario.redeemer (Data.encode Buy)\n        |> Scenario.output (Scenario.toKey listing.seller (max 1000000 (listing.price - cut)) |> Scenario.withDatum tag)\n        |> Scenario.output (Scenario.toKey market.operator (max 1000000 cut) |> Scenario.withDatum tag)\n\n\n{-| A marketplace deployed with a fee over 100% rejects every purchase, even one that pays\nwhat that fee asks.\n-}\nfeeOutOfRangeRejected : Scenario\nfeeOutOfRangeRejected =\n    buyAtFee 10001 |> Scenario.expectFailure\n\n\nnegativeFeeRejected : Scenario\nnegativeFeeRejected =\n    buyAtFee -1 |> Scenario.expectFailure\n\n\ncancel : String -> Scenario\ncancel signer =\n    Scenario.spend \"marketplace\" (Scenario.outRef \"listing\" 0) (Data.encode listing)\n        |> Scenario.parameters [ Data.encode market ]\n        |> Scenario.redeemer (Data.encode Cancel)\n        |> Scenario.signedBy (Scenario.key signer)\n\n\ncancelBySeller : Scenario\ncancelBySeller =\n    cancel \"seller\"\n\n\ncancelByOtherRejected : Scenario\ncancelByOtherRejected =\n    cancel \"thief\" |> Scenario.expectFailure\n\n\nfeeRoundsDown : Bool\nfeeRoundsDown =\n    Marketplace.fee { operator = market.operator, feeBasisPoints = 250 } 399 == 9\n\n\n{-| At any price and fee below 100%, paying the seller exactly the price less the fee and\nthe operator the fee buys the NFT; one lovelace less to the seller does not.\n-}\nbuyingPaysExactly : Int -> Int -> Bool -> Property\nbuyingPaysExactly rawPrice rawBasisPoints short =\n    let\n        priced =\n            { listing | price = modBy 1000000000 (abs rawPrice) + 1 }\n\n        charging =\n            { market | feeBasisPoints = modBy 10000 rawBasisPoints }\n\n        cut =\n            Marketplace.fee charging priced.price\n\n        toSeller =\n            if short then\n                priced.price - cut - 1\n\n            else\n                priced.price - cut\n\n        scenario =\n            Scenario.spend \"marketplace\" (Scenario.outRef \"listing\" 0) (Data.encode priced)\n                |> Scenario.parameters [ Data.encode charging ]\n                |> Scenario.redeemer (Data.encode Buy)\n                |> Scenario.output (Scenario.toKey priced.seller toSeller |> Scenario.withDatum tag)\n                |> Scenario.output (Scenario.toKey charging.operator cut |> Scenario.withDatum tag)\n    in\n    Property.scenario\n        (if short then\n            Scenario.expectFailure scenario\n\n         else\n            scenario\n        )\n"
      }
    },
    {
      "name": "order-swap",
      "summary": "A limit order: a maker locks GOLD tokens and asks 3 SILVER for each. A taker fills any part of it by paying the maker. The maker may cancel. Only the offered token is for sale:",
      "url": "https://github.com/bloxbean/elci-lang/tree/main/examples/order-swap",
      "files": {
        "elci.toml": "[project]\nsource-directories = [\"src\"]\ntarget = \"plutus-v3-pv11-uplc-1.1.0\"\njulc-version = \"0.1.0-pre20-ebaf028-SNAPSHOT\"\n\n[validators.swap]\nboundary = \"julc-strict-v1\"\nspend = \"Swap.spend\"\n",
        "README.md": "# Order swap\n\nA limit order: a maker locks GOLD tokens and asks 3 SILVER for each. A taker fills any part\nof it by paying the maker. The maker may cancel. Only the offered token is for sale:\n\n- A partial fill must return everything else in the order to the script under the same\n  order datum: the remaining GOLD, the lovelace and any other tokens\n  (`partialFillMustReturnEverything`, `partialFillMustReturnTheOtherTokens`).\n- The returned order holds exactly those tokens and no others (`junkTokensRejected`), so\n  no one can pad an order until its full fill no longer fits in one output.\n- A full fill pays the maker the price and everything the order held besides the GOLD\n  (`fullFillMustPayTheDeposit`, `fullFillMustPayTheOtherTokens`).\n- The returned order must be the same order (`changedOrderRejected`).\n- The maker sets the price; a price of 0 or less gives the GOLD away.\n\nTwo rules keep one output from counting twice:\n\n- The maker's payment carries the order's output reference as its inline datum\n  (`untaggedPaymentRejected`, `wrongTagRejected`).\n- A fill may spend only one input of this script, whatever its staking part, so one\n  returned output cannot stand for two orders (`secondOrderInTheSameTransactionRejected`,\n  `secondOrderUnderAnotherStakeRejected`).\n\nThe maker is identified by payment credential, so the taker chooses the staking part of the\nmaker's payment. A contract that must protect the maker's staking rights stores the maker's\nfull address and compares it.\n\nIt uses `Tx.ownInput`, `Tx.continuingOutputs`, `Tx.outputsTo`, `Tx.inlineDatum`,\n`Value.geq` and `Value.withoutLovelace`. The property `fillsAreChecked` covers every fill size with exact and short\npayments.\n\n```sh\nelci test examples/order-swap\n```\n",
        "src/Swap.elm": "module Swap exposing (Action(..), Order, spend)\n\n{-| A limit order. A maker locks tokens and asks for other tokens at a fixed price. A taker\nfills all or part of it by paying the maker; a partial fill must return everything else in\nthe order, lovelace and other tokens included, to the script under the same order. A full\nfill pays the maker the price and everything the order held besides the offered tokens.\nThe maker may cancel.\n\n  - The maker's payment carries the order's output reference as its inline datum, so one\n    payment cannot fill two orders.\n  - The transaction may spend only one input of this script, so one returned output\n    cannot stand for two orders either.\n\n-}\n\nimport Julc.Data as Data\nimport Julc.Ledger exposing (Credential(..), PolicyId, PubKeyHash, ScriptContext, TokenName, TxInInfo, TxOutRef)\nimport Tx\nimport Value exposing (Value)\n\n\n{-| The maker offers one token and asks `price` of another for each unit.\n-}\ntype alias Order =\n    { maker : PubKeyHash\n    , offerPolicy : PolicyId\n    , offerName : TokenName\n    , askPolicy : PolicyId\n    , askName : TokenName\n    , price : Int\n    }\n\n\ntype Action\n    = Take Int\n    | Cancel\n\n\nspend : Order -> Action -> ScriptContext -> Bool\nspend order action ctx =\n    case action of\n        Cancel ->\n            Tx.signedBy order.maker ctx\n\n        Take amount ->\n            case Tx.ownInput ctx of\n                Just own ->\n                    fill order amount own ctx\n\n                Nothing ->\n                    False\n\n\nfill : Order -> Int -> TxInInfo -> ScriptContext -> Bool\nfill order amount own ctx =\n    let\n        offered =\n            Value.quantityOf order.offerPolicy order.offerName own.resolved.value\n\n        rest =\n            Value.subtract own.resolved.value (Value.singleton order.offerPolicy order.offerName amount)\n\n        payment =\n            Value.singleton order.askPolicy order.askName (amount * order.price)\n    in\n    (amount > 0)\n        && (amount <= offered)\n        && onlyScriptInput own ctx\n        && (if amount == offered then\n                makerPaid order (Value.add payment rest) own.outRef ctx\n\n            else\n                makerPaid order payment own.outRef ctx && restReturned order rest ctx\n           )\n\n\n{-| Whether this is the only input from the script.\n-}\nonlyScriptInput : TxInInfo -> ScriptContext -> Bool\nonlyScriptInput own ctx =\n    List.length (List.filter (\\input -> input.resolved.address.credential == own.resolved.address.credential) ctx.txInfo.inputs) == 1\n\n\nmakerPaid : Order -> Value -> TxOutRef -> ScriptContext -> Bool\nmakerPaid order owed ref ctx =\n    List.any\n        (\\output -> Value.geq output.value owed && (Tx.inlineDatum output == Just (Data.encode ref)))\n        (Tx.outputsTo (PubKeyCredential order.maker) ctx)\n\n\n{-| Whether one output returns `rest` to the script under the same order: at least its\nlovelace, and exactly its tokens, so no one can fill the order with other tokens until it\nno longer fits in one output.\n-}\nrestReturned : Order -> Value -> ScriptContext -> Bool\nrestReturned order rest ctx =\n    case Tx.continuingOutputs ctx of\n        [ output ] ->\n            (Value.lovelaceOf output.value >= Value.lovelaceOf rest)\n                && (Value.withoutLovelace output.value == Value.withoutLovelace rest)\n                && (Tx.inlineDatum output == Just (Data.encode order))\n\n        _ ->\n            False\n",
        "tests/SwapTest.elm": "module SwapTest exposing\n    ( cancelByMaker\n    , cancelByOtherRejected\n    , changedOrderRejected\n    , fillCompletely\n    , fillPartially\n    , fillsAreChecked\n    , fullFillMustPayTheDeposit\n    , fullFillMustPayTheOtherTokens\n    , fullFillPaysTheDeposit\n    , junkTokensRejected\n    , overfillRejected\n    , partialFillMustReturnEverything\n    , partialFillMustReturnTheOtherTokens\n    , partialFillMustReturnTheRest\n    , partialFillReturnsEverything\n    , secondOrderInTheSameTransactionRejected\n    , secondOrderUnderAnotherStakeRejected\n    , underpaidRejected\n    , untaggedPaymentRejected\n    , wrongTagRejected\n    , zeroTakeRejected\n    )\n\nimport Bytes\nimport Julc.Data as Data\nimport Julc.Ledger exposing (Credential(..), PolicyId(..), StakingCredential(..), TokenName(..))\nimport Property exposing (Property)\nimport Scenario exposing (Policy(..), Scenario)\nimport Swap exposing (Action(..), Order)\n\n\ngold : Bytes\ngold =\n    Bytes.fromString \"gold-policy-0123456789abcdef\"\n\n\nsilver : Bytes\nsilver =\n    Bytes.fromString \"silver-policy-0123456789abcd\"\n\n\norder : Order\norder =\n    { maker = Scenario.key \"maker\"\n    , offerPolicy = PolicyId gold\n    , offerName = TokenName (Bytes.fromString \"GOLD\")\n    , askPolicy = PolicyId silver\n    , askName = TokenName (Bytes.fromString \"SILVER\")\n    , price = 3\n    }\n\n\n{-| The order's output: 10 GOLD at the script.\n-}\nlocked : Int -> Scenario -> Scenario\nlocked index =\n    Scenario.input (Scenario.outRef \"order\" index)\n        (Scenario.toScript 2000000\n            |> Scenario.withToken (Policy gold) (Bytes.fromString \"GOLD\") 10\n            |> Scenario.withDatum (Data.encode order)\n        )\n\n\ntake : Int -> Int -> Scenario\ntake amount payment =\n    Scenario.spend \"swap\" (Scenario.outRef \"order\" 0) (Data.encode order)\n        |> locked 0\n        |> Scenario.redeemer (Data.encode (Take amount))\n        |> Scenario.output\n            (Scenario.toKey order.maker 2000000\n                |> Scenario.withToken (Policy silver) (Bytes.fromString \"SILVER\") payment\n                |> Scenario.withDatum (Data.encode (Scenario.outRef \"order\" 0))\n            )\n\n\nrest : Int -> Scenario -> Scenario\nrest quantity =\n    Scenario.output\n        (Scenario.toScript 2000000\n            |> Scenario.withToken (Policy gold) (Bytes.fromString \"GOLD\") quantity\n            |> Scenario.withDatum (Data.encode order)\n        )\n\n\nfillCompletely : Scenario\nfillCompletely =\n    take 10 30\n\n\nfillPartially : Scenario\nfillPartially =\n    take 4 12 |> rest 6\n\n\npartialFillMustReturnTheRest : Scenario\npartialFillMustReturnTheRest =\n    take 4 12 |> Scenario.expectFailure\n\n\nunderpaidRejected : Scenario\nunderpaidRejected =\n    take 10 29 |> Scenario.expectFailure\n\n\noverfillRejected : Scenario\noverfillRejected =\n    take 11 33 |> Scenario.expectFailure\n\n\n{-| Two orders spent together cannot share one returned output.\n-}\nsecondOrderInTheSameTransactionRejected : Scenario\nsecondOrderInTheSameTransactionRejected =\n    take 4 12 |> rest 6 |> locked 1 |> Scenario.expectFailure\n\n\n{-| A richer order: 100 ADA, 10 GOLD and 5 BONUS. Only GOLD is for sale.\n-}\nrich : Scenario -> Scenario\nrich =\n    Scenario.input (Scenario.outRef \"order\" 0)\n        (Scenario.toScript 100000000\n            |> Scenario.withToken (Policy gold) (Bytes.fromString \"GOLD\") 10\n            |> Scenario.withToken (Policy gold) (Bytes.fromString \"BONUS\") 5\n            |> Scenario.withDatum (Data.encode order)\n        )\n\n\ntakeRich : Int -> Scenario\ntakeRich amount =\n    Scenario.spend \"swap\" (Scenario.outRef \"order\" 0) (Data.encode order)\n        |> rich\n        |> Scenario.redeemer (Data.encode (Take amount))\n\n\n{-| The maker's payment, tagged with the order: lovelace, SILVER and BONUS.\n-}\npaid : Int -> Int -> Int -> Scenario -> Scenario\npaid lovelace silverAmount bonus =\n    Scenario.output\n        (Scenario.toKey order.maker lovelace\n            |> Scenario.withToken (Policy silver) (Bytes.fromString \"SILVER\") silverAmount\n            |> Scenario.withToken (Policy gold) (Bytes.fromString \"BONUS\") bonus\n            |> Scenario.withDatum (Data.encode (Scenario.outRef \"order\" 0))\n        )\n\n\n{-| What a partial fill returns to the script: lovelace, GOLD and BONUS.\n-}\nreturned : Int -> Int -> Int -> Scenario -> Scenario\nreturned lovelace quantity bonus =\n    Scenario.output\n        (Scenario.toScript lovelace\n            |> Scenario.withToken (Policy gold) (Bytes.fromString \"GOLD\") quantity\n            |> Scenario.withToken (Policy gold) (Bytes.fromString \"BONUS\") bonus\n            |> Scenario.withDatum (Data.encode order)\n        )\n\n\npartialFillReturnsEverything : Scenario\npartialFillReturnsEverything =\n    takeRich 1 |> paid 1500000 3 0 |> returned 100000000 9 5\n\n\n{-| A taker who returns the GOLD but keeps the lovelace and the BONUS tokens is rejected.\n-}\npartialFillMustReturnEverything : Scenario\npartialFillMustReturnEverything =\n    takeRich 1 |> paid 1500000 3 0 |> returned 1500000 9 0 |> Scenario.expectFailure\n\n\n{-| Returning all the lovelace but keeping one BONUS is rejected too.\n-}\npartialFillMustReturnTheOtherTokens : Scenario\npartialFillMustReturnTheOtherTokens =\n    takeRich 1 |> paid 1500000 3 0 |> returned 100000000 9 4 |> Scenario.expectFailure\n\n\n{-| A returned order padded with other tokens is rejected, so no one can grow the order\nuntil its full fill no longer fits in one output.\n-}\njunkTokensRejected : Scenario\njunkTokensRejected =\n    takeRich 1 |> paid 1500000 3 0 |> returned 100000000 9 6 |> Scenario.expectFailure\n\n\nfullFillPaysTheDeposit : Scenario\nfullFillPaysTheDeposit =\n    takeRich 10 |> paid 100000000 30 5\n\n\n{-| A taker who pays the price but keeps the order's lovelace is rejected.\n-}\nfullFillMustPayTheDeposit : Scenario\nfullFillMustPayTheDeposit =\n    takeRich 10 |> paid 1500000 30 5 |> Scenario.expectFailure\n\n\n{-| The returned order must be the same order: a taker cannot name themselves the maker.\n-}\nchangedOrderRejected : Scenario\nchangedOrderRejected =\n    take 1 3\n        |> Scenario.output\n            (Scenario.toScript 2000000\n                |> Scenario.withToken (Policy gold) (Bytes.fromString \"GOLD\") 9\n                |> Scenario.withDatum (Data.encode { order | maker = Scenario.key \"taker\" })\n            )\n        |> Scenario.expectFailure\n\n\nuntaggedPaymentRejected : Scenario\nuntaggedPaymentRejected =\n    Scenario.spend \"swap\" (Scenario.outRef \"order\" 0) (Data.encode order)\n        |> locked 0\n        |> Scenario.redeemer (Data.encode (Take 10))\n        |> Scenario.output\n            (Scenario.toKey order.maker 2000000\n                |> Scenario.withToken (Policy silver) (Bytes.fromString \"SILVER\") 30\n            )\n        |> Scenario.expectFailure\n\n\n{-| A payment tagged for another order does not fill this one.\n-}\nwrongTagRejected : Scenario\nwrongTagRejected =\n    Scenario.spend \"swap\" (Scenario.outRef \"order\" 0) (Data.encode order)\n        |> locked 0\n        |> Scenario.redeemer (Data.encode (Take 10))\n        |> Scenario.output\n            (Scenario.toKey order.maker 2000000\n                |> Scenario.withToken (Policy silver) (Bytes.fromString \"SILVER\") 30\n                |> Scenario.withDatum (Data.encode (Scenario.outRef \"order\" 1))\n            )\n        |> Scenario.expectFailure\n\n\n{-| Paying the lovelace but keeping one BONUS is rejected.\n-}\nfullFillMustPayTheOtherTokens : Scenario\nfullFillMustPayTheOtherTokens =\n    takeRich 10 |> paid 100000000 30 4 |> Scenario.expectFailure\n\n\n{-| A second order of this script at another staking part cannot be filled alongside.\n-}\nsecondOrderUnderAnotherStakeRejected : Scenario\nsecondOrderUnderAnotherStakeRejected =\n    take 4 12\n        |> rest 6\n        |> Scenario.input (Scenario.outRef \"order\" 1)\n            (Scenario.toStakedScript (StakingHash (PubKeyCredential (Scenario.key \"stake\"))) 2000000\n                |> Scenario.withToken (Policy gold) (Bytes.fromString \"GOLD\") 10\n                |> Scenario.withDatum (Data.encode order)\n            )\n        |> Scenario.expectFailure\n\n\nzeroTakeRejected : Scenario\nzeroTakeRejected =\n    take 0 0 |> rest 10 |> Scenario.expectFailure\n\n\ncancel : String -> Scenario\ncancel signer =\n    Scenario.spend \"swap\" (Scenario.outRef \"order\" 0) (Data.encode order)\n        |> locked 0\n        |> Scenario.redeemer (Data.encode Cancel)\n        |> Scenario.signedBy (Scenario.key signer)\n\n\ncancelByMaker : Scenario\ncancelByMaker =\n    cancel \"maker\"\n\n\ncancelByOtherRejected : Scenario\ncancelByOtherRejected =\n    cancel \"taker\" |> Scenario.expectFailure\n\n\n{-| Every fill of 1 to 10 succeeds with exact payment and the rest returned; one unit less\nof payment always fails.\n-}\nfillsAreChecked : Int -> Bool -> Property\nfillsAreChecked raw short =\n    let\n        amount =\n            modBy 10 raw + 1\n\n        payment =\n            if short then\n                amount * order.price - 1\n\n            else\n                amount * order.price\n\n        scenario =\n            if amount == 10 then\n                take amount payment\n\n            else\n                take amount payment |> rest (10 - amount)\n    in\n    Property.scenario\n        (if short then\n            Scenario.expectFailure scenario\n\n         else\n            scenario\n        )\n"
      }
    },
    {
      "name": "signed",
      "summary": "Nominal ledger hashes and transaction fields: a spend validator checking a signatory.",
      "url": "https://github.com/bloxbean/elci-lang/tree/main/examples/signed",
      "files": {
        "elci.toml": "[project]\nsource-directories = [\"src\"]\ntarget = \"plutus-v3-pv11-uplc-1.1.0\"\njulc-version = \"0.1.0-pre20-ebaf028-SNAPSHOT\"\n\n[validators.signed]\nboundary = \"julc-strict-v1\"\nspend = \"Signed.validate\"\n",
        "src/Signed.elm": "module Signed exposing (validate)\n\nimport Julc.Ledger exposing (PubKeyHash, ScriptContext)\n\n\nvalidate : PubKeyHash -> Int -> ScriptContext -> Bool\nvalidate owner minimumFee ctx =\n    ctx.txInfo.fee\n        >= minimumFee\n        && List.any (\\signer -> signer == owner) ctx.txInfo.signatories\n"
      }
    },
    {
      "name": "threshold",
      "summary": "A spending validator comparing datum and redeemer, using a bundled Julc Java library (Julc.Math).",
      "url": "https://github.com/bloxbean/elci-lang/tree/main/examples/threshold",
      "files": {
        "elci.toml": "[project]\nsource-directories = [\"src\"]\ntarget = \"plutus-v3-pv11-uplc-1.1.0\"\njulc-version = \"0.1.0-pre20-ebaf028-SNAPSHOT\"\n\n[validators.threshold]\nboundary = \"julc-strict-v1\"\nspend = \"Example.Threshold.validate\"\n\n[java-modules]\n\"Julc.Math\" = \"org.julclang.stdlib.lib.MathLib\"\n",
        "src/Example/Threshold.elm": "module Example.Threshold exposing (validate)\n\nimport Julc.Ledger exposing (ScriptContext)\nimport Julc.Math as Math\n\n\nvalidate : Int -> Int -> ScriptContext -> Bool\nvalidate minimum offered _ =\n    offered >= Math.max minimum 0\n"
      }
    },
    {
      "name": "treasury",
      "summary": "This example configures two independent scripts in one project.",
      "url": "https://github.com/bloxbean/elci-lang/tree/main/examples/treasury",
      "files": {
        "elci.toml": "[project]\nsource-directories = [\"src\"]\ntarget = \"plutus-v3-pv11-uplc-1.1.0\"\njulc-version = \"0.1.0-pre20-ebaf028-SNAPSHOT\"\n\n# One script: the treasury address spends payouts and withdraws its staking rewards.\n[validators.treasury]\nboundary = \"julc-strict-v1\"\nparameters = [\"admin\"]\nspend = \"Treasury.spend\"\nwithdraw = \"Treasury.withdraw\"\n\n# A separate script and policy id.\n[validators.badge]\nboundary = \"julc-strict-v1\"\nparameters = [\"admin\"]\nmint = \"Badge.mint\"\n",
        "README.md": "# Treasury: named validators\n\nThis example configures two independent scripts in one project.\n\n- **`treasury`**: one script with a `spend` and a `withdraw` handler.\n  - Spending a `Payout` with `Release` requires the beneficiary's signature and a\n    positive amount. `Cancel` requires the admin's signature.\n  - Withdrawing the script address's staking rewards requires the admin's\n    signature.\n- **`badge`**: a separate minting policy. It accepts a positive quantity signed by\n  the admin.\n\nBoth are parameterized by `admin`, a `PubKeyHash` applied before deployment.\n`Auth.signedBy` is shared source; each script links only what its handlers reach.\n\n```sh\nelci build examples/treasury\nls examples/treasury/build/validators/treasury examples/treasury/build/validators/badge\n```\n\n`TreasuryExampleTest` builds the project with the CLI and reloads each artifact. It\napplies the `admin` parameter, then evaluates every role and some rejected\npurposes with complete ledger contexts.\n",
        "src/Auth.elm": "module Auth exposing (signedBy)\n\nimport Julc.Ledger exposing (PubKeyHash, ScriptContext)\n\n\nsignedBy : PubKeyHash -> ScriptContext -> Bool\nsignedBy key ctx =\n    List.any (\\signer -> signer == key) ctx.txInfo.signatories\n",
        "src/Badge.elm": "module Badge exposing (mint)\n\nimport Auth\nimport Julc.Ledger exposing (PubKeyHash, ScriptContext)\n\n\nmint : PubKeyHash -> Int -> ScriptContext -> Bool\nmint admin quantity ctx =\n    quantity > 0 && Auth.signedBy admin ctx\n",
        "src/Treasury.elm": "module Treasury exposing (Action(..), Payout, spend, withdraw)\n\nimport Auth exposing (signedBy)\nimport Julc.Ledger exposing (PubKeyHash, ScriptContext)\n\n\ntype alias Payout =\n    { beneficiary : PubKeyHash\n    , amount : Int\n    }\n\n\ntype Action\n    = Release\n    | Cancel\n\n\nspend : PubKeyHash -> Payout -> Action -> ScriptContext -> Bool\nspend admin payout action ctx =\n    case action of\n        Release ->\n            payout.amount > 0 && signedBy payout.beneficiary ctx\n\n        Cancel ->\n            signedBy admin ctx\n\n\nwithdraw : PubKeyHash -> () -> ScriptContext -> Bool\nwithdraw admin _ ctx =\n    signedBy admin ctx\n",
        "tests/TreasuryTest.elm": "module TreasuryTest exposing (..)\n\nimport Bytes\nimport Expect exposing (Expectation)\nimport Julc.Data as Data\nimport Julc.Ledger exposing (PubKeyHash)\nimport Property exposing (Property)\nimport Scenario exposing (Scenario)\nimport Treasury exposing (Action(..), Payout)\n\n\nadmin : PubKeyHash\nadmin =\n    Scenario.key \"admin\"\n\n\nbeneficiary : PubKeyHash\nbeneficiary =\n    Scenario.key \"beneficiary\"\n\n\npayout : Payout\npayout =\n    { beneficiary = beneficiary, amount = 50 }\n\n\nclaim : Action -> Scenario\nclaim action =\n    Scenario.spend \"treasury\" (Scenario.outRef \"treasury\" 0) (Data.encode payout)\n        |> Scenario.parameters [ Data.encode admin ]\n        |> Scenario.redeemer (Data.encode action)\n\n\nbeneficiaryReleases : Scenario\nbeneficiaryReleases =\n    claim Release\n        |> Scenario.signedBy beneficiary\n        |> Scenario.withinBudget 20000000 100000\n\n\nstrangerCannotRelease : Scenario\nstrangerCannotRelease =\n    claim Release\n        |> Scenario.signedBy admin\n        |> Scenario.expectFailure\n\n\nadminCancels : Scenario\nadminCancels =\n    claim Cancel\n        |> Scenario.signedBy admin\n\n\nadminWithdrawsRewards : Scenario\nadminWithdrawsRewards =\n    Scenario.withdraw \"treasury\"\n        |> Scenario.parameters [ Data.encode admin ]\n        |> Scenario.signedBy admin\n\n\nrewardsNeedTheAdmin : Scenario\nrewardsNeedTheAdmin =\n    adminWithdrawsRewards\n        |> Scenario.parameters [ Data.encode beneficiary ]\n        |> Scenario.expectFailure\n\n\nbadge : Int -> Scenario\nbadge quantity =\n    Scenario.mint \"badge\"\n        |> Scenario.parameters [ Data.encode admin ]\n        |> Scenario.minting (Bytes.fromString \"BADGE\") quantity\n        |> Scenario.redeemer (Data.encode quantity)\n        |> Scenario.signedBy admin\n\n\nadminMintsBadges : Scenario\nadminMintsBadges =\n    badge 3\n\n\nzeroBadgesAreRejected : Scenario\nzeroBadgesAreRejected =\n    badge 0\n        |> Scenario.expectFailure\n\n\nkeysAreDistinct : Bool\nkeysAreDistinct =\n    admin /= beneficiary\n\n\npayoutsRoundTripThroughData : Expectation\npayoutsRoundTripThroughData =\n    Expect.equal payout (Data.decode (Data.encode payout))\n\n\n{-| Properties run with generated arguments; a failure shrinks to a small counterexample.\n-}\npayoutsAlwaysRoundTrip : Payout -> Property\npayoutsAlwaysRoundTrip generated =\n    Property.expect (Expect.equal generated (Data.decode (Data.encode generated)))\n\n\nonlyTheBeneficiaryReleases : PubKeyHash -> Property\nonlyTheBeneficiaryReleases signer =\n    let\n        release =\n            claim Release\n                |> Scenario.signedBy signer\n    in\n    if signer == beneficiary then\n        Property.scenario release\n\n    else\n        Property.scenario (Scenario.expectFailure release)\n\n\nbadgesNeedAPositiveQuantity : Int -> Property\nbadgesNeedAPositiveQuantity quantity =\n    if quantity > 0 then\n        Property.scenario (badge quantity)\n\n    else\n        Property.scenario (Scenario.expectFailure (badge quantity))\n"
      }
    },
    {
      "name": "vesting",
      "summary": "This spending validator locks an output until a POSIX-time deadline. After the deadline, only the beneficiary recorded in the datum can spend it.",
      "url": "https://github.com/bloxbean/elci-lang/tree/main/examples/vesting",
      "files": {
        "elci.toml": "[project]\nsource-directories = [\"src\"]\ntarget = \"plutus-v3-pv11-uplc-1.1.0\"\njulc-version = \"0.1.0-pre20-ebaf028-SNAPSHOT\"\n\n[validators.vesting]\nboundary = \"julc-strict-v1\"\nspend = \"Vesting.validate\"\n",
        "README.md": "# Vesting contract\n\nThis spending validator locks an output until a POSIX-time deadline. After the\ndeadline, only the beneficiary recorded in the datum can spend it.\n\nThe datum has the following Elci type:\n\n```elm\ntype alias VestingDatum =\n    { beneficiary : PubKeyHash\n    , deadline : Int\n    }\n```\n\nThe redeemer is `Claim`, encoded as constructor `0` with no fields. The validator\naccepts a claim only when both conditions hold:\n\n1. the transaction can only run after `deadline`:\n   `Interval.isEntirelyAfter datum.deadline ctx.txInfo.validRange`; and\n2. the transaction is signed by `beneficiary`: `Tx.signedBy datum.beneficiary ctx`.\n\nThe whole validity range must be after the deadline, so a transaction whose range\nmerely spans the deadline is rejected, and so is one that could run at the deadline\nitself.\n\nFrom the repository root, check and compile the contract with:\n\n```shell\nbuild/install/elci/bin/elci check examples/vesting\nbuild/install/elci/bin/elci build examples/vesting\n```\n\nAfter building the native CLI, the equivalent command is:\n\n```shell\nbuild/native/elci build examples/vesting\n```\n\nThe generated artifacts are written under `examples/vesting/build/validators/vesting/`.\n\n`tests/VestingTest.elm` holds transaction scenarios for claims at, after and before\nthe deadline, with and without the beneficiary's signature, and a property that a\nsigned claim succeeds exactly when its range starts after the deadline:\n\n```shell\nbuild/install/elci/bin/elci test examples/vesting\n```\n",
        "src/Vesting.elm": "module Vesting exposing (VestingAction(..), VestingDatum, validate)\n\nimport Interval\nimport Julc.Ledger exposing (PubKeyHash, ScriptContext)\nimport Tx\n\n\ntype alias VestingDatum =\n    { beneficiary : PubKeyHash\n    , deadline : Int\n    }\n\n\ntype VestingAction\n    = Claim\n\n\nvalidate : VestingDatum -> VestingAction -> ScriptContext -> Bool\nvalidate datum action ctx =\n    case action of\n        Claim ->\n            Interval.isEntirelyAfter datum.deadline ctx.txInfo.validRange\n                && Tx.signedBy datum.beneficiary ctx\n",
        "tests/VestingTest.elm": "module VestingTest exposing (..)\n\nimport Julc.Data as Data\nimport Julc.Ledger exposing (PubKeyHash)\nimport Property exposing (Property)\nimport Scenario exposing (Scenario)\nimport Vesting exposing (VestingAction(..), VestingDatum)\n\n\nbeneficiary : PubKeyHash\nbeneficiary =\n    Scenario.key \"beneficiary\"\n\n\ndatum : VestingDatum\ndatum =\n    { beneficiary = beneficiary, deadline = 1000 }\n\n\nclaimFrom : Int -> Scenario\nclaimFrom time =\n    Scenario.spend \"vesting\" (Scenario.outRef \"vesting\" 0) (Data.encode datum)\n        |> Scenario.redeemer (Data.encode Claim)\n        |> Scenario.validFrom time\n\n\nclaimsAfterTheDeadline : Scenario\nclaimsAfterTheDeadline =\n    claimFrom 1001\n        |> Scenario.signedBy beneficiary\n\n\nclaimsInAClosedRange : Scenario\nclaimsInAClosedRange =\n    claimFrom 5000\n        |> Scenario.validBefore 6000\n        |> Scenario.signedBy beneficiary\n\n\nclaimsAtTheDeadlineFail : Scenario\nclaimsAtTheDeadlineFail =\n    claimFrom 1000\n        |> Scenario.signedBy beneficiary\n        |> Scenario.expectFailure\n\n\nearlyClaimsFail : Scenario\nearlyClaimsFail =\n    claimFrom 999\n        |> Scenario.signedBy beneficiary\n        |> Scenario.expectFailure\n\n\nunsignedClaimsFail : Scenario\nunsignedClaimsFail =\n    claimFrom 2000\n        |> Scenario.expectFailure\n\n\n{-| Whenever a signed claim's validity range starts, it succeeds exactly when that is\nafter the deadline.\n-}\nclaimsSucceedExactlyAfterTheDeadline : Int -> Property\nclaimsSucceedExactlyAfterTheDeadline time =\n    let\n        signed =\n            claimFrom time\n                |> Scenario.signedBy beneficiary\n    in\n    if time > datum.deadline then\n        Property.scenario signed\n\n    else\n        Property.scenario (Scenario.expectFailure signed)\n"
      }
    }
  ]
}
