diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 54f3def..dbcd1be 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -7,8 +7,8 @@ on: workflow_dispatch: jobs: - tests: - name: Run test suite + kudos-tests: + name: Kudos runs-on: ubuntu-latest defaults: run: @@ -19,7 +19,30 @@ jobs: - name: Download latest nightly Juvix binary uses: jaxxstorm/action-install-gh-release@v1.10.0 with: - repo: anoma/juvix-nightly-builds + repo: anoma/juvix + cache: enable + - name: Clean + run: juvix clean --global && juvix clean && juvix dependencies update + - name: Type Check + run: juvix typecheck + - name: Format Check + run: juvix format + #- name: Run Example + # run: juvix eval Example.juvix + + hello-world-tests: + name: Hello World + runs-on: ubuntu-latest + defaults: + run: + working-directory: HelloWorld + steps: + - name: checkout code + uses: actions/checkout@v3 + - name: Download latest nightly Juvix binary + uses: jaxxstorm/action-install-gh-release@v1.10.0 + with: + repo: anoma/juvix cache: enable - name: Clean run: juvix clean --global && juvix clean && juvix dependencies update @@ -27,5 +50,3 @@ jobs: run: juvix typecheck - name: Format Check run: juvix format - - name: Run Example - run: juvix eval Example.juvix diff --git a/.gitignore b/.gitignore index 33dafc2..83c7381 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ .history *.nockma .DS_Store + + +.vscode \ No newline at end of file diff --git a/HelloWorld/Interface/Transaction.juvix b/HelloWorld/Interface/Transaction.juvix new file mode 100644 index 0000000..81f8c4c --- /dev/null +++ b/HelloWorld/Interface/Transaction.juvix @@ -0,0 +1,87 @@ +module Interface.Transaction; + +import Stdlib.Prelude open; +import Stdlib.Data.Set as Set open using {Set}; +import Stdlib.Data.Map as Map open using {Map}; +import Anoma open; +import Applib open; +import Resource open; + +transferHello + (standardInputs : StandardInputs) + (existingHello : Resource) + (receiver : ExternalIdentity) + : Transaction := + let + nonce := generateNonce (StandardInputs.randSeed standardInputs); + in prepareTransaction@{ + standardInputs; + consumed := Set.singleton existingHello; + created := + Set.singleton + mkHelloResource@{ + owner := receiver; + nonce; + }; + }; + +helloWorldIntent + (standardInputs : StandardInputs) + (existingHello : Resource) + (receiver : ExternalIdentity) + : Transaction := + prepareTransaction@{ + standardInputs; + consumed := Set.singleton existingHello; + created := + Set.singleton + mkWorldResource@{ + owner := Identity.external (StandardInputs.caller standardInputs); + nonce := generateNonce (StandardInputs.randSeed standardInputs); + }; + }; + +prepareTransaction + (standardInputs : StandardInputs) + (consumed created : Set Resource) + : Transaction := + let + -- Put maps into the custom inputs that map: + -- - nullifiers to consumed resources + -- - commitments to created resources + tagsAndCustomInputs := + computeTagsAndCustomInputs@{ + consumed; + created; + }; + + tags := TagsAndCustomInputs.tags tagsAndCustomInputs; + pair := tagsToPair tags; + nullifiers := fst pair; + commitments := snd pair; + + -- Put signed messages and signatures from the caller in the app data. + -- The signed messages link back to the original consumed resources, where the signature verification is part of the resource logic requiring the commitments of created resources to be part of the action. + appData := + Set.map (nullifier in nullifiers) { + mkResourceRelationshipAppDataEntry@{ + signer := Identity.internal (StandardInputs.caller standardInputs); + origin := Consumed nullifier; + mustBeConsumed := Set.empty; + mustBeCreated := commitments; + } + } + |> Map.fromSet; + in mkTransactionHelper@{ + roots := Set.singleton (StandardInputs.currentRoot standardInputs); + actions := + Set.singleton + mkActionHelper@{ + consumed; + created; + tags := TagsAndCustomInputs.tags tagsAndCustomInputs; + appData; + customInputs := + TagsAndCustomInputs.customInputs tagsAndCustomInputs; + }; + }; diff --git a/HelloWorld/Package.juvix b/HelloWorld/Package.juvix new file mode 100644 index 0000000..5145faf --- /dev/null +++ b/HelloWorld/Package.juvix @@ -0,0 +1,14 @@ +module Package; + +import PackageDescription.V2 open; + +package : Package := + defaultPackage@?{ + name := "hello-world"; + dependencies := + [ + github "anoma" "juvix-stdlib" "v0.8.0"; + github "anoma" "juvix-arm-specs" "v2.0.0-transparent-alpha.1"; + github "anoma" "anoma-app-lib" "v0.6.1"; + ]; + }; diff --git a/HelloWorld/Resource.juvix b/HelloWorld/Resource.juvix new file mode 100644 index 0000000..bba1ceb --- /dev/null +++ b/HelloWorld/Resource.juvix @@ -0,0 +1,58 @@ +module Resource; + +import Stdlib.Prelude open; +import Anoma open; +import Anoma.Builtin.System open; +import Applib open; +import Applib.Authorization.Check open public; +import Applib.Authorization.Check open public; +import Applib.Authorization.Message open public; + +logic (publicInputs : Logic.Instance) (privateInputs : Logic.Witness) : Bool := + let + tag := Logic.Instance.tag publicInputs; + customInputs := Logic.Witness.customInputs privateInputs; + in case tag of + | Consumed nullifier := + case lookupResource nullifier customInputs of { + | nothing := false + | just self := + isAuthorizedBy@{ + signer := HasOwner.get self; + origin := tag; + publicInputs; + } + } + | Created commitment := true; + +-- You don't need to change anything below this point. +mkLabelledResource + (label : String) + (owner : ExternalIdentity) + (nonce : Nonce) + {ephemeral : Bool := false} + : Resource := + mkResource@{ + logicRef := BindingReference.compute logic; + labelRef := BindingReference.compute (mkLabel (anomaEncode label)); + valueRef := BindingReference.compute (mkValue (anomaEncode owner)); + quantity := 1; + nonce; + ephemeral; + randSeed := UnusedRandSeed; + nullifierKeyCommitment := Universal.nullifierKeyCommitment; + }; + +mkHelloResource (owner : ExternalIdentity) (nonce : Nonce) : Resource := + mkLabelledResource@{ + label := "Hello"; + owner; + nonce; + }; + +mkWorldResource (owner : ExternalIdentity) (nonce : Nonce) : Resource := + mkLabelledResource@{ + label := "World"; + owner; + nonce; + }; diff --git a/HelloWorld/juvix.lock.yaml b/HelloWorld/juvix.lock.yaml new file mode 100644 index 0000000..18081ba --- /dev/null +++ b/HelloWorld/juvix.lock.yaml @@ -0,0 +1,41 @@ +# This file was autogenerated by Juvix version 0.6.8. +# Do not edit this file manually. + +version: 2 +checksum: 7e1503c9e6c5f62bedadd6b6637bc55e25372a26fe9628bbf5f4026fd1ad34a5 +dependencies: +- git: + name: anoma_juvix-stdlib + ref: 0080b1183ab55e5180e69bfc3987e4cd6edbc230 + url: https://github.com/anoma/juvix-stdlib + dependencies: [] +- git: + name: anoma_juvix-arm-specs + ref: dc691b9e17b4b8136296904d433c946f81588157 + url: https://github.com/anoma/juvix-arm-specs + dependencies: + - git: + name: anoma_juvix-stdlib + ref: 0080b1183ab55e5180e69bfc3987e4cd6edbc230 + url: https://github.com/anoma/juvix-stdlib + dependencies: [] +- git: + name: anoma_anoma-app-lib + ref: a6c4993f203d759051ef4a31c0c6c7fde0a9e9a2 + url: https://github.com/anoma/anoma-app-lib + dependencies: + - git: + name: anoma_juvix-stdlib + ref: 0080b1183ab55e5180e69bfc3987e4cd6edbc230 + url: https://github.com/anoma/juvix-stdlib + dependencies: [] + - git: + name: anoma_juvix-arm-specs + ref: dc691b9e17b4b8136296904d433c946f81588157 + url: https://github.com/anoma/juvix-arm-specs + dependencies: + - git: + name: anoma_juvix-stdlib + ref: 0080b1183ab55e5180e69bfc3987e4cd6edbc230 + url: https://github.com/anoma/juvix-stdlib + dependencies: [] diff --git a/Kudos/Example.juvix b/Kudos/Example.juvix index b1e4080..e21e391 100644 --- a/Kudos/Example.juvix +++ b/Kudos/Example.juvix @@ -1,17 +1,14 @@ module Example; -import Anoma open; import Stdlib.Prelude open; import Stdlib.Debug.Fail open using {failwith}; -import Applib.Resource.Error open; -import Applib.Authorization.Identities open; -import Applib.Helpers open; - -import Anoma.Transaction open; -import Anoma.Identity open; +import Anoma open; +import Anoma.Builtin.ByteArray open; import Anoma.State.CommitmentTree open; +import Applib open; + import Interface open; alice : Identity := Universal.identity; @@ -20,18 +17,16 @@ bob : ExternalIdentity := Zero.externalIdentity; standardInputs : StandardInputs := mkStandardInputs@{ - identity := alice; - currentRoot := mkRoot 0 + caller := alice; + currentRoot := mkRoot 0; + randSeed := mkRandSeed (mkByteArray (replicate 32 0x0)); }; --- Create 10 Kudo tokens as Alice (the originator) for Bob (the owner). main : Transaction := - case + fromResult initialize@{ standardInputs; quantity := 10; - receiver := bob - } - of - | error err := failwith (Show.show err) - | ok tx := tx; + receiver := bob; + }; diff --git a/Kudos/Interface.juvix b/Kudos/Interface.juvix index b1a8897..8682f32 100644 --- a/Kudos/Interface.juvix +++ b/Kudos/Interface.juvix @@ -1,52 +1,55 @@ module Interface; import Stdlib.Prelude open; +import Stdlib.Data.Set as Set open using {Set}; -import Anoma.Identity open; -import Anoma.Transaction open; -import Anoma.Resource open; +import Anoma open; +import Applib open; -import Applib.Resource.Error open; -import Applib.Transaction as Transaction; - -import Applib.Token.Resource open; -import Applib.Token.Label open; -import Applib.Intent.Asset open; -import Applib.Intent.Swap.Resource open; -import Applib.Intent.Swap.Solution open; - -import Applib.Helpers open; +import Applib.Token open; +import Applib.Intent open; +import Applib.Transaction.Errors open; import Label open; +notKudoError : DefaultError := + mkDefaultError@{ + msg := "The input resource is not a Kudo token."; + }; + initialize (standardInputs : StandardInputs) (quantity : Quantity) (receiver : ExternalIdentity) : Result StandardError Transaction := let - self := standardInputs |> StandardInputs.identity |> Identity.external; + self := Identity.external (StandardInputs.caller standardInputs); + nonce := generateNonce (StandardInputs.randSeed standardInputs); token := Token.create@{ + nonce; quantity; tokenLabel := mkKudoLabel self; - owner := receiver + owner := receiver; }; in Transaction.initialize@{ - standardInputs; - toInitialize := token; - maybeDummy := nothing - }; + standardInputs; + toInitialize := token; + maybeDummy := nothing; + }; -finalize (standardInputs : StandardInputs) (token : Token) : Result StandardError Transaction := +finalize + (standardInputs : StandardInputs) + (token : Token) + : Result StandardError Transaction := let - self : ExternalIdentity := standardInputs |> StandardInputs.identity |> Identity.external; + self := Identity.external (StandardInputs.caller standardInputs); in case isKudo (self) token of | false := throw notKudoError | true := Transaction.finalize@{ standardInputs; - toFinalize := token + toFinalize := token; }; send @@ -56,7 +59,7 @@ send (receiver : ExternalIdentity) : Result StandardError Transaction := let - self : ExternalIdentity := standardInputs |> StandardInputs.identity |> Identity.external; + self := Identity.external (StandardInputs.caller standardInputs); in case isKudo self token of | false := throw notKudoError | true := @@ -64,7 +67,7 @@ send standardInputs; toSend := token; quantity; - receiver + receiver; }; transfer @@ -73,14 +76,14 @@ transfer (receiver : ExternalIdentity) : Result StandardError Transaction := let - self : ExternalIdentity := standardInputs |> StandardInputs.identity |> Identity.external; + self := Identity.external (StandardInputs.caller standardInputs); in case isKudo (self) token of | false := throw notKudoError | true := Transaction.transfer@{ standardInputs; toTransfer := token; - receiver + receiver; }; split @@ -90,14 +93,14 @@ split (quantitiesAndReceivers : List (Pair Quantity ExternalIdentity)) : Result StandardError Transaction := let - self : ExternalIdentity := standardInputs |> StandardInputs.identity |> Identity.external; + self := Identity.external (StandardInputs.caller standardInputs); in case isKudo self token of | false := throw notKudoError | true := Transaction.split@{ standardInputs; toSplit := token; - quantitiesAndReceivers + quantitiesAndReceivers; }; merge @@ -106,45 +109,55 @@ merge (receiver : ExternalIdentity) : Result StandardError Transaction := let - self := standardInputs |> StandardInputs.identity |> Identity.external; - in case all (t in tokens) {isKudo self t} of + self := Identity.external (StandardInputs.caller standardInputs); + in case + all (t in tokens) { + isKudo self t + } + of | false := throw notKudoError | true := Transaction.merge@{ standardInputs; toMerge := tokens; - receiver + receiver; }; swap (standardInputs : StandardInputs) - (toSwap : List Token) - (want : QuantifiedAssets) + (toSwap : Set Token) + (want : Asset.QuantifiedAssets) (solver : ExternalIdentity) : Result StandardError Transaction := let - self := standardInputs |> StandardInputs.identity |> Identity.external; - in case all (t in toSwap) {isKudo self t} of + self := Identity.external (StandardInputs.caller standardInputs); + nonce := generateNonce (StandardInputs.randSeed standardInputs); + in case + all (t in Set.toList toSwap) { + isKudo self t + } + of | false := throw notKudoError | true := Transaction.swap@{ standardInputs; toSwap; intent := - SwapIntent.create@{ + Swap.SwapIntent.create@{ + nonce; want; receiver := self; - solver - } + solver; + }; }; settle (standardInputs : StandardInputs) - (transactions : List Transaction) - (solutions : List Solution) + (transactions : Set Transaction) + (solutions : Set Swap.Solution) : Result StandardError Transaction := Transaction.settle@{ standardInputs; transactions; - solutions + solutions; }; diff --git a/Kudos/Label.juvix b/Kudos/Label.juvix index 2e410b0..d01e994 100644 --- a/Kudos/Label.juvix +++ b/Kudos/Label.juvix @@ -1,18 +1,14 @@ module Label; import Stdlib.Prelude open; -import Applib.Helpers open; -import Applib.Token.Resource open; -import Applib.Token.Label open; -import Applib.Token.Logic open; +import Anoma open; +import Anoma.Builtin.System open; -import Applib.Resource.Error open; +import Applib open; +import Applib.Token open; import Applib.Resource.Traits open; -import Anoma.Identity open; -import Anoma.Builtin.System open; - mkKudoLabel (originator : ExternalIdentity) : TokenLabel := mkTokenLabel@{ name := "Kudos"; @@ -20,7 +16,7 @@ mkKudoLabel (originator : ExternalIdentity) : TokenLabel := decimals := 18; supply := Unbound; transferability := Transferability.Transferable; - originator + originator; }; isKudo (originator : ExternalIdentity) (token : Token) : Bool := @@ -34,8 +30,3 @@ isKudo (originator : ExternalIdentity) (token : Token) : Bool := | label /= expectedLabel := false | logicEncoded /= expectedLogicEncoded := false | else := true; - -notKudoError : DefaultError := - mkDefaultError@{ - msg := "The input resource is not a Kudo token." - }; diff --git a/Kudos/Main.juvix b/Kudos/Main.juvix index 12c1f3a..ae9ab99 100644 --- a/Kudos/Main.juvix +++ b/Kudos/Main.juvix @@ -2,17 +2,14 @@ module Main; import Stdlib.Prelude open; import Stdlib.Debug.Fail open; - -import Anoma.Identity open; +import Anoma open; import Anoma.Builtin.System open; -import Anoma.Transaction open; - -import Applib.Resource.Error open; -import Applib.Helpers open; +import Applib open; import Kudos as Kudos; -INVALID_FUNCTION_SELECTOR : {A : Type} -> A := failwith "Invalid function selector."; +INVALID_FUNCTION_SELECTOR : {A : Type} -> A := + failwith "Invalid function selector."; INVALID_ARGUMENT_NUMBER : {A : Type} -> A := failwith "Invalid argument number"; @@ -45,53 +42,53 @@ main (funcSelector : Nat) (args : List Nat) : AnomaTransaction := Kudos.initialize@{ standardInputs := anomaDecode a1; quantity := anomaDecode a2; - receiver := anomaDecode a3 + receiver := anomaDecode a3; } | Finalize, [a1; a2] := Kudos.finalize@{ standardInputs := anomaDecode a1; - token := anomaDecode a2 + token := anomaDecode a2; } | Send, [a1; a2; a3; a4] := Kudos.send@{ standardInputs := anomaDecode a1; token := anomaDecode a2; quantity := anomaDecode a3; - receiver := anomaDecode a4 + receiver := anomaDecode a4; } | Transfer, [a1; a2; a3] := Kudos.transfer@{ standardInputs := anomaDecode a1; token := anomaDecode a2; - receiver := anomaDecode a3 + receiver := anomaDecode a3; } | Split, [a1; a2; a3] := Kudos.split@{ standardInputs := anomaDecode a1; token := anomaDecode a2; - quantitiesAndReceivers := anomaDecode a3 + quantitiesAndReceivers := anomaDecode a3; } | Merge, [a1; a2; a3] := Kudos.merge@{ standardInputs := anomaDecode a1; tokens := anomaDecode a2; - receiver := anomaDecode a3 + receiver := anomaDecode a3; } | Swap, [a1; a2; a3; a4] := Kudos.swap@{ standardInputs := anomaDecode a1; toSwap := anomaDecode a2; want := anomaDecode a3; - solver := anomaDecode a4 + solver := anomaDecode a4; } | Settle, [a1; a2; a3] := Kudos.settle@{ standardInputs := anomaDecode a1; transactions := anomaDecode a2; - solutions := anomaDecode a3 + solutions := anomaDecode a3; } | INVALID, _ := INVALID_FUNCTION_SELECTOR | _, _ := INVALID_ARGUMENT_NUMBER } - |> txFromResult + |> fromResult |> toAnomaTransaction; diff --git a/Kudos/Package.juvix b/Kudos/Package.juvix index 58a9ffa..93e05e1 100644 --- a/Kudos/Package.juvix +++ b/Kudos/Package.juvix @@ -6,9 +6,9 @@ package : Package := defaultPackage@{ name := "kudos"; dependencies := - [ github "anoma" "juvix-stdlib" "ff351799c068e7b3e23dd903547d228dc30aff5e" - ; github "anoma" "juvix-test" "v0.15.0" - ; github "anoma" "juvix-arm-transparent" "efb1be6b0448690fb4d0b95a58f88fb1d5c7cc3e" - ; github "anoma" "anoma-app-lib" "32ff9d624aa8548f979deaff1340f4dbd4cf7b72" - ] + [ + github "anoma" "juvix-stdlib" "v0.8.0"; + github "anoma" "juvix-arm-specs" "v2.0.0-transparent-alpha.1"; + github "anoma" "anoma-app-lib" "v0.6.1"; + ]; }; diff --git a/Kudos/juvix.lock.yaml b/Kudos/juvix.lock.yaml index 3eec868..09ff25e 100644 --- a/Kudos/juvix.lock.yaml +++ b/Kudos/juvix.lock.yaml @@ -1,61 +1,41 @@ -# This file was autogenerated by Juvix version 0.6.6. +# This file was autogenerated by Juvix version 0.6.8. # Do not edit this file manually. version: 2 -checksum: a08e32ccb9183e0e50aaed60ba838db6fb58678e262c0965938d437aaea9e2c2 +checksum: 06effc901751f48da4b1616af06402c6a61d21fd755057ecbdcb87fe90b3aa32 dependencies: - git: name: anoma_juvix-stdlib - ref: ff351799c068e7b3e23dd903547d228dc30aff5e + ref: 0080b1183ab55e5180e69bfc3987e4cd6edbc230 url: https://github.com/anoma/juvix-stdlib dependencies: [] - git: - name: anoma_juvix-test - ref: 3103c41e055eb9018a851fd3688cd608cad8f55d - url: https://github.com/anoma/juvix-test + name: anoma_juvix-arm-specs + ref: dc691b9e17b4b8136296904d433c946f81588157 + url: https://github.com/anoma/juvix-arm-specs dependencies: - git: name: anoma_juvix-stdlib - ref: 615a02c8107076ca9661c5234d41792be91a5104 - url: https://github.com/anoma/juvix-stdlib - dependencies: [] -- git: - name: anoma_juvix-arm-transparent - ref: efb1be6b0448690fb4d0b95a58f88fb1d5c7cc3e - url: https://github.com/anoma/juvix-arm-transparent - dependencies: - - git: - name: anoma_juvix-stdlib - ref: ff351799c068e7b3e23dd903547d228dc30aff5e + ref: 0080b1183ab55e5180e69bfc3987e4cd6edbc230 url: https://github.com/anoma/juvix-stdlib dependencies: [] - git: name: anoma_anoma-app-lib - ref: 32ff9d624aa8548f979deaff1340f4dbd4cf7b72 + ref: a6c4993f203d759051ef4a31c0c6c7fde0a9e9a2 url: https://github.com/anoma/anoma-app-lib dependencies: - git: name: anoma_juvix-stdlib - ref: ff351799c068e7b3e23dd903547d228dc30aff5e + ref: 0080b1183ab55e5180e69bfc3987e4cd6edbc230 url: https://github.com/anoma/juvix-stdlib dependencies: [] - git: - name: anoma_juvix-test - ref: 3103c41e055eb9018a851fd3688cd608cad8f55d - url: https://github.com/anoma/juvix-test - dependencies: - - git: - name: anoma_juvix-stdlib - ref: 615a02c8107076ca9661c5234d41792be91a5104 - url: https://github.com/anoma/juvix-stdlib - dependencies: [] - - git: - name: anoma_juvix-arm-transparent - ref: efb1be6b0448690fb4d0b95a58f88fb1d5c7cc3e - url: https://github.com/anoma/juvix-arm-transparent + name: anoma_juvix-arm-specs + ref: dc691b9e17b4b8136296904d433c946f81588157 + url: https://github.com/anoma/juvix-arm-specs dependencies: - git: name: anoma_juvix-stdlib - ref: ff351799c068e7b3e23dd903547d228dc30aff5e + ref: 0080b1183ab55e5180e69bfc3987e4cd6edbc230 url: https://github.com/anoma/juvix-stdlib dependencies: []