From e2af94c215dd33e960a9d9ba409b1dea3745c07b Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 26 Apr 2021 19:01:15 +0700 Subject: [PATCH 001/169] cp plutus-starter template --- .../.devcontainer/devcontainer.json | 23 ++ MetaLamp/lending-pool/.gitignore | 23 ++ MetaLamp/lending-pool/LICENSE | 201 ++++++++++++++++ MetaLamp/lending-pool/README.md | 149 ++++++++++++ MetaLamp/lending-pool/cabal.project | 144 ++++++++++++ .../examples/src/Plutus/Contracts/Game.hs | 162 +++++++++++++ MetaLamp/lending-pool/examples/test/Spec.hs | 21 ++ .../lending-pool/examples/test/Spec/Game.hs | 60 +++++ .../lending-pool/examples/test/Spec/game.pir | 217 ++++++++++++++++++ MetaLamp/lending-pool/hie.yaml | 2 + MetaLamp/lending-pool/pab/Main.hs | 90 ++++++++ MetaLamp/lending-pool/plutus-starter.cabal | 81 +++++++ MetaLamp/lending-pool/src/MyModule.hs | 7 + 13 files changed, 1180 insertions(+) create mode 100644 MetaLamp/lending-pool/.devcontainer/devcontainer.json create mode 100644 MetaLamp/lending-pool/.gitignore create mode 100644 MetaLamp/lending-pool/LICENSE create mode 100644 MetaLamp/lending-pool/README.md create mode 100644 MetaLamp/lending-pool/cabal.project create mode 100644 MetaLamp/lending-pool/examples/src/Plutus/Contracts/Game.hs create mode 100644 MetaLamp/lending-pool/examples/test/Spec.hs create mode 100644 MetaLamp/lending-pool/examples/test/Spec/Game.hs create mode 100644 MetaLamp/lending-pool/examples/test/Spec/game.pir create mode 100644 MetaLamp/lending-pool/hie.yaml create mode 100644 MetaLamp/lending-pool/pab/Main.hs create mode 100644 MetaLamp/lending-pool/plutus-starter.cabal create mode 100644 MetaLamp/lending-pool/src/MyModule.hs diff --git a/MetaLamp/lending-pool/.devcontainer/devcontainer.json b/MetaLamp/lending-pool/.devcontainer/devcontainer.json new file mode 100644 index 000000000..2a514c5f2 --- /dev/null +++ b/MetaLamp/lending-pool/.devcontainer/devcontainer.json @@ -0,0 +1,23 @@ +{ + "name": "Plutus Starter Project", + "image": "plutus-devcontainer:latest", + + "remoteUser": "plutus", + + "mounts": [ + // This shares cabal's remote repository state with the host. We don't mount the whole of '.cabal', because + // 1. '.cabal/config' contains absolute paths that will only make sense on the host, and + // 2. '.cabal/store' is not necessarily portable to different version of cabal etc. + "source=${localEnv:HOME}/.cabal/packages,target=/home/plutus/.cabal/packages,type=bind,consistency=cached", + ], + + "settings": { + // Note: don't change from bash so it runs .bashrc + "terminal.integrated.shell.linux": "/bin/bash" + }, + + // IDs of extensions inside container + "extensions": [ + "haskell.haskell" + ], +} diff --git a/MetaLamp/lending-pool/.gitignore b/MetaLamp/lending-pool/.gitignore new file mode 100644 index 000000000..4c9e245b5 --- /dev/null +++ b/MetaLamp/lending-pool/.gitignore @@ -0,0 +1,23 @@ +dist +dist-* +cabal-dev +*.o +*.hi +*.hie +*.chi +*.chs.h +*.dyn_o +*.dyn_hi +.hpc +.hsenv +.cabal-sandbox/ +cabal.sandbox.config +*.prof +*.aux +*.hp +*.eventlog +.stack-work/ +cabal.project.local +cabal.project.local~ +.HTF/ +.ghc.environment.* diff --git a/MetaLamp/lending-pool/LICENSE b/MetaLamp/lending-pool/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/MetaLamp/lending-pool/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/MetaLamp/lending-pool/README.md b/MetaLamp/lending-pool/README.md new file mode 100644 index 000000000..9912e989f --- /dev/null +++ b/MetaLamp/lending-pool/README.md @@ -0,0 +1,149 @@ +# Plutus Platform starter project + +This project gives a simple starter project for using the Plutus Platform. + +## Setting up + +For now, the only supported tooling setup is to use the provided VSCode devcontainer to get an environment with the correct tools set up. + +- Install Docker +- Install VSCode + - Install the [Remote Development extension pack](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) + - You do *not* need to install the Haskell extension +- Get the docker image (for now, we need to build this with Nix) + - Clone https://github.com/input-output-hk/plutus + - Set up your machine to build things with Nix, following the Plutus README (make sure to set up the binary cache!) + - Build and load the docker container: `docker load < $(nix-build default.nix -A devcontainer)` +- Clone this repository and open it in VSCode + - It will ask if you want to open it in the container, say yes. + - `cabal build` from the terminal should work + - Opening a Haskell file should give you IDE features (it takes a little while to set up the first time) + + +## The Plutus Application Backend (PAB) example + +We have provided an example PAB application in `./pab`. With the PAB we can serve and interact +with contracts over a web API. You can read more about the PAB here: [PAB Architecture](https://github.com/input-output-hk/plutus/blob/master/plutus-pab/ARCHITECTURE.adoc). + +Here, the PAB is configured with one contract, the `Game` contract from `./examples/src/Plutus/Contracts/Game.hs`. + +Here's an example of running and interacting with this contract via the API. For this it will help if you +have `jq` installed. + +1. Build the PAB executable: + +``` +cabal build plutus-starter-pab +``` + +2. Run the PAB binary: + +``` +cabal exec -- plutus-starter-pab +```` + +This will then start up the server on port 8080. The devcontainer process will then automatically expose this port so that you can connect to it from any terminal (it doesn't have to be a terminal running in the devcontainer). + +First, let's verify that the game is present in the server: + +3. Check what contracts are present: + +``` +curl -s http://localhost:8080/api/new/contract/definitions | jq +``` + +You should receive a list of contracts and the endpoints that can be called on them, and the arguments +required for those endpoints. + +We're interested in the `GameContract` one. + +#### Playing the guessing game over the API + +The game has two players (wallets). One will initialise the contract and lock a value inside. Another +wallet will then make guesses. Supposing they guess correctly, they'll receive the funds that were +locked; otherwise, they won't! + +1. Start the instances: + +``` +# Wallet 1 +curl -s -H "Content-Type: application/json" \ + --request POST \ + --data '{"caID": "GameContract", "caWallet":{"getWallet": 1}}' \ + http://localhost:8080/api/new/contract/activate | jq + +# Wallet 2 +curl -s -H "Content-Type: application/json" \ + --request POST \ + --data '{"caID": "GameContract", "caWallet":{"getWallet": 2}}' \ + http://localhost:8080/api/new/contract/activate | jq +``` + +From these two queries you will get back two contract instance IDs. These will be needed +in the subsequent steps for running actions against. We can optionally take a look at the state +of the contract with the `status` API: + +2. Get the status + +``` +export INSTANCE_ID=... +curl -s http://localhost:8080/api/new/contract/instance/$INSTANCE_ID/status | jq +``` + +This has a lot of information; and in particular we can see what endpoints are still available +to call. + +3. Start the game by locking some value inside + +Now, let's call the `lock` endpoint to start the game. In order to do so, we need to construct +a JSON representation of the `LockParams` that the endpoint takes (look at `Game.hs`). The easiest +way is to simply build the term in haskell and ask `aeson` to encode it. From the terminal: + +``` +cabal repl +> import Plutus.Contracts.Game +> import Ledger.Ada +> args = LockParams { secretWord = "eagle", amount = lovelaceValueOf 90 } +> import Data.Aeson +> import Data.ByteString.Lazy.Char8 as BSL +> BSL.putStrLn $ encode args +{"amount":{"getValue":[[{"unCurrencySymbol":""},[[{"unTokenName":""},90]]]]},"secretWord":"eagle"} +``` + +Great! This is all we need to call the `lock` endpoint, so let's do that now with +the instance from Wallet 1: + +4. Lock some value (Wallet 1) + +``` +export INSTANCE_ID=... +curl -H "Content-Type: application/json" \ + --request POST \ + --data '{"amount":{"getValue":[[{"unCurrencySymbol":""},[[{"unTokenName":""},90]]]]},"secretWord":"eagle"}' \ + http://localhost:8080/api/new/contract/instance/$INSTANCE_ID/endpoint/lock +``` + +We can do likewise to work out what the JSON for `GuessParams` is, and then make a guess from +Wallet 2: + +5. Make a guess (Wallet 2) + +``` +export INSTANCE_ID=... +curl -H "Content-Type: application/json" \ + --request POST \ + --data '{"guessWord": "duck"}' \ + http://localhost:8080/api/new/contract/instance/$INSTANCE_ID/endpoint/guess +``` + +Note that this guess is wrong, so in the log of the server we will see that the transaction +didn't validate. + +As an exercise, you can now spin up another instance for Wallet 2 and make a correct guess, and +confirm that the transaction validates and the Ada is transferred into the right wallet. + +Note that you can verify the balances by looking at the log of `plutus-starter-pab` +when exiting it by pressing return. + +Finally, also node that the PAB also exposes a websocket, which you can read about in +the general [PAB Architecture documentation](https://github.com/input-output-hk/plutus/blob/master/plutus-pab/ARCHITECTURE.adoc). \ No newline at end of file diff --git a/MetaLamp/lending-pool/cabal.project b/MetaLamp/lending-pool/cabal.project new file mode 100644 index 000000000..f7e25adc5 --- /dev/null +++ b/MetaLamp/lending-pool/cabal.project @@ -0,0 +1,144 @@ +index-state: 2021-02-24T00:00:00Z + +packages: ./. + +-- You never, ever, want this. +write-ghc-environment-files: never + +-- Always build tests and benchmarks. +tests: true +benchmarks: true + +source-repository-package + type: git + location: https://github.com/input-output-hk/plutus.git + subdir: + freer-extras + playground-common + plutus-core + plutus-contract + plutus-ledger + plutus-ledger-api + plutus-tx + plutus-tx-plugin + plutus-pab + plutus-use-cases + prettyprinter-configurable + quickcheck-dynamic + tag: 03a95411238225db1d10288fbd3b405f5f53c78b + +-- The following sections are copied from the 'plutus' repository cabal.project at the revision +-- given above. +-- This is necessary because the 'plutus' libraries depend on a number of other libraries which are +-- not on Hackage, and so need to be pulled in as `source-repository-package`s themselves. Make sure to +-- re-update this section from the template when you do an upgrade. +package eventful-sql-common + ghc-options: -XDerivingStrategies -XStandaloneDeriving -XUndecidableInstances -XDataKinds -XFlexibleInstances + +allow-newer: + -- Has a commit to allow newer aeson, not on Hackage yet + monoidal-containers:aeson + -- Pins to an old version of Template Haskell, unclear if/when it will be updated + , size-based:template-haskell + + -- The following two dependencies are needed by plutus. + , eventful-sql-common:persistent + , eventful-sql-common:persistent-template + +constraints: + -- aws-lambda-haskell-runtime-wai doesn't compile with newer versions + aws-lambda-haskell-runtime <= 3.0.3 + -- big breaking change here, inline-r doens't have an upper bound + , singletons < 3.0 + -- breaks eventful even more than it already was + , persistent-template < 2.12 + +extra-packages: ieee, filemanip + +-- Needs some patches, but upstream seems to be fairly dead (no activity in > 1 year) +source-repository-package + type: git + location: https://github.com/shmish111/purescript-bridge.git + tag: 6a92d7853ea514be8b70bab5e72077bf5a510596 + +source-repository-package + type: git + location: https://github.com/shmish111/servant-purescript.git + tag: a76104490499aa72d40c2790d10e9383e0dbde63 + +source-repository-package + type: git + location: https://github.com/input-output-hk/cardano-crypto.git + tag: f73079303f663e028288f9f4a9e08bcca39a923e + +-- Needs a fix (https://github.com/wenkokke/unlit/pull/11) and a Hackage release +source-repository-package + type: git + location: https://github.com/michaelpj/unlit.git + tag: 9ca1112093c5ffd356fc99c7dafa080e686dd748 + +source-repository-package + type: git + location: https://github.com/input-output-hk/cardano-base + tag: 4251c0bb6e4f443f00231d28f5f70d42876da055 + subdir: + binary + binary/test + slotting + cardano-crypto-class + cardano-crypto-praos + +source-repository-package + type: git + location: https://github.com/input-output-hk/cardano-prelude + tag: ee4e7b547a991876e6b05ba542f4e62909f4a571 + subdir: + cardano-prelude + cardano-prelude-test + +source-repository-package + type: git + location: https://github.com/input-output-hk/ouroboros-network + tag: 6cb9052bde39472a0555d19ade8a42da63d3e904 + subdir: + typed-protocols + typed-protocols-examples + ouroboros-network + ouroboros-network-testing + ouroboros-network-framework + io-sim + io-sim-classes + network-mux + Win32-network + +source-repository-package + type: git + location: https://github.com/input-output-hk/iohk-monitoring-framework + tag: a89c38ed5825ba17ca79fddb85651007753d699d + subdir: + iohk-monitoring + tracer-transformers + contra-tracer + plugins/backend-ekg + +source-repository-package + type: git + location: https://github.com/input-output-hk/cardano-ledger-specs + tag: 097890495cbb0e8b62106bcd090a5721c3f4b36f + subdir: + byron/chain/executable-spec + byron/crypto + byron/crypto/test + byron/ledger/executable-spec + byron/ledger/impl + byron/ledger/impl/test + semantics/executable-spec + semantics/small-steps-test + shelley/chain-and-ledger/dependencies/non-integer + shelley/chain-and-ledger/executable-spec + shelley-ma/impl + +source-repository-package + type: git + location: https://github.com/input-output-hk/goblins + tag: cde90a2b27f79187ca8310b6549331e59595e7ba diff --git a/MetaLamp/lending-pool/examples/src/Plutus/Contracts/Game.hs b/MetaLamp/lending-pool/examples/src/Plutus/Contracts/Game.hs new file mode 100644 index 000000000..4f7dfe0be --- /dev/null +++ b/MetaLamp/lending-pool/examples/src/Plutus/Contracts/Game.hs @@ -0,0 +1,162 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE PartialTypeSignatures #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE TypeSynonymInstances #-} +{-# LANGUAGE ViewPatterns #-} + +-- | A guessing game +module Plutus.Contracts.Game + ( lock + , guess + , game + , GameSchema + , GuessParams(..) + , LockParams(..) + -- * Scripts + , gameValidator + , hashString + , clearString + -- * Address + , gameAddress + , validateGuess + -- * Traces + , guessTrace + , guessWrongTrace + , lockTrace + ) where + +import Control.Monad (void) +import Data.Aeson (FromJSON, ToJSON) +import GHC.Generics (Generic) +import Ledger (Address, Validator, ValidatorCtx, Value) +import qualified Ledger.Constraints as Constraints +import qualified Ledger.Typed.Scripts as Scripts +import Plutus.Contract +import Plutus.Contract.Schema () +import Plutus.Trace.Emulator (EmulatorTrace) +import qualified Plutus.Trace.Emulator as Trace +import qualified PlutusTx +import PlutusTx.Prelude +import Schema (ToArgument, ToSchema) +import Wallet.Emulator (Wallet (..)) + +import qualified Ledger +import qualified Ledger.Ada as Ada + +import qualified Data.ByteString.Char8 as C +import qualified Prelude + +newtype HashedString = HashedString ByteString deriving newtype PlutusTx.IsData + +PlutusTx.makeLift ''HashedString + +newtype ClearString = ClearString ByteString deriving newtype PlutusTx.IsData + +PlutusTx.makeLift ''ClearString + +type GameSchema = + BlockchainActions + .\/ Endpoint "lock" LockParams + .\/ Endpoint "guess" GuessParams + +-- | The validation function (DataValue -> RedeemerValue -> ValidatorCtx -> Bool) +validateGuess :: HashedString -> ClearString -> ValidatorCtx -> Bool +validateGuess (HashedString actual) (ClearString guess') _ = actual == sha2_256 guess' + +-- | The validator script of the game. +gameValidator :: Validator +gameValidator = Scripts.validatorScript gameInstance + +data Game +instance Scripts.ScriptType Game where + type instance RedeemerType Game = ClearString + type instance DatumType Game = HashedString + +gameInstance :: Scripts.ScriptInstance Game +gameInstance = Scripts.validator @Game + $$(PlutusTx.compile [|| validateGuess ||]) + $$(PlutusTx.compile [|| wrap ||]) where + wrap = Scripts.wrapValidator @HashedString @ClearString + +-- create a data script for the guessing game by hashing the string +-- and lifting the hash to its on-chain representation +hashString :: String -> HashedString +hashString = HashedString . sha2_256 . C.pack + +-- create a redeemer script for the guessing game by lifting the +-- string to its on-chain representation +clearString :: String -> ClearString +clearString = ClearString . C.pack + +-- | The address of the game (the hash of its validator script) +gameAddress :: Address +gameAddress = Ledger.scriptAddress gameValidator + +-- | Parameters for the "lock" endpoint +data LockParams = LockParams + { secretWord :: String + , amount :: Value + } + deriving stock (Prelude.Eq, Prelude.Show, Generic) + deriving anyclass (FromJSON, ToJSON, ToSchema, ToArgument) + +-- | Parameters for the "guess" endpoint +newtype GuessParams = GuessParams + { guessWord :: String + } + deriving stock (Prelude.Eq, Prelude.Show, Generic) + deriving anyclass (FromJSON, ToJSON, ToSchema, ToArgument) + +lock :: AsContractError e => Contract () GameSchema e () +lock = do + LockParams secret amt <- endpoint @"lock" @LockParams + let tx = Constraints.mustPayToTheScript (hashString secret) amt + void (submitTxConstraints gameInstance tx) + +guess :: AsContractError e => Contract () GameSchema e () +guess = do + GuessParams theGuess <- endpoint @"guess" @GuessParams + unspentOutputs <- utxoAt gameAddress + let redeemer = clearString theGuess + tx = collectFromScript unspentOutputs redeemer + void (submitTxConstraintsSpending gameInstance unspentOutputs tx) + +game :: AsContractError e => Contract () GameSchema e () +game = lock `select` guess + +lockTrace :: EmulatorTrace () +lockTrace = do + let w1 = Wallet 1 + hdl <- Trace.activateContractWallet w1 (game @ContractError) + Trace.callEndpoint @"lock" hdl (LockParams "secret" (Ada.lovelaceValueOf 10)) + void $ Trace.waitNSlots 1 + +guessTrace :: EmulatorTrace () +guessTrace = do + lockTrace + let w2 = Wallet 2 + hdl <- Trace.activateContractWallet w2 (game @ContractError) + Trace.callEndpoint @"guess" hdl (GuessParams "secret") + +guessWrongTrace :: EmulatorTrace () +guessWrongTrace = do + lockTrace + let w2 = Wallet 2 + hdl <- Trace.activateContractWallet w2 (game @ContractError) + Trace.callEndpoint @"guess" hdl (GuessParams "SECRET") diff --git a/MetaLamp/lending-pool/examples/test/Spec.hs b/MetaLamp/lending-pool/examples/test/Spec.hs new file mode 100644 index 000000000..60001de7b --- /dev/null +++ b/MetaLamp/lending-pool/examples/test/Spec.hs @@ -0,0 +1,21 @@ +{-# LANGUAGE OverloadedStrings #-} +module Main(main) where + +import qualified Spec.Game +import Test.Tasty +import Test.Tasty.Hedgehog (HedgehogTestLimit (..)) + +main :: IO () +main = defaultMain tests + +-- | Number of successful tests for each hedgehog property. +-- The default is 100 but we use a smaller number here in order to speed up +-- the test suite. +-- +limit :: HedgehogTestLimit +limit = HedgehogTestLimit (Just 5) + +tests :: TestTree +tests = localOption limit $ testGroup "use cases" [ + Spec.Game.tests + ] diff --git a/MetaLamp/lending-pool/examples/test/Spec/Game.hs b/MetaLamp/lending-pool/examples/test/Spec/Game.hs new file mode 100644 index 000000000..e479d43ad --- /dev/null +++ b/MetaLamp/lending-pool/examples/test/Spec/Game.hs @@ -0,0 +1,60 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} + +module Spec.Game + ( tests + ) where + +import Control.Monad (void) +import Ledger.Ada (adaValueOf) +import Plutus.Contract (Contract, ContractError) +import Plutus.Contract.Test +import Plutus.Contracts.Game +import Plutus.Trace.Emulator (ContractInstanceTag) +import qualified Plutus.Trace.Emulator as Trace +import qualified PlutusTx +import qualified PlutusTx.Prelude as PlutusTx +import Test.Tasty +import qualified Test.Tasty.HUnit as HUnit + +w1, w2 :: Wallet +w1 = Wallet 1 +w2 = Wallet 2 + +t1, t2 :: ContractInstanceTag +t1 = Trace.walletInstanceTag w1 +t2 = Trace.walletInstanceTag w2 + +theContract :: Contract () GameSchema ContractError () +theContract = game + +tests :: TestTree +tests = testGroup "game" + [ checkPredicate "Expose 'lock' and 'guess' endpoints" + (endpointAvailable @"lock" theContract (Trace.walletInstanceTag w1) + .&&. endpointAvailable @"guess" theContract (Trace.walletInstanceTag w1)) + $ void (Trace.activateContractWallet w1 theContract) + + , checkPredicate "'lock' endpoint submits a transaction" + (anyTx theContract (Trace.walletInstanceTag w1)) + $ do + hdl <- Trace.activateContractWallet w1 theContract + Trace.callEndpoint @"lock" hdl (LockParams "secret" (adaValueOf 10)) + + , checkPredicate "'guess' endpoint is available after locking funds" + (endpointAvailable @"guess" theContract (Trace.walletInstanceTag w2)) + lockTrace + + , checkPredicate "guess right (unlock funds)" + (walletFundsChange w2 (1 `timesFeeAdjust` 10) + .&&. walletFundsChange w1 (1 `timesFeeAdjust` (-10))) + guessTrace + + , checkPredicate "guess wrong" + (walletFundsChange w2 PlutusTx.zero + .&&. walletFundsChange w1 (1 `timesFeeAdjust` (-10))) + guessWrongTrace + , goldenPir "examples/test/Spec/game.pir" $$(PlutusTx.compile [|| validateGuess ||]) + , HUnit.testCase "script size is reasonable" (reasonable gameValidator 20000) + ] diff --git a/MetaLamp/lending-pool/examples/test/Spec/game.pir b/MetaLamp/lending-pool/examples/test/Spec/game.pir new file mode 100644 index 000000000..dcea0aeab --- /dev/null +++ b/MetaLamp/lending-pool/examples/test/Spec/game.pir @@ -0,0 +1,217 @@ +(program + (let + (nonrec) + (datatypebind + (datatype + (tyvardecl Tuple2 (fun (type) (fun (type) (type)))) + (tyvardecl a (type)) (tyvardecl b (type)) + Tuple2_match + (vardecl Tuple2 (fun a (fun b [[Tuple2 a] b]))) + ) + ) + (let + (rec) + (datatypebind + (datatype + (tyvardecl List (fun (type) (type))) + (tyvardecl a (type)) + Nil_match + (vardecl Nil [List a]) (vardecl Cons (fun a (fun [List a] [List a]))) + ) + ) + (let + (rec) + (datatypebind + (datatype + (tyvardecl Data (type)) + + Data_match + (vardecl B (fun (con bytestring) Data)) + (vardecl Constr (fun (con integer) (fun [List Data] Data))) + (vardecl I (fun (con integer) Data)) + (vardecl List (fun [List Data] Data)) + (vardecl Map (fun [List [[Tuple2 Data] Data]] Data)) + ) + ) + (let + (nonrec) + (datatypebind + (datatype + (tyvardecl Extended (fun (type) (type))) + (tyvardecl a (type)) + Extended_match + (vardecl Finite (fun a [Extended a])) + (vardecl NegInf [Extended a]) + (vardecl PosInf [Extended a]) + ) + ) + (datatypebind + (datatype + (tyvardecl Bool (type)) + + Bool_match + (vardecl True Bool) (vardecl False Bool) + ) + ) + (datatypebind + (datatype + (tyvardecl LowerBound (fun (type) (type))) + (tyvardecl a (type)) + LowerBound_match + (vardecl LowerBound (fun [Extended a] (fun Bool [LowerBound a]))) + ) + ) + (datatypebind + (datatype + (tyvardecl UpperBound (fun (type) (type))) + (tyvardecl a (type)) + UpperBound_match + (vardecl UpperBound (fun [Extended a] (fun Bool [UpperBound a]))) + ) + ) + (datatypebind + (datatype + (tyvardecl Interval (fun (type) (type))) + (tyvardecl a (type)) + Interval_match + (vardecl + Interval (fun [LowerBound a] (fun [UpperBound a] [Interval a])) + ) + ) + ) + (datatypebind + (datatype + (tyvardecl Tuple3 (fun (type) (fun (type) (fun (type) (type))))) + (tyvardecl a (type)) (tyvardecl b (type)) (tyvardecl c (type)) + Tuple3_match + (vardecl Tuple3 (fun a (fun b (fun c [[[Tuple3 a] b] c])))) + ) + ) + (datatypebind + (datatype + (tyvardecl Maybe (fun (type) (type))) + (tyvardecl a (type)) + Maybe_match + (vardecl Just (fun a [Maybe a])) (vardecl Nothing [Maybe a]) + ) + ) + (datatypebind + (datatype + (tyvardecl TxOutRef (type)) + + TxOutRef_match + (vardecl + TxOutRef (fun (con bytestring) (fun (con integer) TxOutRef)) + ) + ) + ) + (datatypebind + (datatype + (tyvardecl TxInInfo (type)) + + TxInInfo_match + (vardecl + TxInInfo + (fun TxOutRef (fun [Maybe [[[Tuple3 (con bytestring)] (con bytestring)] (con bytestring)]] (fun [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] (con integer)]] TxInInfo))) + ) + ) + ) + (datatypebind + (datatype + (tyvardecl Address (type)) + + Address_match + (vardecl PubKeyAddress (fun (con bytestring) Address)) + (vardecl ScriptAddress (fun (con bytestring) Address)) + ) + ) + (datatypebind + (datatype + (tyvardecl TxOutType (type)) + + TxOutType_match + (vardecl PayToPubKey TxOutType) + (vardecl PayToScript (fun (con bytestring) TxOutType)) + ) + ) + (datatypebind + (datatype + (tyvardecl TxOut (type)) + + TxOut_match + (vardecl + TxOut + (fun Address (fun [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] (con integer)]] (fun TxOutType TxOut))) + ) + ) + ) + (datatypebind + (datatype + (tyvardecl TxInfo (type)) + + TxInfo_match + (vardecl + TxInfo + (fun [List TxInInfo] (fun [List TxOut] (fun [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] (con integer)]] (fun [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] (con integer)]] (fun [Interval (con integer)] (fun [List (con bytestring)] (fun [List (con bytestring)] (fun [List [[Tuple2 (con bytestring)] Data]] (fun (con bytestring) TxInfo))))))))) + ) + ) + ) + (datatypebind + (datatype + (tyvardecl ValidatorCtx (type)) + + ValidatorCtx_match + (vardecl + ValidatorCtx (fun TxInfo (fun (con integer) ValidatorCtx)) + ) + ) + ) + (termbind + (strict) + (vardecl + equalsByteString + (fun (con bytestring) (fun (con bytestring) Bool)) + ) + (lam + arg + (con bytestring) + (lam + arg + (con bytestring) + [ + (lam + b + (con bool) + [ [ [ { (builtin ifThenElse) Bool } b ] True ] False ] + ) + [ [ (builtin equalsByteString) arg ] arg ] + ] + ) + ) + ) + (termbind + (strict) + (vardecl + validateGuess + (fun (con bytestring) (fun (con bytestring) (fun ValidatorCtx Bool))) + ) + (lam + ds + (con bytestring) + (lam + ds + (con bytestring) + (lam + ds + ValidatorCtx + [ [ equalsByteString ds ] [ (builtin sha2_256) ds ] ] + ) + ) + ) + ) + validateGuess + ) + ) + ) + ) +) \ No newline at end of file diff --git a/MetaLamp/lending-pool/hie.yaml b/MetaLamp/lending-pool/hie.yaml new file mode 100644 index 000000000..04cd24395 --- /dev/null +++ b/MetaLamp/lending-pool/hie.yaml @@ -0,0 +1,2 @@ +cradle: + cabal: diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs new file mode 100644 index 000000000..10822ec12 --- /dev/null +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -0,0 +1,90 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + +module Main(main) where + +import Control.Monad (void) +import Control.Monad.Freer (Eff, Member, interpret, type (~>)) +import Control.Monad.Freer.Error (Error) +import Control.Monad.IO.Class (MonadIO (..)) +import Data.Aeson (FromJSON (..), ToJSON (..), genericToJSON, genericParseJSON + , defaultOptions, Options(..)) +import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) +import GHC.Generics (Generic) +import Plutus.Contract (BlockchainActions, ContractError) +import Plutus.PAB.Effects.Contract (ContractEffect (..)) +import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), type (.\\)) +import qualified Plutus.PAB.Effects.Contract.Builtin as Builtin +import Plutus.PAB.Simulator (SimulatorEffectHandlers) +import qualified Plutus.PAB.Simulator as Simulator +import Plutus.PAB.Types (PABError (..)) +import qualified Plutus.PAB.Webserver.Server as PAB.Server +import Plutus.Contracts.Game as Game +import Wallet.Emulator.Types (Wallet (..)) + +main :: IO () +main = void $ Simulator.runSimulationWith handlers $ do + Simulator.logString @(Builtin StarterContracts) "Starting plutus-starter PAB webserver on port 8080. Press enter to exit." + shutdown <- PAB.Server.startServerDebug + -- Example of spinning up a game instance on startup + -- void $ Simulator.activateContract (Wallet 1) GameContract + -- You can add simulator actions here: + -- Simulator.observableState + -- etc. + -- That way, the simulation gets to a predefined state and you don't have to + -- use the HTTP API for setup. + + -- Pressing enter results in the balances being printed + void $ liftIO getLine + + Simulator.logString @(Builtin StarterContracts) "Balances at the end of the simulation" + b <- Simulator.currentBalances + Simulator.logBalances @(Builtin StarterContracts) b + + shutdown + +data StarterContracts = + GameContract + deriving (Eq, Ord, Show, Generic) + +-- NOTE: Because 'StarterContracts' only has one constructor, corresponding to +-- the demo 'Game' contract, we kindly ask aeson to still encode it as if it had +-- many; this way we get to see the label of the contract in the API output! +-- If you simple have more contracts, you can just use the anyclass deriving +-- statement on 'StarterContracts' instead: +-- +-- `... deriving anyclass (ToJSON, FromJSON)` +instance ToJSON StarterContracts where + toJSON = genericToJSON defaultOptions { + tagSingleConstructors = True } +instance FromJSON StarterContracts where + parseJSON = genericParseJSON defaultOptions { + tagSingleConstructors = True } + +instance Pretty StarterContracts where + pretty = viaShow + +handleStarterContract :: + ( Member (Error PABError) effs + ) + => ContractEffect (Builtin StarterContracts) + ~> Eff effs +handleStarterContract = Builtin.handleBuiltin getSchema getContract where + getSchema = \case + GameContract -> Builtin.endpointsToSchemas @(Game.GameSchema .\\ BlockchainActions) + getContract = \case + GameContract -> SomeBuiltin (Game.game @ContractError) + +handlers :: SimulatorEffectHandlers (Builtin StarterContracts) +handlers = + Simulator.mkSimulatorHandlers @(Builtin StarterContracts) [GameContract] + $ interpret handleStarterContract + diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal new file mode 100644 index 000000000..224e769ab --- /dev/null +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -0,0 +1,81 @@ +cabal-version: 2.4 +name: plutus-starter +version: 0.1.0.0 + +-- A short (one-line) description of the package. +-- synopsis: + +-- A longer description of the package. +-- description: + +-- A URL where users can report bugs. +-- bug-reports: + +license: Apache-2.0 +license-files: LICENSE +author: Your name +maintainer: Your email + +-- A copyright notice. +-- copyright: +-- category: +-- extra-source-files: CHANGELOG.md + +library + exposed-modules: + MyModule + Plutus.Contracts.Game + build-depends: + base >= 4.9 && < 5, + aeson, + bytestring, + playground-common, + plutus-contract, + plutus-tx-plugin, + plutus-tx, + plutus-ledger + hs-source-dirs: src examples/src + default-language: Haskell2010 + ghc-options: + -- See Plutus Tx readme + -fobject-code -fno-ignore-interface-pragmas -fno-omit-interface-pragmas + +test-suite plutus-example-projects-test + type: exitcode-stdio-1.0 + main-is: Spec.hs + hs-source-dirs: examples/test + other-modules: + Spec.Game + default-language: Haskell2010 + ghc-options: -Wall -Wnoncanonical-monad-instances + -Wincomplete-uni-patterns -Wincomplete-record-updates + -Wredundant-constraints -Widentities -rtsopts + -- See Plutus Tx readme + -fobject-code -fno-ignore-interface-pragmas -fno-omit-interface-pragmas + build-depends: + plutus-tx -any, + plutus-tx-plugin, + plutus-contract -any, + plutus-ledger -any, + plutus-starter -any + build-depends: + base >=4.9 && <5, + tasty -any, + tasty-hunit -any, + tasty-hedgehog >=0.2.0.0 + +executable plutus-starter-pab + main-is: Main.hs + hs-source-dirs: pab + ghc-options: + -threaded + build-depends: + base >= 4.9 && < 5, + plutus-contract -any, + plutus-pab -any, + plutus-starter -any, + aeson -any, + freer-simple -any, + prettyprinter -any, + freer-extras -any, + plutus-ledger -any diff --git a/MetaLamp/lending-pool/src/MyModule.hs b/MetaLamp/lending-pool/src/MyModule.hs new file mode 100644 index 000000000..2a1505371 --- /dev/null +++ b/MetaLamp/lending-pool/src/MyModule.hs @@ -0,0 +1,7 @@ +module MyModule where + +hello :: String +hello = "hello" + +main :: IO () +main = putStrLn hello \ No newline at end of file From 86e851e9af82a94c4fcce25137cb6f98f2bd25c5 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 28 Apr 2021 15:42:25 +0700 Subject: [PATCH 002/169] cp analogous uniswap impl --- MetaLamp/lending-pool/plutus-starter.cabal | 7 +- .../src/Plutus/Contracts/LendingPool.hs | 588 ++++++++++++++++++ 2 files changed, 594 insertions(+), 1 deletion(-) create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 224e769ab..162ad3148 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -25,15 +25,20 @@ library exposed-modules: MyModule Plutus.Contracts.Game + Plutus.Contracts.LendingPool build-depends: base >= 4.9 && < 5, aeson, bytestring, + containers, + text, + -- Plutus: playground-common, plutus-contract, plutus-tx-plugin, plutus-tx, - plutus-ledger + plutus-ledger, + plutus-use-cases hs-source-dirs: src examples/src default-language: Haskell2010 ghc-options: diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs new file mode 100644 index 000000000..3bd131b51 --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -0,0 +1,588 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + + +module Plutus.Contracts.LendingPool + ( Coin (..) + , coin, coinValueOf + , Uniswap (..), uniswap + , poolStateCoinFromUniswapCurrency, liquidityCoin + , CreateParams (..) + , CloseParams (..) + , UniswapUserSchema, UserContractState (..) + , start, create, close + , ownerEndpoint, userEndpoints + ) where + +import Control.Monad hiding (fmap) +import qualified Data.Map as Map +import Data.Monoid (Last (..)) +import Data.Proxy (Proxy (..)) +import Data.Text (Text, pack) +import Data.Void (Void) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as Scripts +import qualified Ledger.Typed.Scripts as Scripts +import Ledger.Value as Value +import Playground.Contract +import Plutus.Contract hiding (when) +-- TODO remove that dep Plutus.Contracts.Currency (?) +import qualified Plutus.Contracts.Currency as Currency +import qualified PlutusTx +import PlutusTx.Prelude hiding (Semigroup (..), unless) +import Prelude (Semigroup (..)) +import qualified Prelude +import Text.Printf (printf) + +feeNum, feeDen :: Integer +feeNum = 3 +feeDen = 1000 + +uniswapTokenName, poolStateTokenName :: TokenName +uniswapTokenName = "Uniswap" +poolStateTokenName = "Pool State" + +-- | A pair consisting of a 'CurrencySymbol' and a 'TokenName'. +-- Coins are the entities that can be swapped in the exchange. +data Coin = Coin + { cCurrency :: CurrencySymbol + , cToken :: TokenName + } deriving (Show, Generic, ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''Coin +PlutusTx.makeLift ''Coin + +instance Eq Coin where + {-# INLINABLE (==) #-} + c == d = cCurrency c == cCurrency d && cToken c == cToken d + +instance Prelude.Eq Coin where + (==) = (==) + +{-# INLINABLE compareCoins #-} +compareCoins :: Coin -> Coin -> Ordering +compareCoins c d = case compare (cCurrency c) (cCurrency d) of + LT -> LT + GT -> GT + EQ -> compare (cToken c) (cToken d) + +instance Prelude.Ord Coin where + compare = compareCoins + +{-# INLINABLE coinLT #-} +coinLT :: Coin -> Coin -> Bool +coinLT c d = case compareCoins c d of + LT -> True + _ -> False + +{-# INLINABLE coin #-} +-- | @'coin' c n@ denotes the value given by @n@ units of @'Coin'@ @c@. +coin :: Coin -- ^ The 'Coin'. + -> Integer -- ^ The desired number coins. + -> Value -- ^ The 'Value' consisting of the given number of units of the given 'Coin'. +coin Coin{..} = Value.singleton cCurrency cToken + +{-# INLINABLE coinValueOf #-} +-- | Calculates how many units of the specified 'Coin' are contained in the +-- given 'Value'. +coinValueOf :: Value -- ^ The 'Value' to inspect. + -> Coin -- ^ The 'Coin' to look for. + -> Integer -- ^ The number of units of the given 'Coin' contained in the given 'Value'. +coinValueOf v Coin{..} = valueOf v cCurrency cToken + +{-# INLINABLE hashCoin #-} +hashCoin :: Coin -> ByteString +hashCoin Coin{..} = sha2_256 $ concatenate (unCurrencySymbol cCurrency) (unTokenName cToken) + +data Sqrt = + Imaginary + | Exact Integer + | Irrational Integer + deriving stock Show + +PlutusTx.unstableMakeIsData ''Sqrt +PlutusTx.makeLift ''Sqrt + +{-# INLINABLE rsqrt #-} +rsqrt :: Integer -> Integer -> Sqrt +rsqrt n d + | n * d < 0 = Imaginary + | n == 0 = Exact 0 + | n == d = Exact 1 + | n < 0 = rsqrt (negate n) (negate d) + | otherwise = go 1 $ 1 + divide n d + where + go :: Integer -> Integer -> Sqrt + go l u + | l * l * d == n = Exact l + | u == (l + 1) = Irrational l + | otherwise = + let + m = divide (l + u) 2 + in + if m * m * d <= n then go m u + else go l m + +{-# INLINABLE isqrt #-} +isqrt :: Integer -> Sqrt +isqrt n = rsqrt n 1 + +{-# INLINABLE calculateInitialLiquidity #-} +calculateInitialLiquidity :: Integer -> Integer -> Integer +calculateInitialLiquidity outA outB = case isqrt (outA * outB) of + Exact l + | l > 0 -> l + Irrational l + | l > 0 -> l + 1 + _ -> traceError "insufficient liquidity" + +data LiquidityPool = LiquidityPool + { lpCoinA :: Coin + , lpCoinB :: Coin + } deriving (Show, Generic, ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''LiquidityPool +PlutusTx.makeLift ''LiquidityPool + +instance Eq LiquidityPool where + {-# INLINABLE (==) #-} + x == y = (lpCoinA x == lpCoinA y && lpCoinB x == lpCoinB y) || + (lpCoinA x == lpCoinB y && lpCoinB x == lpCoinA y) + +{-# INLINABLE hashLiquidityPool #-} +hashLiquidityPool :: LiquidityPool -> ByteString +hashLiquidityPool LiquidityPool{..} = sha2_256 $ concatenate (hashCoin c) (hashCoin d) + where + (c, d) + | lpCoinA `coinLT` lpCoinB = (lpCoinA, lpCoinB) + | otherwise = (lpCoinB, lpCoinA) + +newtype Uniswap = Uniswap + { usCoin :: Coin + } deriving stock (Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.makeLift ''Uniswap + +instance Prelude.Eq Uniswap where + u == v = usCoin u Prelude.== usCoin v + +instance Prelude.Ord Uniswap where + compare u v = Prelude.compare (usCoin u) (usCoin v) + +data UniswapAction = Create LiquidityPool | Close + deriving Show + +PlutusTx.unstableMakeIsData ''UniswapAction +PlutusTx.makeLift ''UniswapAction + +data UniswapDatum = + Factory [LiquidityPool] + | Pool LiquidityPool Integer + deriving stock (Show) + +PlutusTx.unstableMakeIsData ''UniswapDatum +PlutusTx.makeLift ''UniswapDatum + +data Uniswapping +instance Scripts.ScriptType Uniswapping where + type instance RedeemerType Uniswapping = UniswapAction + type instance DatumType Uniswapping = UniswapDatum + +{-# INLINABLE validateCreate #-} +validateCreate :: Uniswap + -> Coin + -> [LiquidityPool] + -> LiquidityPool + -> ValidatorCtx + -> Bool +validateCreate Uniswap{..} c lps lp@LiquidityPool{..} ctx = + traceIfFalse "Uniswap coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) usCoin == 1) && + (lpCoinA /= lpCoinB) && + all (/= lp) lps && + Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ coin usCoin 1) && + (coinValueOf forged c == 1) && + (coinValueOf forged liquidityCoin' == liquidity) && + (outA > 0) && + (outB > 0) && + Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp liquidity) $ + coin lpCoinA outA <> coin lpCoinB outB <> coin c 1) + where + poolOutput :: TxOutInfo + poolOutput = case [o | o <- getContinuingOutputs ctx, coinValueOf (txOutValue o) c == 1] of + [o] -> o + _ -> traceError "expected exactly one pool output" + + outA, outB, liquidity :: Integer + outA = coinValueOf (txOutValue poolOutput) lpCoinA + outB = coinValueOf (txOutValue poolOutput) lpCoinB + liquidity = calculateInitialLiquidity outA outB + + forged :: Value + forged = txInfoForge $ valCtxTxInfo ctx + + liquidityCoin' :: Coin + liquidityCoin' = let Coin cs _ = c in Coin cs $ lpTicker lp + +{-# INLINABLE validateCloseFactory #-} +validateCloseFactory :: Uniswap -> Coin -> [LiquidityPool] -> ValidatorCtx -> Bool +validateCloseFactory us c lps ctx = + traceIfFalse "Uniswap coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) usC == 1) && + traceIfFalse "wrong forge value" (txInfoForge info == negate (coin c 1 <> coin lC (snd lpLiquidity))) && + traceIfFalse "factory output wrong" + (Constraints.checkOwnOutputConstraint ctx $ OutputConstraint (Factory $ filter (/= fst lpLiquidity) lps) $ coin usC 1) + where + info :: TxInfo + info = valCtxTxInfo ctx + + poolInput :: TxInInfo + poolInput = case [ i + | i <- txInfoInputs info + , coinValueOf (txInInfoValue i) c == 1 + ] of + [i] -> i + _ -> traceError "expected exactly one pool input" + + lpLiquidity :: (LiquidityPool, Integer) + lpLiquidity = case txInInfoWitness poolInput of + Nothing -> traceError "pool input witness missing" + Just (_, _, h) -> findPoolDatum info h + + lC, usC :: Coin + lC = Coin (cCurrency c) (lpTicker $ fst lpLiquidity) + usC = usCoin us + +{-# INLINABLE validateClosePool #-} +validateClosePool :: Uniswap -> ValidatorCtx -> Bool +validateClosePool us ctx = hasFactoryInput + where + info :: TxInfo + info = valCtxTxInfo ctx + + hasFactoryInput :: Bool + hasFactoryInput = + traceIfFalse "Uniswap factory input expected" $ + coinValueOf (valueSpent info) (usCoin us) == 1 + + +{-# INLINABLE findPoolDatum #-} +findPoolDatum :: TxInfo -> DatumHash -> (LiquidityPool, Integer) +findPoolDatum info h = case findDatum h info of + Just (Datum d) -> case PlutusTx.fromData d of + Just (Pool lp a) -> (lp, a) + _ -> traceError "error decoding data" + _ -> traceError "pool input datum not found" + +{-# INLINABLE lpTicker #-} +lpTicker :: LiquidityPool -> TokenName +--lpTicker = TokenName . hashLiquidityPool +lpTicker LiquidityPool{..} = TokenName $ + unCurrencySymbol (cCurrency c) `concatenate` + unCurrencySymbol (cCurrency d) `concatenate` + unTokenName (cToken c) `concatenate` + unTokenName (cToken d) + where + (c, d) + | lpCoinA `coinLT` lpCoinB = (lpCoinA, lpCoinB) + | otherwise = (lpCoinB, lpCoinA) + +mkUniswapValidator :: Uniswap + -> Coin + -> UniswapDatum + -> UniswapAction + -> ValidatorCtx + -> Bool +mkUniswapValidator us c (Factory lps) (Create lp) ctx = validateCreate us c lps lp ctx +mkUniswapValidator us c (Factory lps) Close ctx = validateCloseFactory us c lps ctx +mkUniswapValidator us _ (Pool _ _) Close ctx = validateClosePool us ctx +mkUniswapValidator _ _ _ _ _ = False + +validateLiquidityForging :: Uniswap -> TokenName -> PolicyCtx -> Bool +validateLiquidityForging us tn ctx = case [ i + | i <- txInfoInputs $ policyCtxTxInfo ctx + , let v = txInInfoValue i + , (coinValueOf v usC == 1) || + (coinValueOf v lpC == 1) + ] of + [_] -> True + [_, _] -> True + _ -> traceError "pool state forging without Uniswap input" + where + usC, lpC :: Coin + usC = usCoin us + lpC = Coin (ownCurrencySymbol ctx) tn + +uniswapInstance :: Uniswap -> Scripts.ScriptInstance Uniswapping +uniswapInstance us = Scripts.validator @Uniswapping + ($$(PlutusTx.compile [|| mkUniswapValidator ||]) + `PlutusTx.applyCode` PlutusTx.liftCode us + `PlutusTx.applyCode` PlutusTx.liftCode c) + $$(PlutusTx.compile [|| wrap ||]) + where + c :: Coin + c = poolStateCoin us + + wrap = Scripts.wrapValidator @UniswapDatum @UniswapAction + +uniswapScript :: Uniswap -> Validator +uniswapScript = Scripts.validatorScript . uniswapInstance + +uniswapHash :: Uniswap -> Ledger.ValidatorHash +uniswapHash = Scripts.validatorHash . uniswapScript + +uniswapAddress :: Uniswap -> Ledger.Address +uniswapAddress = ScriptAddress . uniswapHash + +uniswap :: CurrencySymbol -> Uniswap +uniswap cs = Uniswap $ Coin cs uniswapTokenName + +liquidityPolicy :: Uniswap -> MonetaryPolicy +liquidityPolicy us = mkMonetaryPolicyScript $ + $$(PlutusTx.compile [|| \u t -> Scripts.wrapMonetaryPolicy (validateLiquidityForging u t) ||]) + `PlutusTx.applyCode` PlutusTx.liftCode us + `PlutusTx.applyCode` PlutusTx.liftCode poolStateTokenName + +liquidityCurrency :: Uniswap -> CurrencySymbol +liquidityCurrency = scriptCurrencySymbol . liquidityPolicy + +poolStateCoin :: Uniswap -> Coin +poolStateCoin = flip Coin poolStateTokenName . liquidityCurrency + +-- | Gets the 'Coin' used to identity liquidity pools. +poolStateCoinFromUniswapCurrency :: CurrencySymbol -- ^ The currency identifying the Uniswap instance. + -> Coin +poolStateCoinFromUniswapCurrency = poolStateCoin . uniswap + +-- | Gets the liquidity token for a given liquidity pool. +liquidityCoin :: CurrencySymbol -- ^ The currency identifying the Uniswap instance. + -> Coin -- ^ One coin in the liquidity pair. + -> Coin -- ^ The other coin in the liquidity pair. + -> Coin +liquidityCoin cs coinA coinB = Coin (liquidityCurrency $ uniswap cs) $ lpTicker $ LiquidityPool coinA coinB + +-- | Paraneters for the @create@-endpoint, which creates a new liquidity pool. +data CreateParams = CreateParams + { cpCoinA :: Coin -- ^ One 'Coin' of the liquidity pair. + , cpCoinB :: Coin -- ^ The other 'Coin'. + , cpAmountA :: Integer -- ^ Amount of liquidity for the first 'Coin'. + , cpAmountB :: Integer -- ^ Amount of liquidity for the second 'Coin'. + } deriving (Show, Generic, ToJSON, FromJSON, ToSchema) + +-- | Parameters for the @close@-endpoint, which closes a liquidity pool. +data CloseParams = CloseParams + { clpCoinA :: Coin -- ^ One 'Coin' of the liquidity pair. + , clpCoinB :: Coin -- ^ The other 'Coin' of the liquidity pair. + } deriving (Show, Generic, ToJSON, FromJSON, ToSchema) + +-- | Creates a Uniswap "factory". This factory will keep track of the existing liquidity pools and enforce that there will be at most one liquidity pool +-- for any pair of tokens at any given time. +start :: HasBlockchainActions s => Contract w s Text Uniswap +start = do + pkh <- pubKeyHash <$> ownPubKey + cs <- fmap Currency.currencySymbol $ + mapError (pack . show @Currency.CurrencyError) $ + Currency.forgeContract pkh [(uniswapTokenName, 1)] + let c = Coin cs uniswapTokenName + us = uniswap cs + inst = uniswapInstance us + tx = mustPayToTheScript (Factory []) $ coin c 1 + ledgerTx <- submitTxConstraints inst tx + void $ awaitTxConfirmed $ txId ledgerTx + + logInfo @String $ printf "started Uniswap %s at address %s" (show us) (show $ uniswapAddress us) + return us + +-- | Creates a liquidity pool for a pair of coins. The creator provides liquidity for both coins and gets liquidity tokens in return. +create :: HasBlockchainActions s => Uniswap -> CreateParams -> Contract w s Text () +create us CreateParams{..} = do + when (cpCoinA == cpCoinB) $ throwError "coins must be different" + when (cpAmountA <= 0 || cpAmountB <= 0) $ throwError "amounts must be positive" + (oref, o, lps) <- findUniswapFactory us + let liquidity = calculateInitialLiquidity cpAmountA cpAmountB + lp = LiquidityPool {lpCoinA = cpCoinA, lpCoinB = cpCoinB} + let usInst = uniswapInstance us + usScript = uniswapScript us + usDat1 = Factory $ lp : lps + usDat2 = Pool lp liquidity + psC = poolStateCoin us + lC = Coin (liquidityCurrency us) $ lpTicker lp + usVal = coin (usCoin us) 1 + lpVal = coin cpCoinA cpAmountA <> coin cpCoinB cpAmountB <> coin psC 1 + + lookups = Constraints.scriptInstanceLookups usInst <> + Constraints.otherScript usScript <> + Constraints.monetaryPolicy (liquidityPolicy us) <> + Constraints.unspentOutputs (Map.singleton oref o) + + tx = Constraints.mustPayToTheScript usDat1 usVal <> + Constraints.mustPayToTheScript usDat2 lpVal <> + Constraints.mustForgeValue (coin psC 1 <> coin lC liquidity) <> + Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ Create lp) + + ledgerTx <- submitTxConstraintsWith lookups tx + void $ awaitTxConfirmed $ txId ledgerTx + + logInfo $ "created liquidity pool: " ++ show lp + +-- | Closes a liquidity pool by burning all remaining liquidity tokens in exchange for all liquidity remaining in the pool. +close :: HasBlockchainActions s => Uniswap -> CloseParams -> Contract w s Text () +close us CloseParams{..} = do + ((oref1, o1, lps), (oref2, o2, lp, liquidity)) <- findUniswapFactoryAndPool us clpCoinA clpCoinB + pkh <- pubKeyHash <$> ownPubKey + let usInst = uniswapInstance us + usScript = uniswapScript us + usDat = Factory $ filter (/= lp) lps + usC = usCoin us + psC = poolStateCoin us + lC = Coin (liquidityCurrency us) $ lpTicker lp + usVal = coin usC 1 + psVal = coin psC 1 + lVal = coin lC liquidity + redeemer = Redeemer $ PlutusTx.toData Close + + lookups = Constraints.scriptInstanceLookups usInst <> + Constraints.otherScript usScript <> + Constraints.monetaryPolicy (liquidityPolicy us) <> + Constraints.ownPubKeyHash pkh <> + Constraints.unspentOutputs (Map.singleton oref1 o1 <> Map.singleton oref2 o2) + + tx = Constraints.mustPayToTheScript usDat usVal <> + Constraints.mustForgeValue (negate $ psVal <> lVal) <> + Constraints.mustSpendScriptOutput oref1 redeemer <> + Constraints.mustSpendScriptOutput oref2 redeemer <> + Constraints.mustIncludeDatum (Datum $ PlutusTx.toData $ Pool lp liquidity) + + ledgerTx <- submitTxConstraintsWith lookups tx + void $ awaitTxConfirmed $ txId ledgerTx + + logInfo $ "closed liquidity pool: " ++ show lp + +getUniswapDatum :: TxOutTx -> Contract w s Text UniswapDatum +getUniswapDatum o = case txOutType $ txOutTxOut o of + PayToPubKey -> throwError "unexpected out type" + PayToScript h -> case Map.lookup h $ txData $ txOutTxTx o of + Nothing -> throwError "datum not found" + Just (Datum e) -> case PlutusTx.fromData e of + Nothing -> throwError "datum has wrong type" + Just d -> return d + +findUniswapInstance :: HasBlockchainActions s => Uniswap -> Coin -> (UniswapDatum -> Maybe a) -> Contract w s Text (TxOutRef, TxOutTx, a) +findUniswapInstance us c f = do + let addr = uniswapAddress us + logInfo @String $ printf "looking for Uniswap instance at address %s containing coin %s " (show addr) (show c) + utxos <- utxoAt addr + go [x | x@(_, o) <- Map.toList utxos, coinValueOf (txOutValue $ txOutTxOut o) c == 1] + where + go [] = throwError "Uniswap instance not found" + go ((oref, o) : xs) = do + d <- getUniswapDatum o + case f d of + Nothing -> go xs + Just a -> do + logInfo @String $ printf "found Uniswap instance with datum: %s" (show d) + return (oref, o, a) + +findUniswapFactory :: HasBlockchainActions s => Uniswap -> Contract w s Text (TxOutRef, TxOutTx, [LiquidityPool]) +findUniswapFactory us@Uniswap{..} = findUniswapInstance us usCoin $ \case + Factory lps -> Just lps + Pool _ _ -> Nothing + +findUniswapPool :: HasBlockchainActions s => Uniswap -> LiquidityPool -> Contract w s Text (TxOutRef, TxOutTx, Integer) +findUniswapPool us lp = findUniswapInstance us (poolStateCoin us) $ \case + Pool lp' l + | lp == lp' -> Just l + _ -> Nothing + +findUniswapFactoryAndPool :: HasBlockchainActions s + => Uniswap + -> Coin + -> Coin + -> Contract w s Text ( (TxOutRef, TxOutTx, [LiquidityPool]) + , (TxOutRef, TxOutTx, LiquidityPool, Integer) + ) +findUniswapFactoryAndPool us coinA coinB = do + (oref1, o1, lps) <- findUniswapFactory us + case [ lp' + | lp' <- lps + , lp' == LiquidityPool coinA coinB + ] of + [lp] -> do + (oref2, o2, a) <- findUniswapPool us lp + return ( (oref1, o1, lps) + , (oref2, o2, lp, a) + ) + _ -> throwError "liquidity pool not found" + +ownerEndpoint :: Contract (Last (Either Text Uniswap)) BlockchainActions Void () +ownerEndpoint = do + e <- runError start + tell $ Last $ Just $ case e of + Left err -> Left err + Right us -> Right us + +-- | Schema for the endpoints for users of Uniswap. +type UniswapUserSchema = + BlockchainActions + .\/ Endpoint "create" CreateParams + .\/ Endpoint "close" CloseParams + .\/ Endpoint "stop" () + +-- | Type of the Uniswap user contract state. +data UserContractState = + Pools [((Coin, Integer), (Coin, Integer))] + | Funds Value + | Created + | Closed + | Stopped + deriving (Show, Generic, FromJSON, ToJSON) + +-- | Provides the following endpoints for users of a Uniswap instance: +-- +-- [@create@]: Creates a liquidity pool for a pair of coins. The creator provides liquidity for both coins and gets liquidity tokens in return. +-- [@close@]: Closes a liquidity pool by burning all remaining liquidity tokens in exchange for all liquidity remaining in the pool. +-- [@stop@]: Stops the contract. +userEndpoints :: Uniswap -> Contract (Last (Either Text UserContractState)) UniswapUserSchema Void () +userEndpoints us = + stop + `select` + ((f (Proxy @"create") (const Created) create `select` + f (Proxy @"close") (const Closed) close ) + >> userEndpoints us) + where + f :: forall l a p. + HasEndpoint l p UniswapUserSchema + => Proxy l + -> (a -> UserContractState) + -> (Uniswap -> p -> Contract (Last (Either Text UserContractState)) UniswapUserSchema Text a) + -> Contract (Last (Either Text UserContractState)) UniswapUserSchema Void () + f _ g c = do + e <- runError $ do + p <- endpoint @l + c us p + tell $ Last $ Just $ case e of + Left err -> Left err + Right a -> Right $ g a + + stop :: Contract (Last (Either Text UserContractState)) UniswapUserSchema Void () + stop = do + e <- runError $ endpoint @"stop" + tell $ Last $ Just $ case e of + Left err -> Left err + Right () -> Right Stopped From 737afbada1acb26b68e063188d778b5352fbe41a Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 28 Apr 2021 20:24:11 +0700 Subject: [PATCH 003/169] rename aave --- .../src/Plutus/Contracts/LendingPool.hs | 219 +++++++++--------- 1 file changed, 108 insertions(+), 111 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index 3bd131b51..fc4cf5cec 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -19,11 +19,11 @@ module Plutus.Contracts.LendingPool ( Coin (..) , coin, coinValueOf - , Uniswap (..), uniswap - , poolStateCoinFromUniswapCurrency, liquidityCoin + , Aave (..), aave + , poolStateCoinFromAaveCurrency, liquidityCoin , CreateParams (..) , CloseParams (..) - , UniswapUserSchema, UserContractState (..) + , AaveUserSchema, UserContractState (..) , start, create, close , ownerEndpoint, userEndpoints ) where @@ -55,8 +55,8 @@ feeNum, feeDen :: Integer feeNum = 3 feeDen = 1000 -uniswapTokenName, poolStateTokenName :: TokenName -uniswapTokenName = "Uniswap" +aaveTokenName, poolStateTokenName :: TokenName +aaveTokenName = "Aave" poolStateTokenName = "Pool State" -- | A pair consisting of a 'CurrencySymbol' and a 'TokenName'. @@ -174,50 +174,50 @@ hashLiquidityPool LiquidityPool{..} = sha2_256 $ concatenate (hashCoin c) (hashC | lpCoinA `coinLT` lpCoinB = (lpCoinA, lpCoinB) | otherwise = (lpCoinB, lpCoinA) -newtype Uniswap = Uniswap - { usCoin :: Coin +newtype Aave = Aave + { aaveCoin :: Coin } deriving stock (Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) -PlutusTx.makeLift ''Uniswap +PlutusTx.makeLift ''Aave -instance Prelude.Eq Uniswap where - u == v = usCoin u Prelude.== usCoin v +instance Prelude.Eq Aave where + u == v = aaveCoin u Prelude.== aaveCoin v -instance Prelude.Ord Uniswap where - compare u v = Prelude.compare (usCoin u) (usCoin v) +instance Prelude.Ord Aave where + compare u v = Prelude.compare (aaveCoin u) (aaveCoin v) -data UniswapAction = Create LiquidityPool | Close +data AaveAction = Create LiquidityPool | Close deriving Show -PlutusTx.unstableMakeIsData ''UniswapAction -PlutusTx.makeLift ''UniswapAction +PlutusTx.unstableMakeIsData ''AaveAction +PlutusTx.makeLift ''AaveAction -data UniswapDatum = +data AaveDatum = Factory [LiquidityPool] | Pool LiquidityPool Integer deriving stock (Show) -PlutusTx.unstableMakeIsData ''UniswapDatum -PlutusTx.makeLift ''UniswapDatum +PlutusTx.unstableMakeIsData ''AaveDatum +PlutusTx.makeLift ''AaveDatum -data Uniswapping -instance Scripts.ScriptType Uniswapping where - type instance RedeemerType Uniswapping = UniswapAction - type instance DatumType Uniswapping = UniswapDatum +data Aaveping +instance Scripts.ScriptType Aaveping where + type instance RedeemerType Aaveping = AaveAction + type instance DatumType Aaveping = AaveDatum {-# INLINABLE validateCreate #-} -validateCreate :: Uniswap +validateCreate :: Aave -> Coin -> [LiquidityPool] -> LiquidityPool -> ValidatorCtx -> Bool -validateCreate Uniswap{..} c lps lp@LiquidityPool{..} ctx = - traceIfFalse "Uniswap coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) usCoin == 1) && +validateCreate Aave{..} c lps lp@LiquidityPool{..} ctx = + traceIfFalse "Aave coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) aaveCoin == 1) && (lpCoinA /= lpCoinB) && all (/= lp) lps && - Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ coin usCoin 1) && + Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ coin aaveCoin 1) && (coinValueOf forged c == 1) && (coinValueOf forged liquidityCoin' == liquidity) && (outA > 0) && @@ -242,9 +242,9 @@ validateCreate Uniswap{..} c lps lp@LiquidityPool{..} ctx = liquidityCoin' = let Coin cs _ = c in Coin cs $ lpTicker lp {-# INLINABLE validateCloseFactory #-} -validateCloseFactory :: Uniswap -> Coin -> [LiquidityPool] -> ValidatorCtx -> Bool +validateCloseFactory :: Aave -> Coin -> [LiquidityPool] -> ValidatorCtx -> Bool validateCloseFactory us c lps ctx = - traceIfFalse "Uniswap coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) usC == 1) && + traceIfFalse "Aave coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) usC == 1) && traceIfFalse "wrong forge value" (txInfoForge info == negate (coin c 1 <> coin lC (snd lpLiquidity))) && traceIfFalse "factory output wrong" (Constraints.checkOwnOutputConstraint ctx $ OutputConstraint (Factory $ filter (/= fst lpLiquidity) lps) $ coin usC 1) @@ -267,10 +267,10 @@ validateCloseFactory us c lps ctx = lC, usC :: Coin lC = Coin (cCurrency c) (lpTicker $ fst lpLiquidity) - usC = usCoin us + usC = aaveCoin us {-# INLINABLE validateClosePool #-} -validateClosePool :: Uniswap -> ValidatorCtx -> Bool +validateClosePool :: Aave -> ValidatorCtx -> Bool validateClosePool us ctx = hasFactoryInput where info :: TxInfo @@ -278,8 +278,8 @@ validateClosePool us ctx = hasFactoryInput hasFactoryInput :: Bool hasFactoryInput = - traceIfFalse "Uniswap factory input expected" $ - coinValueOf (valueSpent info) (usCoin us) == 1 + traceIfFalse "Aave factory input expected" $ + coinValueOf (valueSpent info) (aaveCoin us) == 1 {-# INLINABLE findPoolDatum #-} @@ -303,18 +303,18 @@ lpTicker LiquidityPool{..} = TokenName $ | lpCoinA `coinLT` lpCoinB = (lpCoinA, lpCoinB) | otherwise = (lpCoinB, lpCoinA) -mkUniswapValidator :: Uniswap +mkAaveValidator :: Aave -> Coin - -> UniswapDatum - -> UniswapAction + -> AaveDatum + -> AaveAction -> ValidatorCtx -> Bool -mkUniswapValidator us c (Factory lps) (Create lp) ctx = validateCreate us c lps lp ctx -mkUniswapValidator us c (Factory lps) Close ctx = validateCloseFactory us c lps ctx -mkUniswapValidator us _ (Pool _ _) Close ctx = validateClosePool us ctx -mkUniswapValidator _ _ _ _ _ = False +mkAaveValidator us c (Factory lps) (Create lp) ctx = validateCreate us c lps lp ctx +mkAaveValidator us c (Factory lps) Close ctx = validateCloseFactory us c lps ctx +mkAaveValidator us _ (Pool _ _) Close ctx = validateClosePool us ctx +mkAaveValidator _ _ _ _ _ = False -validateLiquidityForging :: Uniswap -> TokenName -> PolicyCtx -> Bool +validateLiquidityForging :: Aave -> TokenName -> PolicyCtx -> Bool validateLiquidityForging us tn ctx = case [ i | i <- txInfoInputs $ policyCtxTxInfo ctx , let v = txInInfoValue i @@ -323,15 +323,15 @@ validateLiquidityForging us tn ctx = case [ i ] of [_] -> True [_, _] -> True - _ -> traceError "pool state forging without Uniswap input" + _ -> traceError "pool state forging without Aave input" where usC, lpC :: Coin - usC = usCoin us + usC = aaveCoin us lpC = Coin (ownCurrencySymbol ctx) tn -uniswapInstance :: Uniswap -> Scripts.ScriptInstance Uniswapping -uniswapInstance us = Scripts.validator @Uniswapping - ($$(PlutusTx.compile [|| mkUniswapValidator ||]) +aaveInstance :: Aave -> Scripts.ScriptInstance Aaveping +aaveInstance us = Scripts.validator @Aaveping + ($$(PlutusTx.compile [|| mkAaveValidator ||]) `PlutusTx.applyCode` PlutusTx.liftCode us `PlutusTx.applyCode` PlutusTx.liftCode c) $$(PlutusTx.compile [|| wrap ||]) @@ -339,43 +339,43 @@ uniswapInstance us = Scripts.validator @Uniswapping c :: Coin c = poolStateCoin us - wrap = Scripts.wrapValidator @UniswapDatum @UniswapAction + wrap = Scripts.wrapValidator @AaveDatum @AaveAction -uniswapScript :: Uniswap -> Validator -uniswapScript = Scripts.validatorScript . uniswapInstance +aaveScript :: Aave -> Validator +aaveScript = Scripts.validatorScript . aaveInstance -uniswapHash :: Uniswap -> Ledger.ValidatorHash -uniswapHash = Scripts.validatorHash . uniswapScript +aaveHash :: Aave -> Ledger.ValidatorHash +aaveHash = Scripts.validatorHash . aaveScript -uniswapAddress :: Uniswap -> Ledger.Address -uniswapAddress = ScriptAddress . uniswapHash +aaveAddress :: Aave -> Ledger.Address +aaveAddress = ScriptAddress . aaveHash -uniswap :: CurrencySymbol -> Uniswap -uniswap cs = Uniswap $ Coin cs uniswapTokenName +aave :: CurrencySymbol -> Aave +aave cs = Aave $ Coin cs aaveTokenName -liquidityPolicy :: Uniswap -> MonetaryPolicy +liquidityPolicy :: Aave -> MonetaryPolicy liquidityPolicy us = mkMonetaryPolicyScript $ $$(PlutusTx.compile [|| \u t -> Scripts.wrapMonetaryPolicy (validateLiquidityForging u t) ||]) `PlutusTx.applyCode` PlutusTx.liftCode us `PlutusTx.applyCode` PlutusTx.liftCode poolStateTokenName -liquidityCurrency :: Uniswap -> CurrencySymbol +liquidityCurrency :: Aave -> CurrencySymbol liquidityCurrency = scriptCurrencySymbol . liquidityPolicy -poolStateCoin :: Uniswap -> Coin +poolStateCoin :: Aave -> Coin poolStateCoin = flip Coin poolStateTokenName . liquidityCurrency -- | Gets the 'Coin' used to identity liquidity pools. -poolStateCoinFromUniswapCurrency :: CurrencySymbol -- ^ The currency identifying the Uniswap instance. +poolStateCoinFromAaveCurrency :: CurrencySymbol -- ^ The currency identifying the Aave instance. -> Coin -poolStateCoinFromUniswapCurrency = poolStateCoin . uniswap +poolStateCoinFromAaveCurrency = poolStateCoin . aave -- | Gets the liquidity token for a given liquidity pool. -liquidityCoin :: CurrencySymbol -- ^ The currency identifying the Uniswap instance. +liquidityCoin :: CurrencySymbol -- ^ The currency identifying the Aave instance. -> Coin -- ^ One coin in the liquidity pair. -> Coin -- ^ The other coin in the liquidity pair. -> Coin -liquidityCoin cs coinA coinB = Coin (liquidityCurrency $ uniswap cs) $ lpTicker $ LiquidityPool coinA coinB +liquidityCoin cs coinA coinB = Coin (liquidityCurrency $ aave cs) $ lpTicker $ LiquidityPool coinA coinB -- | Paraneters for the @create@-endpoint, which creates a new liquidity pool. data CreateParams = CreateParams @@ -391,39 +391,39 @@ data CloseParams = CloseParams , clpCoinB :: Coin -- ^ The other 'Coin' of the liquidity pair. } deriving (Show, Generic, ToJSON, FromJSON, ToSchema) --- | Creates a Uniswap "factory". This factory will keep track of the existing liquidity pools and enforce that there will be at most one liquidity pool +-- | Creates a Aave "factory". This factory will keep track of the existing liquidity pools and enforce that there will be at most one liquidity pool -- for any pair of tokens at any given time. -start :: HasBlockchainActions s => Contract w s Text Uniswap +start :: HasBlockchainActions s => Contract w s Text Aave start = do pkh <- pubKeyHash <$> ownPubKey cs <- fmap Currency.currencySymbol $ mapError (pack . show @Currency.CurrencyError) $ - Currency.forgeContract pkh [(uniswapTokenName, 1)] - let c = Coin cs uniswapTokenName - us = uniswap cs - inst = uniswapInstance us + Currency.forgeContract pkh [(aaveTokenName, 1)] + let c = Coin cs aaveTokenName + aa = aave cs + inst = aaveInstance aa tx = mustPayToTheScript (Factory []) $ coin c 1 ledgerTx <- submitTxConstraints inst tx void $ awaitTxConfirmed $ txId ledgerTx - logInfo @String $ printf "started Uniswap %s at address %s" (show us) (show $ uniswapAddress us) - return us + logInfo @String $ printf "started Aave %s at address %s" (show aa) (show $ aaveAddress aa) + return aa -- | Creates a liquidity pool for a pair of coins. The creator provides liquidity for both coins and gets liquidity tokens in return. -create :: HasBlockchainActions s => Uniswap -> CreateParams -> Contract w s Text () +create :: HasBlockchainActions s => Aave -> CreateParams -> Contract w s Text () create us CreateParams{..} = do when (cpCoinA == cpCoinB) $ throwError "coins must be different" when (cpAmountA <= 0 || cpAmountB <= 0) $ throwError "amounts must be positive" - (oref, o, lps) <- findUniswapFactory us + (oref, o, lps) <- findAaveFactory us let liquidity = calculateInitialLiquidity cpAmountA cpAmountB lp = LiquidityPool {lpCoinA = cpCoinA, lpCoinB = cpCoinB} - let usInst = uniswapInstance us - usScript = uniswapScript us + let usInst = aaveInstance us + usScript = aaveScript us usDat1 = Factory $ lp : lps usDat2 = Pool lp liquidity psC = poolStateCoin us lC = Coin (liquidityCurrency us) $ lpTicker lp - usVal = coin (usCoin us) 1 + usVal = coin (aaveCoin us) 1 lpVal = coin cpCoinA cpAmountA <> coin cpCoinB cpAmountB <> coin psC 1 lookups = Constraints.scriptInstanceLookups usInst <> @@ -442,14 +442,14 @@ create us CreateParams{..} = do logInfo $ "created liquidity pool: " ++ show lp -- | Closes a liquidity pool by burning all remaining liquidity tokens in exchange for all liquidity remaining in the pool. -close :: HasBlockchainActions s => Uniswap -> CloseParams -> Contract w s Text () +close :: HasBlockchainActions s => Aave -> CloseParams -> Contract w s Text () close us CloseParams{..} = do - ((oref1, o1, lps), (oref2, o2, lp, liquidity)) <- findUniswapFactoryAndPool us clpCoinA clpCoinB + ((oref1, o1, lps), (oref2, o2, lp, liquidity)) <- findAaveFactoryAndPool us clpCoinA clpCoinB pkh <- pubKeyHash <$> ownPubKey - let usInst = uniswapInstance us - usScript = uniswapScript us + let usInst = aaveInstance us + usScript = aaveScript us usDat = Factory $ filter (/= lp) lps - usC = usCoin us + usC = aaveCoin us psC = poolStateCoin us lC = Coin (liquidityCurrency us) $ lpTicker lp usVal = coin usC 1 @@ -474,8 +474,8 @@ close us CloseParams{..} = do logInfo $ "closed liquidity pool: " ++ show lp -getUniswapDatum :: TxOutTx -> Contract w s Text UniswapDatum -getUniswapDatum o = case txOutType $ txOutTxOut o of +getAaveDatum :: TxOutTx -> Contract w s Text AaveDatum +getAaveDatum o = case txOutType $ txOutTxOut o of PayToPubKey -> throwError "unexpected out type" PayToScript h -> case Map.lookup h $ txData $ txOutTxTx o of Nothing -> throwError "datum not found" @@ -483,82 +483,79 @@ getUniswapDatum o = case txOutType $ txOutTxOut o of Nothing -> throwError "datum has wrong type" Just d -> return d -findUniswapInstance :: HasBlockchainActions s => Uniswap -> Coin -> (UniswapDatum -> Maybe a) -> Contract w s Text (TxOutRef, TxOutTx, a) -findUniswapInstance us c f = do - let addr = uniswapAddress us - logInfo @String $ printf "looking for Uniswap instance at address %s containing coin %s " (show addr) (show c) +findAaveInstance :: HasBlockchainActions s => Aave -> Coin -> (AaveDatum -> Maybe a) -> Contract w s Text (TxOutRef, TxOutTx, a) +findAaveInstance us c f = do + let addr = aaveAddress us + logInfo @String $ printf "looking for Aave instance at address %s containing coin %s " (show addr) (show c) utxos <- utxoAt addr go [x | x@(_, o) <- Map.toList utxos, coinValueOf (txOutValue $ txOutTxOut o) c == 1] where - go [] = throwError "Uniswap instance not found" + go [] = throwError "Aave instance not found" go ((oref, o) : xs) = do - d <- getUniswapDatum o + d <- getAaveDatum o case f d of Nothing -> go xs Just a -> do - logInfo @String $ printf "found Uniswap instance with datum: %s" (show d) + logInfo @String $ printf "found Aave instance with datum: %s" (show d) return (oref, o, a) -findUniswapFactory :: HasBlockchainActions s => Uniswap -> Contract w s Text (TxOutRef, TxOutTx, [LiquidityPool]) -findUniswapFactory us@Uniswap{..} = findUniswapInstance us usCoin $ \case +findAaveFactory :: HasBlockchainActions s => Aave -> Contract w s Text (TxOutRef, TxOutTx, [LiquidityPool]) +findAaveFactory us@Aave{..} = findAaveInstance us aaveCoin $ \case Factory lps -> Just lps Pool _ _ -> Nothing -findUniswapPool :: HasBlockchainActions s => Uniswap -> LiquidityPool -> Contract w s Text (TxOutRef, TxOutTx, Integer) -findUniswapPool us lp = findUniswapInstance us (poolStateCoin us) $ \case +findAavePool :: HasBlockchainActions s => Aave -> LiquidityPool -> Contract w s Text (TxOutRef, TxOutTx, Integer) +findAavePool us lp = findAaveInstance us (poolStateCoin us) $ \case Pool lp' l | lp == lp' -> Just l _ -> Nothing -findUniswapFactoryAndPool :: HasBlockchainActions s - => Uniswap +findAaveFactoryAndPool :: HasBlockchainActions s + => Aave -> Coin -> Coin -> Contract w s Text ( (TxOutRef, TxOutTx, [LiquidityPool]) , (TxOutRef, TxOutTx, LiquidityPool, Integer) ) -findUniswapFactoryAndPool us coinA coinB = do - (oref1, o1, lps) <- findUniswapFactory us +findAaveFactoryAndPool us coinA coinB = do + (oref1, o1, lps) <- findAaveFactory us case [ lp' | lp' <- lps , lp' == LiquidityPool coinA coinB ] of [lp] -> do - (oref2, o2, a) <- findUniswapPool us lp + (oref2, o2, a) <- findAavePool us lp return ( (oref1, o1, lps) , (oref2, o2, lp, a) ) _ -> throwError "liquidity pool not found" -ownerEndpoint :: Contract (Last (Either Text Uniswap)) BlockchainActions Void () +ownerEndpoint :: Contract (Last (Either Text Aave)) BlockchainActions Void () ownerEndpoint = do e <- runError start tell $ Last $ Just $ case e of Left err -> Left err Right us -> Right us --- | Schema for the endpoints for users of Uniswap. -type UniswapUserSchema = +-- | Schema for the endpoints for users of Aave. +type AaveUserSchema = BlockchainActions .\/ Endpoint "create" CreateParams .\/ Endpoint "close" CloseParams .\/ Endpoint "stop" () --- | Type of the Uniswap user contract state. -data UserContractState = - Pools [((Coin, Integer), (Coin, Integer))] - | Funds Value - | Created +-- | Type of the Aave user contract state. +data UserContractState = Created | Closed | Stopped deriving (Show, Generic, FromJSON, ToJSON) --- | Provides the following endpoints for users of a Uniswap instance: +-- | Provides the following endpoints for users of a Aave instance: -- -- [@create@]: Creates a liquidity pool for a pair of coins. The creator provides liquidity for both coins and gets liquidity tokens in return. -- [@close@]: Closes a liquidity pool by burning all remaining liquidity tokens in exchange for all liquidity remaining in the pool. -- [@stop@]: Stops the contract. -userEndpoints :: Uniswap -> Contract (Last (Either Text UserContractState)) UniswapUserSchema Void () +userEndpoints :: Aave -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () userEndpoints us = stop `select` @@ -567,11 +564,11 @@ userEndpoints us = >> userEndpoints us) where f :: forall l a p. - HasEndpoint l p UniswapUserSchema + HasEndpoint l p AaveUserSchema => Proxy l -> (a -> UserContractState) - -> (Uniswap -> p -> Contract (Last (Either Text UserContractState)) UniswapUserSchema Text a) - -> Contract (Last (Either Text UserContractState)) UniswapUserSchema Void () + -> (Aave -> p -> Contract (Last (Either Text UserContractState)) AaveUserSchema Text a) + -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () f _ g c = do e <- runError $ do p <- endpoint @l @@ -580,7 +577,7 @@ userEndpoints us = Left err -> Left err Right a -> Right $ g a - stop :: Contract (Last (Either Text UserContractState)) UniswapUserSchema Void () + stop :: Contract (Last (Either Text UserContractState)) AaveUserSchema Void () stop = do e <- runError $ endpoint @"stop" tell $ Last $ Just $ case e of From 5e763b4c9e3e2e40232dcf0e8e13cee5e79b17f2 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 29 Apr 2021 14:55:19 +0700 Subject: [PATCH 004/169] rename script --- .../src/Plutus/Contracts/LendingPool.hs | 102 +++++++++--------- 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index fc4cf5cec..f9af732a2 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -51,10 +51,6 @@ import Prelude (Semigroup (..)) import qualified Prelude import Text.Printf (printf) -feeNum, feeDen :: Integer -feeNum = 3 -feeDen = 1000 - aaveTokenName, poolStateTokenName :: TokenName aaveTokenName = "Aave" poolStateTokenName = "Pool State" @@ -201,10 +197,10 @@ data AaveDatum = PlutusTx.unstableMakeIsData ''AaveDatum PlutusTx.makeLift ''AaveDatum -data Aaveping -instance Scripts.ScriptType Aaveping where - type instance RedeemerType Aaveping = AaveAction - type instance DatumType Aaveping = AaveDatum +data AaveScript +instance Scripts.ScriptType AaveScript where + type instance RedeemerType AaveScript = AaveAction + type instance DatumType AaveScript = AaveDatum {-# INLINABLE validateCreate #-} validateCreate :: Aave @@ -243,7 +239,7 @@ validateCreate Aave{..} c lps lp@LiquidityPool{..} ctx = {-# INLINABLE validateCloseFactory #-} validateCloseFactory :: Aave -> Coin -> [LiquidityPool] -> ValidatorCtx -> Bool -validateCloseFactory us c lps ctx = +validateCloseFactory aa c lps ctx = traceIfFalse "Aave coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) usC == 1) && traceIfFalse "wrong forge value" (txInfoForge info == negate (coin c 1 <> coin lC (snd lpLiquidity))) && traceIfFalse "factory output wrong" @@ -267,11 +263,11 @@ validateCloseFactory us c lps ctx = lC, usC :: Coin lC = Coin (cCurrency c) (lpTicker $ fst lpLiquidity) - usC = aaveCoin us + usC = aaveCoin aa {-# INLINABLE validateClosePool #-} validateClosePool :: Aave -> ValidatorCtx -> Bool -validateClosePool us ctx = hasFactoryInput +validateClosePool aa ctx = hasFactoryInput where info :: TxInfo info = valCtxTxInfo ctx @@ -279,7 +275,7 @@ validateClosePool us ctx = hasFactoryInput hasFactoryInput :: Bool hasFactoryInput = traceIfFalse "Aave factory input expected" $ - coinValueOf (valueSpent info) (aaveCoin us) == 1 + coinValueOf (valueSpent info) (aaveCoin aa) == 1 {-# INLINABLE findPoolDatum #-} @@ -309,35 +305,35 @@ mkAaveValidator :: Aave -> AaveAction -> ValidatorCtx -> Bool -mkAaveValidator us c (Factory lps) (Create lp) ctx = validateCreate us c lps lp ctx -mkAaveValidator us c (Factory lps) Close ctx = validateCloseFactory us c lps ctx -mkAaveValidator us _ (Pool _ _) Close ctx = validateClosePool us ctx +mkAaveValidator aa c (Factory lps) (Create lp) ctx = validateCreate aa c lps lp ctx +mkAaveValidator aa c (Factory lps) Close ctx = validateCloseFactory aa c lps ctx +mkAaveValidator aa _ (Pool _ _) Close ctx = validateClosePool aa ctx mkAaveValidator _ _ _ _ _ = False validateLiquidityForging :: Aave -> TokenName -> PolicyCtx -> Bool -validateLiquidityForging us tn ctx = case [ i +validateLiquidityForging aa tn ctx = case [ i | i <- txInfoInputs $ policyCtxTxInfo ctx , let v = txInInfoValue i - , (coinValueOf v usC == 1) || + , (coinValueOf v aaC == 1) || (coinValueOf v lpC == 1) ] of [_] -> True [_, _] -> True _ -> traceError "pool state forging without Aave input" where - usC, lpC :: Coin - usC = aaveCoin us + aaC, lpC :: Coin + aaC = aaveCoin aa lpC = Coin (ownCurrencySymbol ctx) tn -aaveInstance :: Aave -> Scripts.ScriptInstance Aaveping -aaveInstance us = Scripts.validator @Aaveping +aaveInstance :: Aave -> Scripts.ScriptInstance AaveScript +aaveInstance aa = Scripts.validator @AaveScript ($$(PlutusTx.compile [|| mkAaveValidator ||]) - `PlutusTx.applyCode` PlutusTx.liftCode us + `PlutusTx.applyCode` PlutusTx.liftCode aa `PlutusTx.applyCode` PlutusTx.liftCode c) $$(PlutusTx.compile [|| wrap ||]) where c :: Coin - c = poolStateCoin us + c = poolStateCoin aa wrap = Scripts.wrapValidator @AaveDatum @AaveAction @@ -354,9 +350,9 @@ aave :: CurrencySymbol -> Aave aave cs = Aave $ Coin cs aaveTokenName liquidityPolicy :: Aave -> MonetaryPolicy -liquidityPolicy us = mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| \u t -> Scripts.wrapMonetaryPolicy (validateLiquidityForging u t) ||]) - `PlutusTx.applyCode` PlutusTx.liftCode us +liquidityPolicy aa = mkMonetaryPolicyScript $ + $$(PlutusTx.compile [|| \a t -> Scripts.wrapMonetaryPolicy (validateLiquidityForging a t) ||]) + `PlutusTx.applyCode` PlutusTx.liftCode aa `PlutusTx.applyCode` PlutusTx.liftCode poolStateTokenName liquidityCurrency :: Aave -> CurrencySymbol @@ -411,24 +407,24 @@ start = do -- | Creates a liquidity pool for a pair of coins. The creator provides liquidity for both coins and gets liquidity tokens in return. create :: HasBlockchainActions s => Aave -> CreateParams -> Contract w s Text () -create us CreateParams{..} = do +create aa CreateParams{..} = do when (cpCoinA == cpCoinB) $ throwError "coins must be different" when (cpAmountA <= 0 || cpAmountB <= 0) $ throwError "amounts must be positive" - (oref, o, lps) <- findAaveFactory us + (oref, o, lps) <- findAaveFactory aa let liquidity = calculateInitialLiquidity cpAmountA cpAmountB lp = LiquidityPool {lpCoinA = cpCoinA, lpCoinB = cpCoinB} - let usInst = aaveInstance us - usScript = aaveScript us + let usInst = aaveInstance aa + usScript = aaveScript aa usDat1 = Factory $ lp : lps usDat2 = Pool lp liquidity - psC = poolStateCoin us - lC = Coin (liquidityCurrency us) $ lpTicker lp - usVal = coin (aaveCoin us) 1 + psC = poolStateCoin aa + lC = Coin (liquidityCurrency aa) $ lpTicker lp + usVal = coin (aaveCoin aa) 1 lpVal = coin cpCoinA cpAmountA <> coin cpCoinB cpAmountB <> coin psC 1 lookups = Constraints.scriptInstanceLookups usInst <> Constraints.otherScript usScript <> - Constraints.monetaryPolicy (liquidityPolicy us) <> + Constraints.monetaryPolicy (liquidityPolicy aa) <> Constraints.unspentOutputs (Map.singleton oref o) tx = Constraints.mustPayToTheScript usDat1 usVal <> @@ -443,15 +439,15 @@ create us CreateParams{..} = do -- | Closes a liquidity pool by burning all remaining liquidity tokens in exchange for all liquidity remaining in the pool. close :: HasBlockchainActions s => Aave -> CloseParams -> Contract w s Text () -close us CloseParams{..} = do - ((oref1, o1, lps), (oref2, o2, lp, liquidity)) <- findAaveFactoryAndPool us clpCoinA clpCoinB +close aa CloseParams{..} = do + ((oref1, o1, lps), (oref2, o2, lp, liquidity)) <- findAaveFactoryAndPool aa clpCoinA clpCoinB pkh <- pubKeyHash <$> ownPubKey - let usInst = aaveInstance us - usScript = aaveScript us + let usInst = aaveInstance aa + usScript = aaveScript aa usDat = Factory $ filter (/= lp) lps - usC = aaveCoin us - psC = poolStateCoin us - lC = Coin (liquidityCurrency us) $ lpTicker lp + usC = aaveCoin aa + psC = poolStateCoin aa + lC = Coin (liquidityCurrency aa) $ lpTicker lp usVal = coin usC 1 psVal = coin psC 1 lVal = coin lC liquidity @@ -459,7 +455,7 @@ close us CloseParams{..} = do lookups = Constraints.scriptInstanceLookups usInst <> Constraints.otherScript usScript <> - Constraints.monetaryPolicy (liquidityPolicy us) <> + Constraints.monetaryPolicy (liquidityPolicy aa) <> Constraints.ownPubKeyHash pkh <> Constraints.unspentOutputs (Map.singleton oref1 o1 <> Map.singleton oref2 o2) @@ -484,8 +480,8 @@ getAaveDatum o = case txOutType $ txOutTxOut o of Just d -> return d findAaveInstance :: HasBlockchainActions s => Aave -> Coin -> (AaveDatum -> Maybe a) -> Contract w s Text (TxOutRef, TxOutTx, a) -findAaveInstance us c f = do - let addr = aaveAddress us +findAaveInstance aa c f = do + let addr = aaveAddress aa logInfo @String $ printf "looking for Aave instance at address %s containing coin %s " (show addr) (show c) utxos <- utxoAt addr go [x | x@(_, o) <- Map.toList utxos, coinValueOf (txOutValue $ txOutTxOut o) c == 1] @@ -500,12 +496,12 @@ findAaveInstance us c f = do return (oref, o, a) findAaveFactory :: HasBlockchainActions s => Aave -> Contract w s Text (TxOutRef, TxOutTx, [LiquidityPool]) -findAaveFactory us@Aave{..} = findAaveInstance us aaveCoin $ \case +findAaveFactory aa@Aave{..} = findAaveInstance aa aaveCoin $ \case Factory lps -> Just lps Pool _ _ -> Nothing findAavePool :: HasBlockchainActions s => Aave -> LiquidityPool -> Contract w s Text (TxOutRef, TxOutTx, Integer) -findAavePool us lp = findAaveInstance us (poolStateCoin us) $ \case +findAavePool aa lp = findAaveInstance aa (poolStateCoin aa) $ \case Pool lp' l | lp == lp' -> Just l _ -> Nothing @@ -517,14 +513,14 @@ findAaveFactoryAndPool :: HasBlockchainActions s -> Contract w s Text ( (TxOutRef, TxOutTx, [LiquidityPool]) , (TxOutRef, TxOutTx, LiquidityPool, Integer) ) -findAaveFactoryAndPool us coinA coinB = do - (oref1, o1, lps) <- findAaveFactory us +findAaveFactoryAndPool aa coinA coinB = do + (oref1, o1, lps) <- findAaveFactory aa case [ lp' | lp' <- lps , lp' == LiquidityPool coinA coinB ] of [lp] -> do - (oref2, o2, a) <- findAavePool us lp + (oref2, o2, a) <- findAavePool aa lp return ( (oref1, o1, lps) , (oref2, o2, lp, a) ) @@ -535,7 +531,7 @@ ownerEndpoint = do e <- runError start tell $ Last $ Just $ case e of Left err -> Left err - Right us -> Right us + Right aa -> Right aa -- | Schema for the endpoints for users of Aave. type AaveUserSchema = @@ -556,12 +552,12 @@ data UserContractState = Created -- [@close@]: Closes a liquidity pool by burning all remaining liquidity tokens in exchange for all liquidity remaining in the pool. -- [@stop@]: Stops the contract. userEndpoints :: Aave -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () -userEndpoints us = +userEndpoints aa = stop `select` ((f (Proxy @"create") (const Created) create `select` f (Proxy @"close") (const Closed) close ) - >> userEndpoints us) + >> userEndpoints aa) where f :: forall l a p. HasEndpoint l p AaveUserSchema @@ -572,7 +568,7 @@ userEndpoints us = f _ g c = do e <- runError $ do p <- endpoint @l - c us p + c aa p tell $ Last $ Just $ case e of Left err -> Left err Right a -> Right $ g a From 54b6caeaf2ee2be6ad7bbffb642239cc9593d18b Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 30 Apr 2021 15:52:20 +0700 Subject: [PATCH 005/169] change lending pool link --- .../src/Plutus/Contracts/LendingPool.hs | 162 ++++++------------ 1 file changed, 55 insertions(+), 107 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index f9af732a2..fe657c5af 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -20,9 +20,7 @@ module Plutus.Contracts.LendingPool ( Coin (..) , coin, coinValueOf , Aave (..), aave - , poolStateCoinFromAaveCurrency, liquidityCoin - , CreateParams (..) - , CloseParams (..) + , poolStateCoinFromAaveCurrency , AaveUserSchema, UserContractState (..) , start, create, close , ownerEndpoint, userEndpoints @@ -149,26 +147,23 @@ calculateInitialLiquidity outA outB = case isqrt (outA * outB) of | l > 0 -> l + 1 _ -> traceError "insufficient liquidity" -data LiquidityPool = LiquidityPool - { lpCoinA :: Coin - , lpCoinB :: Coin - } deriving (Show, Generic, ToJSON, FromJSON, ToSchema) +data LendingPool = LendingPool + { lpCoin :: Coin, + lpIssuer :: PubKeyHash + } + deriving stock (Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) -PlutusTx.unstableMakeIsData ''LiquidityPool -PlutusTx.makeLift ''LiquidityPool +PlutusTx.unstableMakeIsData ''LendingPool +PlutusTx.makeLift ''LendingPool -instance Eq LiquidityPool where +instance Eq LendingPool where {-# INLINABLE (==) #-} - x == y = (lpCoinA x == lpCoinA y && lpCoinB x == lpCoinB y) || - (lpCoinA x == lpCoinB y && lpCoinB x == lpCoinA y) + x == y = lpCoin x == lpCoin y && lpIssuer x == lpIssuer y -{-# INLINABLE hashLiquidityPool #-} -hashLiquidityPool :: LiquidityPool -> ByteString -hashLiquidityPool LiquidityPool{..} = sha2_256 $ concatenate (hashCoin c) (hashCoin d) - where - (c, d) - | lpCoinA `coinLT` lpCoinB = (lpCoinA, lpCoinB) - | otherwise = (lpCoinB, lpCoinA) +{-# INLINABLE hashLendingPool #-} +hashLendingPool :: LendingPool -> ByteString +hashLendingPool LendingPool{..} = sha2_256 $ hashCoin lpCoin <> getPubKeyHash lpIssuer newtype Aave = Aave { aaveCoin :: Coin @@ -183,15 +178,15 @@ instance Prelude.Eq Aave where instance Prelude.Ord Aave where compare u v = Prelude.compare (aaveCoin u) (aaveCoin v) -data AaveAction = Create LiquidityPool | Close +data AaveAction = Create LendingPool | Close deriving Show PlutusTx.unstableMakeIsData ''AaveAction PlutusTx.makeLift ''AaveAction data AaveDatum = - Factory [LiquidityPool] - | Pool LiquidityPool Integer + Factory [LendingPool] + | Pool LendingPool Integer -- Pool consisting of lending pool link and aTokens amount deriving stock (Show) PlutusTx.unstableMakeIsData ''AaveDatum @@ -205,43 +200,31 @@ instance Scripts.ScriptType AaveScript where {-# INLINABLE validateCreate #-} validateCreate :: Aave -> Coin - -> [LiquidityPool] - -> LiquidityPool + -> [LendingPool] + -> LendingPool -> ValidatorCtx -> Bool -validateCreate Aave{..} c lps lp@LiquidityPool{..} ctx = +validateCreate Aave{..} c lps lp@LendingPool{..} ctx = traceIfFalse "Aave coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) aaveCoin == 1) && - (lpCoinA /= lpCoinB) && - all (/= lp) lps && + notElem lp lps && Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ coin aaveCoin 1) && - (coinValueOf forged c == 1) && - (coinValueOf forged liquidityCoin' == liquidity) && - (outA > 0) && - (outB > 0) && - Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp liquidity) $ - coin lpCoinA outA <> coin lpCoinB outB <> coin c 1) + (coinValueOf forged c == 1) + -- TODO validate aTokens forged + -- Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp liquidity) $ coin c 1) where poolOutput :: TxOutInfo poolOutput = case [o | o <- getContinuingOutputs ctx, coinValueOf (txOutValue o) c == 1] of [o] -> o _ -> traceError "expected exactly one pool output" - outA, outB, liquidity :: Integer - outA = coinValueOf (txOutValue poolOutput) lpCoinA - outB = coinValueOf (txOutValue poolOutput) lpCoinB - liquidity = calculateInitialLiquidity outA outB - forged :: Value forged = txInfoForge $ valCtxTxInfo ctx - liquidityCoin' :: Coin - liquidityCoin' = let Coin cs _ = c in Coin cs $ lpTicker lp - {-# INLINABLE validateCloseFactory #-} -validateCloseFactory :: Aave -> Coin -> [LiquidityPool] -> ValidatorCtx -> Bool +validateCloseFactory :: Aave -> Coin -> [LendingPool] -> ValidatorCtx -> Bool validateCloseFactory aa c lps ctx = traceIfFalse "Aave coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) usC == 1) && - traceIfFalse "wrong forge value" (txInfoForge info == negate (coin c 1 <> coin lC (snd lpLiquidity))) && + traceIfFalse "wrong forge value" (txInfoForge info == negate (coin c 1)) && traceIfFalse "factory output wrong" (Constraints.checkOwnOutputConstraint ctx $ OutputConstraint (Factory $ filter (/= fst lpLiquidity) lps) $ coin usC 1) where @@ -256,13 +239,12 @@ validateCloseFactory aa c lps ctx = [i] -> i _ -> traceError "expected exactly one pool input" - lpLiquidity :: (LiquidityPool, Integer) + lpLiquidity :: (LendingPool, Integer) lpLiquidity = case txInInfoWitness poolInput of Nothing -> traceError "pool input witness missing" Just (_, _, h) -> findPoolDatum info h - lC, usC :: Coin - lC = Coin (cCurrency c) (lpTicker $ fst lpLiquidity) + usC :: Coin usC = aaveCoin aa {-# INLINABLE validateClosePool #-} @@ -279,26 +261,13 @@ validateClosePool aa ctx = hasFactoryInput {-# INLINABLE findPoolDatum #-} -findPoolDatum :: TxInfo -> DatumHash -> (LiquidityPool, Integer) +findPoolDatum :: TxInfo -> DatumHash -> (LendingPool, Integer) findPoolDatum info h = case findDatum h info of Just (Datum d) -> case PlutusTx.fromData d of Just (Pool lp a) -> (lp, a) _ -> traceError "error decoding data" _ -> traceError "pool input datum not found" -{-# INLINABLE lpTicker #-} -lpTicker :: LiquidityPool -> TokenName ---lpTicker = TokenName . hashLiquidityPool -lpTicker LiquidityPool{..} = TokenName $ - unCurrencySymbol (cCurrency c) `concatenate` - unCurrencySymbol (cCurrency d) `concatenate` - unTokenName (cToken c) `concatenate` - unTokenName (cToken d) - where - (c, d) - | lpCoinA `coinLT` lpCoinB = (lpCoinA, lpCoinB) - | otherwise = (lpCoinB, lpCoinA) - mkAaveValidator :: Aave -> Coin -> AaveDatum @@ -366,27 +335,6 @@ poolStateCoinFromAaveCurrency :: CurrencySymbol -- ^ The currency identifying th -> Coin poolStateCoinFromAaveCurrency = poolStateCoin . aave --- | Gets the liquidity token for a given liquidity pool. -liquidityCoin :: CurrencySymbol -- ^ The currency identifying the Aave instance. - -> Coin -- ^ One coin in the liquidity pair. - -> Coin -- ^ The other coin in the liquidity pair. - -> Coin -liquidityCoin cs coinA coinB = Coin (liquidityCurrency $ aave cs) $ lpTicker $ LiquidityPool coinA coinB - --- | Paraneters for the @create@-endpoint, which creates a new liquidity pool. -data CreateParams = CreateParams - { cpCoinA :: Coin -- ^ One 'Coin' of the liquidity pair. - , cpCoinB :: Coin -- ^ The other 'Coin'. - , cpAmountA :: Integer -- ^ Amount of liquidity for the first 'Coin'. - , cpAmountB :: Integer -- ^ Amount of liquidity for the second 'Coin'. - } deriving (Show, Generic, ToJSON, FromJSON, ToSchema) - --- | Parameters for the @close@-endpoint, which closes a liquidity pool. -data CloseParams = CloseParams - { clpCoinA :: Coin -- ^ One 'Coin' of the liquidity pair. - , clpCoinB :: Coin -- ^ The other 'Coin' of the liquidity pair. - } deriving (Show, Generic, ToJSON, FromJSON, ToSchema) - -- | Creates a Aave "factory". This factory will keep track of the existing liquidity pools and enforce that there will be at most one liquidity pool -- for any pair of tokens at any given time. start :: HasBlockchainActions s => Contract w s Text Aave @@ -406,21 +354,23 @@ start = do return aa -- | Creates a liquidity pool for a pair of coins. The creator provides liquidity for both coins and gets liquidity tokens in return. -create :: HasBlockchainActions s => Aave -> CreateParams -> Contract w s Text () -create aa CreateParams{..} = do - when (cpCoinA == cpCoinB) $ throwError "coins must be different" - when (cpAmountA <= 0 || cpAmountB <= 0) $ throwError "amounts must be positive" +create :: HasBlockchainActions s => Aave -> Integer -> Contract w s Text () +create aa aTokensNum = do + pkh <- pubKeyHash <$> ownPubKey + cs <- fmap Currency.currencySymbol $ + mapError (pack . show @Currency.CurrencyError) $ + Currency.forgeContract pkh [(poolStateTokenName, 1)] (oref, o, lps) <- findAaveFactory aa - let liquidity = calculateInitialLiquidity cpAmountA cpAmountB - lp = LiquidityPool {lpCoinA = cpCoinA, lpCoinB = cpCoinB} + let c = Coin cs poolStateTokenName + let lp = LendingPool c pkh let usInst = aaveInstance aa usScript = aaveScript aa usDat1 = Factory $ lp : lps - usDat2 = Pool lp liquidity + usDat2 = Pool lp aTokensNum psC = poolStateCoin aa - lC = Coin (liquidityCurrency aa) $ lpTicker lp usVal = coin (aaveCoin aa) 1 - lpVal = coin cpCoinA cpAmountA <> coin cpCoinB cpAmountB <> coin psC 1 + -- TODO: forge aTokens + lpVal = coin psC 1 lookups = Constraints.scriptInstanceLookups usInst <> Constraints.otherScript usScript <> @@ -429,7 +379,7 @@ create aa CreateParams{..} = do tx = Constraints.mustPayToTheScript usDat1 usVal <> Constraints.mustPayToTheScript usDat2 lpVal <> - Constraints.mustForgeValue (coin psC 1 <> coin lC liquidity) <> + Constraints.mustForgeValue (coin psC 1) <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ Create lp) ledgerTx <- submitTxConstraintsWith lookups tx @@ -438,19 +388,18 @@ create aa CreateParams{..} = do logInfo $ "created liquidity pool: " ++ show lp -- | Closes a liquidity pool by burning all remaining liquidity tokens in exchange for all liquidity remaining in the pool. -close :: HasBlockchainActions s => Aave -> CloseParams -> Contract w s Text () -close aa CloseParams{..} = do - ((oref1, o1, lps), (oref2, o2, lp, liquidity)) <- findAaveFactoryAndPool aa clpCoinA clpCoinB +close :: HasBlockchainActions s => Aave -> Coin -> Contract w s Text () +close aa poolCoin = do + pkh <- pubKeyHash <$> ownPubKey + ((oref1, o1, lps), (oref2, o2, lp, liquidity)) <- findAaveFactoryAndPool aa $ LendingPool poolCoin pkh pkh <- pubKeyHash <$> ownPubKey let usInst = aaveInstance aa usScript = aaveScript aa usDat = Factory $ filter (/= lp) lps usC = aaveCoin aa psC = poolStateCoin aa - lC = Coin (liquidityCurrency aa) $ lpTicker lp usVal = coin usC 1 psVal = coin psC 1 - lVal = coin lC liquidity redeemer = Redeemer $ PlutusTx.toData Close lookups = Constraints.scriptInstanceLookups usInst <> @@ -460,7 +409,7 @@ close aa CloseParams{..} = do Constraints.unspentOutputs (Map.singleton oref1 o1 <> Map.singleton oref2 o2) tx = Constraints.mustPayToTheScript usDat usVal <> - Constraints.mustForgeValue (negate $ psVal <> lVal) <> + Constraints.mustForgeValue (negate psVal) <> Constraints.mustSpendScriptOutput oref1 redeemer <> Constraints.mustSpendScriptOutput oref2 redeemer <> Constraints.mustIncludeDatum (Datum $ PlutusTx.toData $ Pool lp liquidity) @@ -495,12 +444,12 @@ findAaveInstance aa c f = do logInfo @String $ printf "found Aave instance with datum: %s" (show d) return (oref, o, a) -findAaveFactory :: HasBlockchainActions s => Aave -> Contract w s Text (TxOutRef, TxOutTx, [LiquidityPool]) +findAaveFactory :: HasBlockchainActions s => Aave -> Contract w s Text (TxOutRef, TxOutTx, [LendingPool]) findAaveFactory aa@Aave{..} = findAaveInstance aa aaveCoin $ \case Factory lps -> Just lps Pool _ _ -> Nothing -findAavePool :: HasBlockchainActions s => Aave -> LiquidityPool -> Contract w s Text (TxOutRef, TxOutTx, Integer) +findAavePool :: HasBlockchainActions s => Aave -> LendingPool -> Contract w s Text (TxOutRef, TxOutTx, Integer) findAavePool aa lp = findAaveInstance aa (poolStateCoin aa) $ \case Pool lp' l | lp == lp' -> Just l @@ -508,16 +457,15 @@ findAavePool aa lp = findAaveInstance aa (poolStateCoin aa) $ \case findAaveFactoryAndPool :: HasBlockchainActions s => Aave - -> Coin - -> Coin - -> Contract w s Text ( (TxOutRef, TxOutTx, [LiquidityPool]) - , (TxOutRef, TxOutTx, LiquidityPool, Integer) + -> LendingPool + -> Contract w s Text ( (TxOutRef, TxOutTx, [LendingPool]) + , (TxOutRef, TxOutTx, LendingPool, Integer) ) -findAaveFactoryAndPool aa coinA coinB = do +findAaveFactoryAndPool aa lpToFind = do (oref1, o1, lps) <- findAaveFactory aa case [ lp' | lp' <- lps - , lp' == LiquidityPool coinA coinB + , lp' == lpToFind ] of [lp] -> do (oref2, o2, a) <- findAavePool aa lp @@ -536,8 +484,8 @@ ownerEndpoint = do -- | Schema for the endpoints for users of Aave. type AaveUserSchema = BlockchainActions - .\/ Endpoint "create" CreateParams - .\/ Endpoint "close" CloseParams + .\/ Endpoint "create" Integer + .\/ Endpoint "close" Coin .\/ Endpoint "stop" () -- | Type of the Aave user contract state. From 0943616129899a43f7ec4b59d1619e8596ce02f2 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 30 Apr 2021 16:52:35 +0700 Subject: [PATCH 006/169] add aToken into aave link --- .../src/Plutus/Contracts/LendingPool.hs | 130 ++++++------------ 1 file changed, 44 insertions(+), 86 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index fe657c5af..b3d3daf50 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -20,7 +20,6 @@ module Plutus.Contracts.LendingPool ( Coin (..) , coin, coinValueOf , Aave (..), aave - , poolStateCoinFromAaveCurrency , AaveUserSchema, UserContractState (..) , start, create, close , ownerEndpoint, userEndpoints @@ -49,8 +48,9 @@ import Prelude (Semigroup (..)) import qualified Prelude import Text.Printf (printf) -aaveTokenName, poolStateTokenName :: TokenName -aaveTokenName = "Aave" +aaveProtocolName, aaveTokenName, poolStateTokenName :: TokenName +aaveProtocolName = "Aave" +aaveTokenName = "aToken" poolStateTokenName = "Pool State" -- | A pair consisting of a 'CurrencySymbol' and a 'TokenName'. @@ -105,48 +105,6 @@ coinValueOf v Coin{..} = valueOf v cCurrency cToken hashCoin :: Coin -> ByteString hashCoin Coin{..} = sha2_256 $ concatenate (unCurrencySymbol cCurrency) (unTokenName cToken) -data Sqrt = - Imaginary - | Exact Integer - | Irrational Integer - deriving stock Show - -PlutusTx.unstableMakeIsData ''Sqrt -PlutusTx.makeLift ''Sqrt - -{-# INLINABLE rsqrt #-} -rsqrt :: Integer -> Integer -> Sqrt -rsqrt n d - | n * d < 0 = Imaginary - | n == 0 = Exact 0 - | n == d = Exact 1 - | n < 0 = rsqrt (negate n) (negate d) - | otherwise = go 1 $ 1 + divide n d - where - go :: Integer -> Integer -> Sqrt - go l u - | l * l * d == n = Exact l - | u == (l + 1) = Irrational l - | otherwise = - let - m = divide (l + u) 2 - in - if m * m * d <= n then go m u - else go l m - -{-# INLINABLE isqrt #-} -isqrt :: Integer -> Sqrt -isqrt n = rsqrt n 1 - -{-# INLINABLE calculateInitialLiquidity #-} -calculateInitialLiquidity :: Integer -> Integer -> Integer -calculateInitialLiquidity outA outB = case isqrt (outA * outB) of - Exact l - | l > 0 -> l - Irrational l - | l > 0 -> l + 1 - _ -> traceError "insufficient liquidity" - data LendingPool = LendingPool { lpCoin :: Coin, lpIssuer :: PubKeyHash @@ -165,18 +123,19 @@ instance Eq LendingPool where hashLendingPool :: LendingPool -> ByteString hashLendingPool LendingPool{..} = sha2_256 $ hashCoin lpCoin <> getPubKeyHash lpIssuer -newtype Aave = Aave - { aaveCoin :: Coin +data Aave = Aave + { aaveProtocolInst :: Coin, + aaveToken :: Coin } deriving stock (Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) PlutusTx.makeLift ''Aave instance Prelude.Eq Aave where - u == v = aaveCoin u Prelude.== aaveCoin v + u == v = aaveProtocolInst u Prelude.== aaveProtocolInst v instance Prelude.Ord Aave where - compare u v = Prelude.compare (aaveCoin u) (aaveCoin v) + compare u v = Prelude.compare (aaveProtocolInst u) (aaveProtocolInst v) data AaveAction = Create LendingPool | Close deriving Show @@ -205,9 +164,9 @@ validateCreate :: Aave -> ValidatorCtx -> Bool validateCreate Aave{..} c lps lp@LendingPool{..} ctx = - traceIfFalse "Aave coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) aaveCoin == 1) && + traceIfFalse "Aave coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) aaveProtocolInst == 1) && notElem lp lps && - Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ coin aaveCoin 1) && + Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ coin aaveProtocolInst 1) && (coinValueOf forged c == 1) -- TODO validate aTokens forged -- Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp liquidity) $ coin c 1) @@ -223,10 +182,10 @@ validateCreate Aave{..} c lps lp@LendingPool{..} ctx = {-# INLINABLE validateCloseFactory #-} validateCloseFactory :: Aave -> Coin -> [LendingPool] -> ValidatorCtx -> Bool validateCloseFactory aa c lps ctx = - traceIfFalse "Aave coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) usC == 1) && + traceIfFalse "Aave coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) aaC == 1) && traceIfFalse "wrong forge value" (txInfoForge info == negate (coin c 1)) && traceIfFalse "factory output wrong" - (Constraints.checkOwnOutputConstraint ctx $ OutputConstraint (Factory $ filter (/= fst lpLiquidity) lps) $ coin usC 1) + (Constraints.checkOwnOutputConstraint ctx $ OutputConstraint (Factory $ filter (/= fst lpLiquidity) lps) $ coin aaC 1) where info :: TxInfo info = valCtxTxInfo ctx @@ -244,8 +203,8 @@ validateCloseFactory aa c lps ctx = Nothing -> traceError "pool input witness missing" Just (_, _, h) -> findPoolDatum info h - usC :: Coin - usC = aaveCoin aa + aaC :: Coin + aaC = aaveProtocolInst aa {-# INLINABLE validateClosePool #-} validateClosePool :: Aave -> ValidatorCtx -> Bool @@ -257,7 +216,7 @@ validateClosePool aa ctx = hasFactoryInput hasFactoryInput :: Bool hasFactoryInput = traceIfFalse "Aave factory input expected" $ - coinValueOf (valueSpent info) (aaveCoin aa) == 1 + coinValueOf (valueSpent info) (aaveProtocolInst aa) == 1 {-# INLINABLE findPoolDatum #-} @@ -291,7 +250,7 @@ validateLiquidityForging aa tn ctx = case [ i _ -> traceError "pool state forging without Aave input" where aaC, lpC :: Coin - aaC = aaveCoin aa + aaC = aaveProtocolInst aa lpC = Coin (ownCurrencySymbol ctx) tn aaveInstance :: Aave -> Scripts.ScriptInstance AaveScript @@ -315,8 +274,8 @@ aaveHash = Scripts.validatorHash . aaveScript aaveAddress :: Aave -> Ledger.Address aaveAddress = ScriptAddress . aaveHash -aave :: CurrencySymbol -> Aave -aave cs = Aave $ Coin cs aaveTokenName +aave :: CurrencySymbol -> CurrencySymbol -> Aave +aave protocol token = Aave (Coin protocol aaveProtocolName) (Coin token aaveTokenName) liquidityPolicy :: Aave -> MonetaryPolicy liquidityPolicy aa = mkMonetaryPolicyScript $ @@ -330,11 +289,6 @@ liquidityCurrency = scriptCurrencySymbol . liquidityPolicy poolStateCoin :: Aave -> Coin poolStateCoin = flip Coin poolStateTokenName . liquidityCurrency --- | Gets the 'Coin' used to identity liquidity pools. -poolStateCoinFromAaveCurrency :: CurrencySymbol -- ^ The currency identifying the Aave instance. - -> Coin -poolStateCoinFromAaveCurrency = poolStateCoin . aave - -- | Creates a Aave "factory". This factory will keep track of the existing liquidity pools and enforce that there will be at most one liquidity pool -- for any pair of tokens at any given time. start :: HasBlockchainActions s => Contract w s Text Aave @@ -342,11 +296,15 @@ start = do pkh <- pubKeyHash <$> ownPubKey cs <- fmap Currency.currencySymbol $ mapError (pack . show @Currency.CurrencyError) $ - Currency.forgeContract pkh [(aaveTokenName, 1)] - let c = Coin cs aaveTokenName - aa = aave cs + Currency.forgeContract pkh [(aaveProtocolName, 1)] + token <- fmap Currency.currencySymbol $ + mapError (pack . show @Currency.CurrencyError) $ + Currency.forgeContract pkh [(aaveTokenName, 0)] + let c = Coin cs aaveProtocolName + let tokenCoin = Coin token aaveTokenName + aa = aave cs token inst = aaveInstance aa - tx = mustPayToTheScript (Factory []) $ coin c 1 + tx = mustPayToTheScript (Factory []) $ coin c 1 <> coin tokenCoin 0 ledgerTx <- submitTxConstraints inst tx void $ awaitTxConfirmed $ txId ledgerTx @@ -363,22 +321,22 @@ create aa aTokensNum = do (oref, o, lps) <- findAaveFactory aa let c = Coin cs poolStateTokenName let lp = LendingPool c pkh - let usInst = aaveInstance aa - usScript = aaveScript aa - usDat1 = Factory $ lp : lps - usDat2 = Pool lp aTokensNum + let aaInst = aaveInstance aa + aaScript = aaveScript aa + aaDat1 = Factory $ lp : lps + aaDat2 = Pool lp aTokensNum psC = poolStateCoin aa - usVal = coin (aaveCoin aa) 1 + aaVal = coin (aaveProtocolInst aa) 1 -- TODO: forge aTokens lpVal = coin psC 1 - lookups = Constraints.scriptInstanceLookups usInst <> - Constraints.otherScript usScript <> + lookups = Constraints.scriptInstanceLookups aaInst <> + Constraints.otherScript aaScript <> Constraints.monetaryPolicy (liquidityPolicy aa) <> Constraints.unspentOutputs (Map.singleton oref o) - tx = Constraints.mustPayToTheScript usDat1 usVal <> - Constraints.mustPayToTheScript usDat2 lpVal <> + tx = Constraints.mustPayToTheScript aaDat1 aaVal <> + Constraints.mustPayToTheScript aaDat2 lpVal <> Constraints.mustForgeValue (coin psC 1) <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ Create lp) @@ -393,22 +351,22 @@ close aa poolCoin = do pkh <- pubKeyHash <$> ownPubKey ((oref1, o1, lps), (oref2, o2, lp, liquidity)) <- findAaveFactoryAndPool aa $ LendingPool poolCoin pkh pkh <- pubKeyHash <$> ownPubKey - let usInst = aaveInstance aa - usScript = aaveScript aa - usDat = Factory $ filter (/= lp) lps - usC = aaveCoin aa + let aaInst = aaveInstance aa + aaScript = aaveScript aa + aaDat = Factory $ filter (/= lp) lps + aaC = aaveProtocolInst aa psC = poolStateCoin aa - usVal = coin usC 1 + aaVal = coin aaC 1 psVal = coin psC 1 redeemer = Redeemer $ PlutusTx.toData Close - lookups = Constraints.scriptInstanceLookups usInst <> - Constraints.otherScript usScript <> + lookups = Constraints.scriptInstanceLookups aaInst <> + Constraints.otherScript aaScript <> Constraints.monetaryPolicy (liquidityPolicy aa) <> Constraints.ownPubKeyHash pkh <> Constraints.unspentOutputs (Map.singleton oref1 o1 <> Map.singleton oref2 o2) - tx = Constraints.mustPayToTheScript usDat usVal <> + tx = Constraints.mustPayToTheScript aaDat aaVal <> Constraints.mustForgeValue (negate psVal) <> Constraints.mustSpendScriptOutput oref1 redeemer <> Constraints.mustSpendScriptOutput oref2 redeemer <> @@ -445,7 +403,7 @@ findAaveInstance aa c f = do return (oref, o, a) findAaveFactory :: HasBlockchainActions s => Aave -> Contract w s Text (TxOutRef, TxOutTx, [LendingPool]) -findAaveFactory aa@Aave{..} = findAaveInstance aa aaveCoin $ \case +findAaveFactory aa@Aave{..} = findAaveInstance aa aaveProtocolInst $ \case Factory lps -> Just lps Pool _ _ -> Nothing From 09e2532fb216d1dffbe48adbbbb3d2cecdb7f686 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 30 Apr 2021 17:12:23 +0700 Subject: [PATCH 007/169] forge aTokens --- MetaLamp/lending-pool/cabal.project | 19 ++++++++++--------- MetaLamp/lending-pool/plutus-starter.cabal | 1 + .../src/Plutus/Contracts/LendingPool.hs | 15 ++++++++------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/MetaLamp/lending-pool/cabal.project b/MetaLamp/lending-pool/cabal.project index f7e25adc5..903c88a94 100644 --- a/MetaLamp/lending-pool/cabal.project +++ b/MetaLamp/lending-pool/cabal.project @@ -12,24 +12,25 @@ benchmarks: true source-repository-package type: git location: https://github.com/input-output-hk/plutus.git - subdir: + subdir: freer-extras playground-common - plutus-core - plutus-contract - plutus-ledger - plutus-ledger-api - plutus-tx - plutus-tx-plugin + plutus-core + plutus-contract + plutus-ledger + plutus-ledger-api + plutus-tx + plutus-tx-plugin plutus-pab + plutus-ledger-api plutus-use-cases prettyprinter-configurable quickcheck-dynamic tag: 03a95411238225db1d10288fbd3b405f5f53c78b -- The following sections are copied from the 'plutus' repository cabal.project at the revision --- given above. --- This is necessary because the 'plutus' libraries depend on a number of other libraries which are +-- given above. +-- This is necessary because the 'plutus' libraries depend on a number of other libraries which are -- not on Hackage, and so need to be pulled in as `source-repository-package`s themselves. Make sure to -- re-update this section from the template when you do an upgrade. package eventful-sql-common diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 162ad3148..4d77943e5 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -38,6 +38,7 @@ library plutus-tx-plugin, plutus-tx, plutus-ledger, + plutus-ledger-api, plutus-use-cases hs-source-dirs: src examples/src default-language: Haskell2010 diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index b3d3daf50..c79bc2383 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -15,7 +15,6 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} - module Plutus.Contracts.LendingPool ( Coin (..) , coin, coinValueOf @@ -47,6 +46,7 @@ import PlutusTx.Prelude hiding (Semigroup (..), unless import Prelude (Semigroup (..)) import qualified Prelude import Text.Printf (printf) +import Plutus.V1.Ledger.Ada ( lovelaceValueOf ) aaveProtocolName, aaveTokenName, poolStateTokenName :: TokenName aaveProtocolName = "Aave" @@ -167,9 +167,8 @@ validateCreate Aave{..} c lps lp@LendingPool{..} ctx = traceIfFalse "Aave coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) aaveProtocolInst == 1) && notElem lp lps && Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ coin aaveProtocolInst 1) && - (coinValueOf forged c == 1) - -- TODO validate aTokens forged - -- Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp liquidity) $ coin c 1) + (coinValueOf forged c == 1) && + Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp aTokensNum) $ coin c 1) where poolOutput :: TxOutInfo poolOutput = case [o | o <- getContinuingOutputs ctx, coinValueOf (txOutValue o) c == 1] of @@ -179,6 +178,9 @@ validateCreate Aave{..} c lps lp@LendingPool{..} ctx = forged :: Value forged = txInfoForge $ valCtxTxInfo ctx + aTokensNum :: Integer + aTokensNum = coinValueOf forged aaveToken + {-# INLINABLE validateCloseFactory #-} validateCloseFactory :: Aave -> Coin -> [LendingPool] -> ValidatorCtx -> Bool validateCloseFactory aa c lps ctx = @@ -327,8 +329,7 @@ create aa aTokensNum = do aaDat2 = Pool lp aTokensNum psC = poolStateCoin aa aaVal = coin (aaveProtocolInst aa) 1 - -- TODO: forge aTokens - lpVal = coin psC 1 + lpVal = coin psC 1 <> lovelaceValueOf aTokensNum lookups = Constraints.scriptInstanceLookups aaInst <> Constraints.otherScript aaScript <> @@ -337,7 +338,7 @@ create aa aTokensNum = do tx = Constraints.mustPayToTheScript aaDat1 aaVal <> Constraints.mustPayToTheScript aaDat2 lpVal <> - Constraints.mustForgeValue (coin psC 1) <> + Constraints.mustForgeValue (coin psC 1 <> coin (aaveToken aa) aTokensNum) <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ Create lp) ledgerTx <- submitTxConstraintsWith lookups tx From e1dc6ba117f1893927842e04690ed1774293b01b Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 3 May 2021 18:10:40 +0700 Subject: [PATCH 008/169] wip add aave pab server --- MetaLamp/lending-pool/pab/Main.hs | 283 ++++++++++++++++----- MetaLamp/lending-pool/plutus-starter.cabal | 22 +- 2 files changed, 234 insertions(+), 71 deletions(-) diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index 10822ec12..a0f682867 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -4,87 +4,244 @@ {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE EmptyDataDecls #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE RecordWildCards #-} -module Main(main) where - -import Control.Monad (void) -import Control.Monad.Freer (Eff, Member, interpret, type (~>)) -import Control.Monad.Freer.Error (Error) -import Control.Monad.IO.Class (MonadIO (..)) -import Data.Aeson (FromJSON (..), ToJSON (..), genericToJSON, genericParseJSON - , defaultOptions, Options(..)) -import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) -import GHC.Generics (Generic) -import Plutus.Contract (BlockchainActions, ContractError) -import Plutus.PAB.Effects.Contract (ContractEffect (..)) -import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), type (.\\)) -import qualified Plutus.PAB.Effects.Contract.Builtin as Builtin -import Plutus.PAB.Simulator (SimulatorEffectHandlers) -import qualified Plutus.PAB.Simulator as Simulator -import Plutus.PAB.Types (PABError (..)) -import qualified Plutus.PAB.Webserver.Server as PAB.Server -import Plutus.Contracts.Game as Game -import Wallet.Emulator.Types (Wallet (..)) +module Main + ( main + ) where + +import Control.Monad (forM, forM_, void, when) +import Control.Monad.Freer (Eff, Member, reinterpret, type (~>)) +import Control.Monad.Freer.Extras.Log (LogMsg,logDebug) +import Control.Monad.IO.Class (MonadIO (..)) +import Data.Bifunctor (Bifunctor (first)) +import qualified Data.Map.Strict as Map +import qualified Data.Monoid as Monoid +import Data.Row +import qualified Data.Semigroup as Semigroup +import Data.Text (Text,pack) +import Data.Text.Extras (tshow) +import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) +import GHC.Generics (Generic) +import Ledger +import Ledger.Ada +import Ledger.Constraints +import Ledger.Value as Value +import Playground.Schema (endpointsToSchemas) +import Plutus.Contract + ( Contract, + tell, + awaitTxConfirmed, + ownPubKey, + submitTx ) +import qualified Plutus.Contracts.Currency as Currency +import qualified Plutus.Contracts.LendingPool as LP +import Plutus.PAB.Effects.Contract (ContractEffect (..), PABContract (..)) +-- import Plutus.PAB.Effects.Contract.ContractTest (doContractInit, doContractUpdate) +import Plutus.PAB.Events.Contract (ContractPABRequest) +import Plutus.PAB.Events.ContractInstanceState (PartiallyDecodedResponse) +import Plutus.PAB.Monitoring.PABLogMsg (ContractEffectMsg (..)) +import Plutus.PAB.Simulator (SimulatorContractHandler, SimulatorEffectHandlers) +import qualified Plutus.PAB.Simulator as Simulator +import Plutus.PAB.Types (PABError (..)) +import qualified Plutus.PAB.Webserver.Server as PAB.Server +import Prelude hiding (init) +import Wallet.Emulator.Types (Wallet (..), walletPubKey) +import qualified Plutus.PAB.Events.Contract as C +import qualified Data.Aeson as JSON +import qualified Data.Aeson.Types as JSON +import Plutus.Contract.State (ContractRequest (..), ContractResponse (..)) +import qualified Plutus.Contract.State as ContractState +import Plutus.Contract.Schema (Event, Handlers, Input, Output) +import Plutus.Contract.Resumable (Response) +import qualified Plutus.PAB.Events.ContractInstanceState as C +import Control.Monad.Freer.Error (Error, throwError) main :: IO () main = void $ Simulator.runSimulationWith handlers $ do - Simulator.logString @(Builtin StarterContracts) "Starting plutus-starter PAB webserver on port 8080. Press enter to exit." + Simulator.logString @AavePabServer "Starting AavePabServer PAB webserver on port 8080. Press enter to exit." shutdown <- PAB.Server.startServerDebug - -- Example of spinning up a game instance on startup - -- void $ Simulator.activateContract (Wallet 1) GameContract - -- You can add simulator actions here: - -- Simulator.observableState - -- etc. - -- That way, the simulation gets to a predefined state and you don't have to - -- use the HTTP API for setup. - - -- Pressing enter results in the balances being printed - void $ liftIO getLine - - Simulator.logString @(Builtin StarterContracts) "Balances at the end of the simulation" - b <- Simulator.currentBalances - Simulator.logBalances @(Builtin StarterContracts) b + cidInit <- Simulator.activateContract (Wallet 1) Init + cs <- flip Simulator.waitForState cidInit $ \json -> case JSON.fromJSON json of + JSON.Success (Just (Semigroup.Last cur)) -> Just $ Currency.currencySymbol cur + _ -> Nothing + _ <- Simulator.waitUntilFinished cidInit + Simulator.logString @AavePabServer $ "Initialization finished. Minted: " ++ show cs + let coins = Map.fromList [(tn, LP.Coin cs tn) | tn <- tokenNames] + ada = LP.Coin adaSymbol adaToken + + cidStart <- Simulator.activateContract (Wallet 1) AaveStart + us <- flip Simulator.waitForState cidStart $ \json -> case (JSON.fromJSON json :: JSON.Result (Monoid.Last (Either Text LP.Aave))) of + JSON.Success (Monoid.Last (Just (Right us))) -> Just us + _ -> Nothing + Simulator.logString @AavePabServer $ "AavePabServer instance created: " ++ show us + + cids <- fmap Map.fromList $ forM wallets $ \w -> do + cid <- Simulator.activateContract w $ AaveUser us + Simulator.logString @AavePabServer $ "AavePabServer user contract started for " ++ show w + return (w, cid) + + let cp = 100000 :: Integer + Simulator.logString @AavePabServer $ "creating liquidity pool: " ++ show (JSON.encode cp) + _ <- Simulator.callEndpointOnInstance (cids Map.! Wallet 2) "create" cp + flip Simulator.waitForState (cids Map.! Wallet 2) $ \json -> case (JSON.fromJSON json :: JSON.Result (Monoid.Last (Either Text LP.UserContractState))) of + JSON.Success (Monoid.Last (Just (Right LP.Created))) -> Just () + _ -> Nothing + Simulator.logString @AavePabServer "liquidity pool created" + + _ <- liftIO getLine shutdown -data StarterContracts = - GameContract +data AavePabServer + +data AaveContracts = + Init + | AaveStart + | AaveUser LP.Aave deriving (Eq, Ord, Show, Generic) + deriving anyclass (JSON.FromJSON, JSON.ToJSON) --- NOTE: Because 'StarterContracts' only has one constructor, corresponding to --- the demo 'Game' contract, we kindly ask aeson to still encode it as if it had --- many; this way we get to see the label of the contract in the API output! --- If you simple have more contracts, you can just use the anyclass deriving --- statement on 'StarterContracts' instead: --- --- `... deriving anyclass (ToJSON, FromJSON)` -instance ToJSON StarterContracts where - toJSON = genericToJSON defaultOptions { - tagSingleConstructors = True } -instance FromJSON StarterContracts where - parseJSON = genericParseJSON defaultOptions { - tagSingleConstructors = True } - -instance Pretty StarterContracts where +instance PABContract AavePabServer where + type ContractDef AavePabServer = AaveContracts + type State AavePabServer = PartiallyDecodedResponse ContractPABRequest + serialisableState _ = id + +instance Pretty AaveContracts where pretty = viaShow -handleStarterContract :: +handleAaveContract :: ( Member (Error PABError) effs + , Member (LogMsg ContractEffectMsg) effs ) - => ContractEffect (Builtin StarterContracts) + => ContractEffect AavePabServer ~> Eff effs -handleStarterContract = Builtin.handleBuiltin getSchema getContract where - getSchema = \case - GameContract -> Builtin.endpointsToSchemas @(Game.GameSchema .\\ BlockchainActions) - getContract = \case - GameContract -> SomeBuiltin (Game.game @ContractError) +handleAaveContract = \case + InitialState c -> case c of + Init -> doContractInit init + AaveStart -> doContractInit start + AaveUser us -> doContractInit $ userEndpoints us + UpdateContract c state p -> case c of + Init -> doContractUpdate init state p + AaveStart -> doContractUpdate start state p + AaveUser us -> doContractUpdate (userEndpoints us) state p + ExportSchema t -> case t of + Init -> pure $ endpointsToSchemas @Empty + AaveStart -> pure $ endpointsToSchemas @Empty + AaveUser _ -> pure $ endpointsToSchemas @Empty + -- TODO: + -- replace with (Marlowe.MarloweSchema .\\ BlockchainActions) + -- (needs some instances for the Marlowe types (MarloweParams, etc)) + where + init = first tshow initContract + start = first tshow LP.ownerEndpoint + userEndpoints = first tshow . LP.userEndpoints + +handlers :: SimulatorEffectHandlers AavePabServer +handlers = Simulator.mkSimulatorHandlers @AavePabServer [] mlw where + mlw :: SimulatorContractHandler AavePabServer + mlw = + Simulator.handleContractEffectMsg @AavePabServer + . reinterpret handleAaveContract + +initContract :: Contract (Maybe (Semigroup.Last Currency.Currency)) Currency.CurrencySchema Currency.CurrencyError () +initContract = do + ownPK <- pubKeyHash <$> ownPubKey + cur <- Currency.forgeContract ownPK [(tn, fromIntegral (length wallets) * amount) | tn <- tokenNames] + let cs = Currency.currencySymbol cur + v = mconcat [Value.singleton cs tn amount | tn <- tokenNames] + forM_ wallets $ \w -> do + let pkh = pubKeyHash $ walletPubKey w + when (pkh /= ownPK) $ do + tx <- submitTx $ mustPayToPubKey pkh v + awaitTxConfirmed $ txId tx + tell $ Just $ Semigroup.Last cur + where + amount = 1000000 + +wallets :: [Wallet] +wallets = [Wallet i | i <- [1 .. 4]] + +tokenNames :: [TokenName] +tokenNames = ["A", "B", "C", "D"] -handlers :: SimulatorEffectHandlers (Builtin StarterContracts) -handlers = - Simulator.mkSimulatorHandlers @(Builtin StarterContracts) [GameContract] - $ interpret handleStarterContract +doContractInit :: + forall w schema effs. + ( Member (Error PABError) effs + , Forall (Output schema) JSON.ToJSON + , Forall (Input schema) JSON.ToJSON + , Monoid w + , JSON.ToJSON w + ) + => Contract w schema Text () + -> Eff effs (PartiallyDecodedResponse ContractPABRequest) +doContractInit contract = either throwError pure $ do + let value = ContractState.initialiseContract contract + fromString $ fmap (fmap C.unContractHandlerRequest) $ JSON.eitherDecode $ JSON.encode value + +doContractUpdate :: + forall w schema effs. + ( Member (Error PABError) effs + , AllUniqueLabels (Input schema) + , Forall (Input schema) JSON.FromJSON + , Forall (Input schema) JSON.ToJSON + , Forall (Output schema) JSON.ToJSON + , Member (LogMsg ContractEffectMsg) effs + , Monoid w + , JSON.ToJSON w + ) + => Contract w schema Text () + -> PartiallyDecodedResponse ContractPABRequest + -> Response C.ContractResponse + -> Eff effs (PartiallyDecodedResponse ContractPABRequest) +doContractUpdate contract oldState response = do + let C.PartiallyDecodedResponse{..} = oldState + oldState' <- traverse fromJSON newState + typedResp <- traverse (fromJSON . JSON.toJSON . C.ContractHandlersResponse) response + let conReq = ContractRequest{oldState = oldState', event = typedResp } + logDebug $ SendContractRequest (fmap JSON.toJSON conReq) + let response' = mkResponse $ ContractState.insertAndUpdateContract contract conReq + logDebug $ ReceiveContractResponse response' + pure response' + +fromString :: Either String a -> Either PABError a +fromString = first (ContractCommandError 0 . pack) + +mkResponse :: + forall w schema err. + ( Forall (Output schema) JSON.ToJSON + , Forall (Input schema) JSON.ToJSON + , JSON.ToJSON err + , JSON.ToJSON w + ) + => ContractResponse w err (Event schema) (Handlers schema) + -> PartiallyDecodedResponse ContractPABRequest +mkResponse ContractResponse{newState, hooks, logs, observableState, err} = + C.PartiallyDecodedResponse + { C.newState = fmap JSON.toJSON newState + , C.hooks = fmap (fmap (encodeRequest @schema)) hooks + , C.logs = logs + , C.observableState = JSON.toJSON observableState + , C.err = fmap JSON.toJSON err + } + +encodeRequest :: + forall schema. + ( Forall (Output schema) JSON.ToJSON + ) + => Handlers schema + -> ContractPABRequest +encodeRequest = either error C.unContractHandlerRequest . JSON.eitherDecode . JSON.encode +fromJSON :: (Member (Error PABError) effs, JSON.FromJSON a) => JSON.Value -> Eff effs a +fromJSON = + either (throwError . OtherError . pack) pure + . JSON.parseEither JSON.parseJSON diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 4d77943e5..a798926dd 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -77,11 +77,17 @@ executable plutus-starter-pab -threaded build-depends: base >= 4.9 && < 5, - plutus-contract -any, - plutus-pab -any, - plutus-starter -any, - aeson -any, - freer-simple -any, - prettyprinter -any, - freer-extras -any, - plutus-ledger -any + aeson, + freer-simple, + freer-extras, + prettyprinter, + containers, + row-types, + text, + -- Plutus: + plutus-ledger, + plutus-contract, + plutus-pab, + plutus-starter, + playground-common, + plutus-use-cases From 99e67160196f442863b88561c11c57016dfcee80 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 4 May 2021 17:48:18 +0700 Subject: [PATCH 009/169] update plutus && rm example code --- .../.devcontainer/devcontainer.json | 23 -- MetaLamp/lending-pool/cabal.project | 2 +- .../examples/src/Plutus/Contracts/Game.hs | 162 ------------- MetaLamp/lending-pool/examples/test/Spec.hs | 21 -- .../lending-pool/examples/test/Spec/Game.hs | 60 ----- .../lending-pool/examples/test/Spec/game.pir | 217 ------------------ MetaLamp/lending-pool/plutus-starter.cabal | 28 +-- MetaLamp/lending-pool/src/MyModule.hs | 7 - 8 files changed, 2 insertions(+), 518 deletions(-) delete mode 100644 MetaLamp/lending-pool/.devcontainer/devcontainer.json delete mode 100644 MetaLamp/lending-pool/examples/src/Plutus/Contracts/Game.hs delete mode 100644 MetaLamp/lending-pool/examples/test/Spec.hs delete mode 100644 MetaLamp/lending-pool/examples/test/Spec/Game.hs delete mode 100644 MetaLamp/lending-pool/examples/test/Spec/game.pir delete mode 100644 MetaLamp/lending-pool/src/MyModule.hs diff --git a/MetaLamp/lending-pool/.devcontainer/devcontainer.json b/MetaLamp/lending-pool/.devcontainer/devcontainer.json deleted file mode 100644 index 2a514c5f2..000000000 --- a/MetaLamp/lending-pool/.devcontainer/devcontainer.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "Plutus Starter Project", - "image": "plutus-devcontainer:latest", - - "remoteUser": "plutus", - - "mounts": [ - // This shares cabal's remote repository state with the host. We don't mount the whole of '.cabal', because - // 1. '.cabal/config' contains absolute paths that will only make sense on the host, and - // 2. '.cabal/store' is not necessarily portable to different version of cabal etc. - "source=${localEnv:HOME}/.cabal/packages,target=/home/plutus/.cabal/packages,type=bind,consistency=cached", - ], - - "settings": { - // Note: don't change from bash so it runs .bashrc - "terminal.integrated.shell.linux": "/bin/bash" - }, - - // IDs of extensions inside container - "extensions": [ - "haskell.haskell" - ], -} diff --git a/MetaLamp/lending-pool/cabal.project b/MetaLamp/lending-pool/cabal.project index 903c88a94..6f99740fc 100644 --- a/MetaLamp/lending-pool/cabal.project +++ b/MetaLamp/lending-pool/cabal.project @@ -26,7 +26,7 @@ source-repository-package plutus-use-cases prettyprinter-configurable quickcheck-dynamic - tag: 03a95411238225db1d10288fbd3b405f5f53c78b + tag: 58bf9ed626d498c140c69a859a508da03843d097 -- The following sections are copied from the 'plutus' repository cabal.project at the revision -- given above. diff --git a/MetaLamp/lending-pool/examples/src/Plutus/Contracts/Game.hs b/MetaLamp/lending-pool/examples/src/Plutus/Contracts/Game.hs deleted file mode 100644 index 4f7dfe0be..000000000 --- a/MetaLamp/lending-pool/examples/src/Plutus/Contracts/Game.hs +++ /dev/null @@ -1,162 +0,0 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE KindSignatures #-} -{-# LANGUAGE MonoLocalBinds #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE PartialTypeSignatures #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} -{-# LANGUAGE TypeSynonymInstances #-} -{-# LANGUAGE ViewPatterns #-} - --- | A guessing game -module Plutus.Contracts.Game - ( lock - , guess - , game - , GameSchema - , GuessParams(..) - , LockParams(..) - -- * Scripts - , gameValidator - , hashString - , clearString - -- * Address - , gameAddress - , validateGuess - -- * Traces - , guessTrace - , guessWrongTrace - , lockTrace - ) where - -import Control.Monad (void) -import Data.Aeson (FromJSON, ToJSON) -import GHC.Generics (Generic) -import Ledger (Address, Validator, ValidatorCtx, Value) -import qualified Ledger.Constraints as Constraints -import qualified Ledger.Typed.Scripts as Scripts -import Plutus.Contract -import Plutus.Contract.Schema () -import Plutus.Trace.Emulator (EmulatorTrace) -import qualified Plutus.Trace.Emulator as Trace -import qualified PlutusTx -import PlutusTx.Prelude -import Schema (ToArgument, ToSchema) -import Wallet.Emulator (Wallet (..)) - -import qualified Ledger -import qualified Ledger.Ada as Ada - -import qualified Data.ByteString.Char8 as C -import qualified Prelude - -newtype HashedString = HashedString ByteString deriving newtype PlutusTx.IsData - -PlutusTx.makeLift ''HashedString - -newtype ClearString = ClearString ByteString deriving newtype PlutusTx.IsData - -PlutusTx.makeLift ''ClearString - -type GameSchema = - BlockchainActions - .\/ Endpoint "lock" LockParams - .\/ Endpoint "guess" GuessParams - --- | The validation function (DataValue -> RedeemerValue -> ValidatorCtx -> Bool) -validateGuess :: HashedString -> ClearString -> ValidatorCtx -> Bool -validateGuess (HashedString actual) (ClearString guess') _ = actual == sha2_256 guess' - --- | The validator script of the game. -gameValidator :: Validator -gameValidator = Scripts.validatorScript gameInstance - -data Game -instance Scripts.ScriptType Game where - type instance RedeemerType Game = ClearString - type instance DatumType Game = HashedString - -gameInstance :: Scripts.ScriptInstance Game -gameInstance = Scripts.validator @Game - $$(PlutusTx.compile [|| validateGuess ||]) - $$(PlutusTx.compile [|| wrap ||]) where - wrap = Scripts.wrapValidator @HashedString @ClearString - --- create a data script for the guessing game by hashing the string --- and lifting the hash to its on-chain representation -hashString :: String -> HashedString -hashString = HashedString . sha2_256 . C.pack - --- create a redeemer script for the guessing game by lifting the --- string to its on-chain representation -clearString :: String -> ClearString -clearString = ClearString . C.pack - --- | The address of the game (the hash of its validator script) -gameAddress :: Address -gameAddress = Ledger.scriptAddress gameValidator - --- | Parameters for the "lock" endpoint -data LockParams = LockParams - { secretWord :: String - , amount :: Value - } - deriving stock (Prelude.Eq, Prelude.Show, Generic) - deriving anyclass (FromJSON, ToJSON, ToSchema, ToArgument) - --- | Parameters for the "guess" endpoint -newtype GuessParams = GuessParams - { guessWord :: String - } - deriving stock (Prelude.Eq, Prelude.Show, Generic) - deriving anyclass (FromJSON, ToJSON, ToSchema, ToArgument) - -lock :: AsContractError e => Contract () GameSchema e () -lock = do - LockParams secret amt <- endpoint @"lock" @LockParams - let tx = Constraints.mustPayToTheScript (hashString secret) amt - void (submitTxConstraints gameInstance tx) - -guess :: AsContractError e => Contract () GameSchema e () -guess = do - GuessParams theGuess <- endpoint @"guess" @GuessParams - unspentOutputs <- utxoAt gameAddress - let redeemer = clearString theGuess - tx = collectFromScript unspentOutputs redeemer - void (submitTxConstraintsSpending gameInstance unspentOutputs tx) - -game :: AsContractError e => Contract () GameSchema e () -game = lock `select` guess - -lockTrace :: EmulatorTrace () -lockTrace = do - let w1 = Wallet 1 - hdl <- Trace.activateContractWallet w1 (game @ContractError) - Trace.callEndpoint @"lock" hdl (LockParams "secret" (Ada.lovelaceValueOf 10)) - void $ Trace.waitNSlots 1 - -guessTrace :: EmulatorTrace () -guessTrace = do - lockTrace - let w2 = Wallet 2 - hdl <- Trace.activateContractWallet w2 (game @ContractError) - Trace.callEndpoint @"guess" hdl (GuessParams "secret") - -guessWrongTrace :: EmulatorTrace () -guessWrongTrace = do - lockTrace - let w2 = Wallet 2 - hdl <- Trace.activateContractWallet w2 (game @ContractError) - Trace.callEndpoint @"guess" hdl (GuessParams "SECRET") diff --git a/MetaLamp/lending-pool/examples/test/Spec.hs b/MetaLamp/lending-pool/examples/test/Spec.hs deleted file mode 100644 index 60001de7b..000000000 --- a/MetaLamp/lending-pool/examples/test/Spec.hs +++ /dev/null @@ -1,21 +0,0 @@ -{-# LANGUAGE OverloadedStrings #-} -module Main(main) where - -import qualified Spec.Game -import Test.Tasty -import Test.Tasty.Hedgehog (HedgehogTestLimit (..)) - -main :: IO () -main = defaultMain tests - --- | Number of successful tests for each hedgehog property. --- The default is 100 but we use a smaller number here in order to speed up --- the test suite. --- -limit :: HedgehogTestLimit -limit = HedgehogTestLimit (Just 5) - -tests :: TestTree -tests = localOption limit $ testGroup "use cases" [ - Spec.Game.tests - ] diff --git a/MetaLamp/lending-pool/examples/test/Spec/Game.hs b/MetaLamp/lending-pool/examples/test/Spec/Game.hs deleted file mode 100644 index e479d43ad..000000000 --- a/MetaLamp/lending-pool/examples/test/Spec/Game.hs +++ /dev/null @@ -1,60 +0,0 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} - -module Spec.Game - ( tests - ) where - -import Control.Monad (void) -import Ledger.Ada (adaValueOf) -import Plutus.Contract (Contract, ContractError) -import Plutus.Contract.Test -import Plutus.Contracts.Game -import Plutus.Trace.Emulator (ContractInstanceTag) -import qualified Plutus.Trace.Emulator as Trace -import qualified PlutusTx -import qualified PlutusTx.Prelude as PlutusTx -import Test.Tasty -import qualified Test.Tasty.HUnit as HUnit - -w1, w2 :: Wallet -w1 = Wallet 1 -w2 = Wallet 2 - -t1, t2 :: ContractInstanceTag -t1 = Trace.walletInstanceTag w1 -t2 = Trace.walletInstanceTag w2 - -theContract :: Contract () GameSchema ContractError () -theContract = game - -tests :: TestTree -tests = testGroup "game" - [ checkPredicate "Expose 'lock' and 'guess' endpoints" - (endpointAvailable @"lock" theContract (Trace.walletInstanceTag w1) - .&&. endpointAvailable @"guess" theContract (Trace.walletInstanceTag w1)) - $ void (Trace.activateContractWallet w1 theContract) - - , checkPredicate "'lock' endpoint submits a transaction" - (anyTx theContract (Trace.walletInstanceTag w1)) - $ do - hdl <- Trace.activateContractWallet w1 theContract - Trace.callEndpoint @"lock" hdl (LockParams "secret" (adaValueOf 10)) - - , checkPredicate "'guess' endpoint is available after locking funds" - (endpointAvailable @"guess" theContract (Trace.walletInstanceTag w2)) - lockTrace - - , checkPredicate "guess right (unlock funds)" - (walletFundsChange w2 (1 `timesFeeAdjust` 10) - .&&. walletFundsChange w1 (1 `timesFeeAdjust` (-10))) - guessTrace - - , checkPredicate "guess wrong" - (walletFundsChange w2 PlutusTx.zero - .&&. walletFundsChange w1 (1 `timesFeeAdjust` (-10))) - guessWrongTrace - , goldenPir "examples/test/Spec/game.pir" $$(PlutusTx.compile [|| validateGuess ||]) - , HUnit.testCase "script size is reasonable" (reasonable gameValidator 20000) - ] diff --git a/MetaLamp/lending-pool/examples/test/Spec/game.pir b/MetaLamp/lending-pool/examples/test/Spec/game.pir deleted file mode 100644 index dcea0aeab..000000000 --- a/MetaLamp/lending-pool/examples/test/Spec/game.pir +++ /dev/null @@ -1,217 +0,0 @@ -(program - (let - (nonrec) - (datatypebind - (datatype - (tyvardecl Tuple2 (fun (type) (fun (type) (type)))) - (tyvardecl a (type)) (tyvardecl b (type)) - Tuple2_match - (vardecl Tuple2 (fun a (fun b [[Tuple2 a] b]))) - ) - ) - (let - (rec) - (datatypebind - (datatype - (tyvardecl List (fun (type) (type))) - (tyvardecl a (type)) - Nil_match - (vardecl Nil [List a]) (vardecl Cons (fun a (fun [List a] [List a]))) - ) - ) - (let - (rec) - (datatypebind - (datatype - (tyvardecl Data (type)) - - Data_match - (vardecl B (fun (con bytestring) Data)) - (vardecl Constr (fun (con integer) (fun [List Data] Data))) - (vardecl I (fun (con integer) Data)) - (vardecl List (fun [List Data] Data)) - (vardecl Map (fun [List [[Tuple2 Data] Data]] Data)) - ) - ) - (let - (nonrec) - (datatypebind - (datatype - (tyvardecl Extended (fun (type) (type))) - (tyvardecl a (type)) - Extended_match - (vardecl Finite (fun a [Extended a])) - (vardecl NegInf [Extended a]) - (vardecl PosInf [Extended a]) - ) - ) - (datatypebind - (datatype - (tyvardecl Bool (type)) - - Bool_match - (vardecl True Bool) (vardecl False Bool) - ) - ) - (datatypebind - (datatype - (tyvardecl LowerBound (fun (type) (type))) - (tyvardecl a (type)) - LowerBound_match - (vardecl LowerBound (fun [Extended a] (fun Bool [LowerBound a]))) - ) - ) - (datatypebind - (datatype - (tyvardecl UpperBound (fun (type) (type))) - (tyvardecl a (type)) - UpperBound_match - (vardecl UpperBound (fun [Extended a] (fun Bool [UpperBound a]))) - ) - ) - (datatypebind - (datatype - (tyvardecl Interval (fun (type) (type))) - (tyvardecl a (type)) - Interval_match - (vardecl - Interval (fun [LowerBound a] (fun [UpperBound a] [Interval a])) - ) - ) - ) - (datatypebind - (datatype - (tyvardecl Tuple3 (fun (type) (fun (type) (fun (type) (type))))) - (tyvardecl a (type)) (tyvardecl b (type)) (tyvardecl c (type)) - Tuple3_match - (vardecl Tuple3 (fun a (fun b (fun c [[[Tuple3 a] b] c])))) - ) - ) - (datatypebind - (datatype - (tyvardecl Maybe (fun (type) (type))) - (tyvardecl a (type)) - Maybe_match - (vardecl Just (fun a [Maybe a])) (vardecl Nothing [Maybe a]) - ) - ) - (datatypebind - (datatype - (tyvardecl TxOutRef (type)) - - TxOutRef_match - (vardecl - TxOutRef (fun (con bytestring) (fun (con integer) TxOutRef)) - ) - ) - ) - (datatypebind - (datatype - (tyvardecl TxInInfo (type)) - - TxInInfo_match - (vardecl - TxInInfo - (fun TxOutRef (fun [Maybe [[[Tuple3 (con bytestring)] (con bytestring)] (con bytestring)]] (fun [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] (con integer)]] TxInInfo))) - ) - ) - ) - (datatypebind - (datatype - (tyvardecl Address (type)) - - Address_match - (vardecl PubKeyAddress (fun (con bytestring) Address)) - (vardecl ScriptAddress (fun (con bytestring) Address)) - ) - ) - (datatypebind - (datatype - (tyvardecl TxOutType (type)) - - TxOutType_match - (vardecl PayToPubKey TxOutType) - (vardecl PayToScript (fun (con bytestring) TxOutType)) - ) - ) - (datatypebind - (datatype - (tyvardecl TxOut (type)) - - TxOut_match - (vardecl - TxOut - (fun Address (fun [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] (con integer)]] (fun TxOutType TxOut))) - ) - ) - ) - (datatypebind - (datatype - (tyvardecl TxInfo (type)) - - TxInfo_match - (vardecl - TxInfo - (fun [List TxInInfo] (fun [List TxOut] (fun [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] (con integer)]] (fun [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] [[(lam k (type) (lam v (type) [List [[Tuple2 k] v]])) (con bytestring)] (con integer)]] (fun [Interval (con integer)] (fun [List (con bytestring)] (fun [List (con bytestring)] (fun [List [[Tuple2 (con bytestring)] Data]] (fun (con bytestring) TxInfo))))))))) - ) - ) - ) - (datatypebind - (datatype - (tyvardecl ValidatorCtx (type)) - - ValidatorCtx_match - (vardecl - ValidatorCtx (fun TxInfo (fun (con integer) ValidatorCtx)) - ) - ) - ) - (termbind - (strict) - (vardecl - equalsByteString - (fun (con bytestring) (fun (con bytestring) Bool)) - ) - (lam - arg - (con bytestring) - (lam - arg - (con bytestring) - [ - (lam - b - (con bool) - [ [ [ { (builtin ifThenElse) Bool } b ] True ] False ] - ) - [ [ (builtin equalsByteString) arg ] arg ] - ] - ) - ) - ) - (termbind - (strict) - (vardecl - validateGuess - (fun (con bytestring) (fun (con bytestring) (fun ValidatorCtx Bool))) - ) - (lam - ds - (con bytestring) - (lam - ds - (con bytestring) - (lam - ds - ValidatorCtx - [ [ equalsByteString ds ] [ (builtin sha2_256) ds ] ] - ) - ) - ) - ) - validateGuess - ) - ) - ) - ) -) \ No newline at end of file diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index a798926dd..cb889f48b 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -23,8 +23,6 @@ maintainer: Your email library exposed-modules: - MyModule - Plutus.Contracts.Game Plutus.Contracts.LendingPool build-depends: base >= 4.9 && < 5, @@ -40,36 +38,12 @@ library plutus-ledger, plutus-ledger-api, plutus-use-cases - hs-source-dirs: src examples/src + hs-source-dirs: src default-language: Haskell2010 ghc-options: -- See Plutus Tx readme -fobject-code -fno-ignore-interface-pragmas -fno-omit-interface-pragmas -test-suite plutus-example-projects-test - type: exitcode-stdio-1.0 - main-is: Spec.hs - hs-source-dirs: examples/test - other-modules: - Spec.Game - default-language: Haskell2010 - ghc-options: -Wall -Wnoncanonical-monad-instances - -Wincomplete-uni-patterns -Wincomplete-record-updates - -Wredundant-constraints -Widentities -rtsopts - -- See Plutus Tx readme - -fobject-code -fno-ignore-interface-pragmas -fno-omit-interface-pragmas - build-depends: - plutus-tx -any, - plutus-tx-plugin, - plutus-contract -any, - plutus-ledger -any, - plutus-starter -any - build-depends: - base >=4.9 && <5, - tasty -any, - tasty-hunit -any, - tasty-hedgehog >=0.2.0.0 - executable plutus-starter-pab main-is: Main.hs hs-source-dirs: pab diff --git a/MetaLamp/lending-pool/src/MyModule.hs b/MetaLamp/lending-pool/src/MyModule.hs deleted file mode 100644 index 2a1505371..000000000 --- a/MetaLamp/lending-pool/src/MyModule.hs +++ /dev/null @@ -1,7 +0,0 @@ -module MyModule where - -hello :: String -hello = "hello" - -main :: IO () -main = putStrLn hello \ No newline at end of file From 67ba03495f9e0e2db5c6589e365c660009e10340 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 4 May 2021 18:10:51 +0700 Subject: [PATCH 010/169] fix contract errors --- .../src/Plutus/Contracts/LendingPool.hs | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index c79bc2383..363ee4dfc 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -156,64 +156,72 @@ instance Scripts.ScriptType AaveScript where type instance RedeemerType AaveScript = AaveAction type instance DatumType AaveScript = AaveDatum +{-# INLINABLE findOwnInput' #-} +findOwnInput' :: ScriptContext -> TxInInfo +findOwnInput' ctx = fromMaybe (error ()) (findOwnInput ctx) + +{-# INLINABLE valueWithin #-} +valueWithin :: TxInInfo -> Value +valueWithin = txOutValue . txInInfoResolved + {-# INLINABLE validateCreate #-} validateCreate :: Aave -> Coin -> [LendingPool] -> LendingPool - -> ValidatorCtx + -> ScriptContext -> Bool validateCreate Aave{..} c lps lp@LendingPool{..} ctx = - traceIfFalse "Aave coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) aaveProtocolInst == 1) && + traceIfFalse "Aave coin not present" (coinValueOf (valueWithin $ findOwnInput' ctx) aaveProtocolInst == 1) && notElem lp lps && Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ coin aaveProtocolInst 1) && (coinValueOf forged c == 1) && Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp aTokensNum) $ coin c 1) where - poolOutput :: TxOutInfo + poolOutput :: TxOut poolOutput = case [o | o <- getContinuingOutputs ctx, coinValueOf (txOutValue o) c == 1] of [o] -> o _ -> traceError "expected exactly one pool output" forged :: Value - forged = txInfoForge $ valCtxTxInfo ctx + forged = txInfoForge $ scriptContextTxInfo ctx aTokensNum :: Integer aTokensNum = coinValueOf forged aaveToken {-# INLINABLE validateCloseFactory #-} -validateCloseFactory :: Aave -> Coin -> [LendingPool] -> ValidatorCtx -> Bool +validateCloseFactory :: Aave -> Coin -> [LendingPool] -> ScriptContext -> Bool validateCloseFactory aa c lps ctx = - traceIfFalse "Aave coin not present" (coinValueOf (txInInfoValue $ findOwnInput ctx) aaC == 1) && + traceIfFalse "Aave coin not present" (coinValueOf (valueWithin $ findOwnInput' ctx) aaC == 1) && traceIfFalse "wrong forge value" (txInfoForge info == negate (coin c 1)) && traceIfFalse "factory output wrong" (Constraints.checkOwnOutputConstraint ctx $ OutputConstraint (Factory $ filter (/= fst lpLiquidity) lps) $ coin aaC 1) where info :: TxInfo - info = valCtxTxInfo ctx + info = scriptContextTxInfo ctx poolInput :: TxInInfo poolInput = case [ i | i <- txInfoInputs info - , coinValueOf (txInInfoValue i) c == 1 + , coinValueOf (valueWithin i) c == 1 ] of [i] -> i _ -> traceError "expected exactly one pool input" lpLiquidity :: (LendingPool, Integer) - lpLiquidity = case txInInfoWitness poolInput of - Nothing -> traceError "pool input witness missing" - Just (_, _, h) -> findPoolDatum info h + lpLiquidity = case txOutDatumHash . txInInfoResolved $ poolInput of + Nothing -> traceError "pool input witness missing" + Just h -> findPoolDatum info h aaC :: Coin aaC = aaveProtocolInst aa {-# INLINABLE validateClosePool #-} -validateClosePool :: Aave -> ValidatorCtx -> Bool +validateClosePool :: Aave -> ScriptContext -> Bool validateClosePool aa ctx = hasFactoryInput where info :: TxInfo - info = valCtxTxInfo ctx + info = scriptContextTxInfo ctx hasFactoryInput :: Bool hasFactoryInput = @@ -233,17 +241,17 @@ mkAaveValidator :: Aave -> Coin -> AaveDatum -> AaveAction - -> ValidatorCtx + -> ScriptContext -> Bool mkAaveValidator aa c (Factory lps) (Create lp) ctx = validateCreate aa c lps lp ctx mkAaveValidator aa c (Factory lps) Close ctx = validateCloseFactory aa c lps ctx mkAaveValidator aa _ (Pool _ _) Close ctx = validateClosePool aa ctx mkAaveValidator _ _ _ _ _ = False -validateLiquidityForging :: Aave -> TokenName -> PolicyCtx -> Bool +validateLiquidityForging :: Aave -> TokenName -> ScriptContext -> Bool validateLiquidityForging aa tn ctx = case [ i - | i <- txInfoInputs $ policyCtxTxInfo ctx - , let v = txInInfoValue i + | i <- txInfoInputs $ scriptContextTxInfo ctx + , let v = valueWithin i , (coinValueOf v aaC == 1) || (coinValueOf v lpC == 1) ] of @@ -274,7 +282,7 @@ aaveHash :: Aave -> Ledger.ValidatorHash aaveHash = Scripts.validatorHash . aaveScript aaveAddress :: Aave -> Ledger.Address -aaveAddress = ScriptAddress . aaveHash +aaveAddress = Ledger.scriptAddress . aaveScript aave :: CurrencySymbol -> CurrencySymbol -> Aave aave protocol token = Aave (Coin protocol aaveProtocolName) (Coin token aaveTokenName) @@ -379,9 +387,9 @@ close aa poolCoin = do logInfo $ "closed liquidity pool: " ++ show lp getAaveDatum :: TxOutTx -> Contract w s Text AaveDatum -getAaveDatum o = case txOutType $ txOutTxOut o of - PayToPubKey -> throwError "unexpected out type" - PayToScript h -> case Map.lookup h $ txData $ txOutTxTx o of +getAaveDatum o = case txOutDatumHash $ txOutTxOut o of + Nothing -> throwError "datumHash not found" + Just h -> case Map.lookup h $ txData $ txOutTxTx o of Nothing -> throwError "datum not found" Just (Datum e) -> case PlutusTx.fromData e of Nothing -> throwError "datum has wrong type" From 04bbfcd8b9fef42cab43fcffc149df7949ef550f Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 4 May 2021 18:42:25 +0700 Subject: [PATCH 011/169] fix pab server errors --- MetaLamp/lending-pool/pab/Main.hs | 281 ++++++------------ .../src/Plutus/Contracts/LendingPool.hs | 7 +- 2 files changed, 91 insertions(+), 197 deletions(-) diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index a0f682867..d9c53bc3e 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -9,239 +9,128 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE EmptyDataDecls #-} -{-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE RecordWildCards #-} - module Main ( main ) where -import Control.Monad (forM, forM_, void, when) -import Control.Monad.Freer (Eff, Member, reinterpret, type (~>)) -import Control.Monad.Freer.Extras.Log (LogMsg,logDebug) -import Control.Monad.IO.Class (MonadIO (..)) -import Data.Bifunctor (Bifunctor (first)) -import qualified Data.Map.Strict as Map -import qualified Data.Monoid as Monoid -import Data.Row -import qualified Data.Semigroup as Semigroup -import Data.Text (Text,pack) -import Data.Text.Extras (tshow) -import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) -import GHC.Generics (Generic) +import Control.Monad (forM, void) +import Control.Monad.Freer (Eff, Member, interpret, type (~>)) +import Control.Monad.Freer.Error (Error) +import Control.Monad.Freer.Extras.Log (LogMsg) +import Control.Monad.IO.Class (MonadIO (..)) +import Data.Aeson (FromJSON, Result (..), ToJSON, encode, fromJSON) +import qualified Data.Map.Strict as Map +import qualified Data.Monoid as Monoid +import qualified Data.Semigroup as Semigroup +import Data.Text (Text) +import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) +import GHC.Generics (Generic) +import Ledger.Ada (adaSymbol, adaToken) +import qualified Plutus.Contracts.Currency as Currency +import qualified Plutus.Contracts.LendingPool as Aave +import Plutus.PAB.Effects.Contract (ContractEffect (..)) +import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), type (.\\)) +import qualified Plutus.PAB.Effects.Contract.Builtin as Builtin +import Plutus.PAB.Monitoring.PABLogMsg (PABMultiAgentMsg) +import Plutus.PAB.Simulator (SimulatorEffectHandlers) +import qualified Plutus.PAB.Simulator as Simulator +import Plutus.PAB.Types (PABError (..)) +import qualified Plutus.PAB.Webserver.Server as PAB.Server +import Prelude hiding (init) +import Wallet.Emulator.Types (Wallet (..)) +import Control.Monad (forM_, when) +import qualified Data.Semigroup as Semigroup import Ledger -import Ledger.Ada import Ledger.Constraints -import Ledger.Value as Value -import Playground.Schema (endpointsToSchemas) -import Plutus.Contract - ( Contract, - tell, - awaitTxConfirmed, - ownPubKey, - submitTx ) -import qualified Plutus.Contracts.Currency as Currency -import qualified Plutus.Contracts.LendingPool as LP -import Plutus.PAB.Effects.Contract (ContractEffect (..), PABContract (..)) --- import Plutus.PAB.Effects.Contract.ContractTest (doContractInit, doContractUpdate) -import Plutus.PAB.Events.Contract (ContractPABRequest) -import Plutus.PAB.Events.ContractInstanceState (PartiallyDecodedResponse) -import Plutus.PAB.Monitoring.PABLogMsg (ContractEffectMsg (..)) -import Plutus.PAB.Simulator (SimulatorContractHandler, SimulatorEffectHandlers) -import qualified Plutus.PAB.Simulator as Simulator -import Plutus.PAB.Types (PABError (..)) -import qualified Plutus.PAB.Webserver.Server as PAB.Server -import Prelude hiding (init) -import Wallet.Emulator.Types (Wallet (..), walletPubKey) -import qualified Plutus.PAB.Events.Contract as C -import qualified Data.Aeson as JSON -import qualified Data.Aeson.Types as JSON -import Plutus.Contract.State (ContractRequest (..), ContractResponse (..)) -import qualified Plutus.Contract.State as ContractState -import Plutus.Contract.Schema (Event, Handlers, Input, Output) -import Plutus.Contract.Resumable (Response) -import qualified Plutus.PAB.Events.ContractInstanceState as C -import Control.Monad.Freer.Error (Error, throwError) +import Ledger.Value as Value +import Plutus.Contract hiding (when) +import qualified Plutus.Contracts.Currency as Currency +import Wallet.Emulator.Types (Wallet (..), walletPubKey) + +initContract :: Contract (Maybe (Semigroup.Last Currency.OneShotCurrency)) Currency.CurrencySchema Currency.CurrencyError () +initContract = do + ownPK <- pubKeyHash <$> ownPubKey + cur <- Currency.forgeContract ownPK [(tn, fromIntegral (length wallets) * amount) | tn <- tokenNames] + let cs = Currency.currencySymbol cur + v = mconcat [Value.singleton cs tn amount | tn <- tokenNames] + forM_ wallets $ \w -> do + let pkh = pubKeyHash $ walletPubKey w + when (pkh /= ownPK) $ do + tx <- submitTx $ mustPayToPubKey pkh v + awaitTxConfirmed $ txId tx + tell $ Just $ Semigroup.Last cur + where + amount = 1000000 + +wallets :: [Wallet] +wallets = [Wallet i | i <- [1 .. 4]] + +tokenNames :: [TokenName] +tokenNames = ["A", "B", "C", "D"] + main :: IO () main = void $ Simulator.runSimulationWith handlers $ do - Simulator.logString @AavePabServer "Starting AavePabServer PAB webserver on port 8080. Press enter to exit." + Simulator.logString @(Builtin AaveContracts) "Starting Aave PAB webserver on port 8080. Press enter to exit." shutdown <- PAB.Server.startServerDebug cidInit <- Simulator.activateContract (Wallet 1) Init - cs <- flip Simulator.waitForState cidInit $ \json -> case JSON.fromJSON json of - JSON.Success (Just (Semigroup.Last cur)) -> Just $ Currency.currencySymbol cur + cs <- flip Simulator.waitForState cidInit $ \json -> case fromJSON json of + Success (Just (Semigroup.Last cur)) -> Just $ Currency.currencySymbol cur _ -> Nothing _ <- Simulator.waitUntilFinished cidInit - Simulator.logString @AavePabServer $ "Initialization finished. Minted: " ++ show cs - let coins = Map.fromList [(tn, LP.Coin cs tn) | tn <- tokenNames] - ada = LP.Coin adaSymbol adaToken + Simulator.logString @(Builtin AaveContracts) $ "Initialization finished. Minted: " ++ show cs + cidStart <- Simulator.activateContract (Wallet 1) AaveStart - us <- flip Simulator.waitForState cidStart $ \json -> case (JSON.fromJSON json :: JSON.Result (Monoid.Last (Either Text LP.Aave))) of - JSON.Success (Monoid.Last (Just (Right us))) -> Just us + us <- flip Simulator.waitForState cidStart $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.Aave))) of + Success (Monoid.Last (Just (Right us))) -> Just us _ -> Nothing - Simulator.logString @AavePabServer $ "AavePabServer instance created: " ++ show us + Simulator.logString @(Builtin AaveContracts) $ "Aave instance created: " ++ show us cids <- fmap Map.fromList $ forM wallets $ \w -> do cid <- Simulator.activateContract w $ AaveUser us - Simulator.logString @AavePabServer $ "AavePabServer user contract started for " ++ show w + Simulator.logString @(Builtin AaveContracts) $ "Aave user contract started for " ++ show w return (w, cid) - let cp = 100000 :: Integer - Simulator.logString @AavePabServer $ "creating liquidity pool: " ++ show (JSON.encode cp) + let cp = 10000 :: Integer + Simulator.logString @(Builtin AaveContracts) $ "creating liquidity pool: " ++ show (encode cp) _ <- Simulator.callEndpointOnInstance (cids Map.! Wallet 2) "create" cp - flip Simulator.waitForState (cids Map.! Wallet 2) $ \json -> case (JSON.fromJSON json :: JSON.Result (Monoid.Last (Either Text LP.UserContractState))) of - JSON.Success (Monoid.Last (Just (Right LP.Created))) -> Just () + flip Simulator.waitForState (cids Map.! Wallet 2) $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right Aave.Created))) -> Just () _ -> Nothing - Simulator.logString @AavePabServer "liquidity pool created" + Simulator.logString @(Builtin AaveContracts) "liquidity pool created" _ <- liftIO getLine shutdown -data AavePabServer - data AaveContracts = Init | AaveStart - | AaveUser LP.Aave + | AaveUser Aave.Aave deriving (Eq, Ord, Show, Generic) - deriving anyclass (JSON.FromJSON, JSON.ToJSON) - -instance PABContract AavePabServer where - type ContractDef AavePabServer = AaveContracts - type State AavePabServer = PartiallyDecodedResponse ContractPABRequest - serialisableState _ = id + deriving anyclass (FromJSON, ToJSON) instance Pretty AaveContracts where pretty = viaShow handleAaveContract :: ( Member (Error PABError) effs - , Member (LogMsg ContractEffectMsg) effs + , Member (LogMsg (PABMultiAgentMsg (Builtin AaveContracts))) effs ) - => ContractEffect AavePabServer + => ContractEffect (Builtin AaveContracts) ~> Eff effs -handleAaveContract = \case - InitialState c -> case c of - Init -> doContractInit init - AaveStart -> doContractInit start - AaveUser us -> doContractInit $ userEndpoints us - UpdateContract c state p -> case c of - Init -> doContractUpdate init state p - AaveStart -> doContractUpdate start state p - AaveUser us -> doContractUpdate (userEndpoints us) state p - ExportSchema t -> case t of - Init -> pure $ endpointsToSchemas @Empty - AaveStart -> pure $ endpointsToSchemas @Empty - AaveUser _ -> pure $ endpointsToSchemas @Empty - -- TODO: - -- replace with (Marlowe.MarloweSchema .\\ BlockchainActions) - -- (needs some instances for the Marlowe types (MarloweParams, etc)) - where - init = first tshow initContract - start = first tshow LP.ownerEndpoint - userEndpoints = first tshow . LP.userEndpoints - -handlers :: SimulatorEffectHandlers AavePabServer -handlers = Simulator.mkSimulatorHandlers @AavePabServer [] mlw where - mlw :: SimulatorContractHandler AavePabServer - mlw = - Simulator.handleContractEffectMsg @AavePabServer - . reinterpret handleAaveContract - -initContract :: Contract (Maybe (Semigroup.Last Currency.Currency)) Currency.CurrencySchema Currency.CurrencyError () -initContract = do - ownPK <- pubKeyHash <$> ownPubKey - cur <- Currency.forgeContract ownPK [(tn, fromIntegral (length wallets) * amount) | tn <- tokenNames] - let cs = Currency.currencySymbol cur - v = mconcat [Value.singleton cs tn amount | tn <- tokenNames] - forM_ wallets $ \w -> do - let pkh = pubKeyHash $ walletPubKey w - when (pkh /= ownPK) $ do - tx <- submitTx $ mustPayToPubKey pkh v - awaitTxConfirmed $ txId tx - tell $ Just $ Semigroup.Last cur - where - amount = 1000000 - -wallets :: [Wallet] -wallets = [Wallet i | i <- [1 .. 4]] - -tokenNames :: [TokenName] -tokenNames = ["A", "B", "C", "D"] - -doContractInit :: - forall w schema effs. - ( Member (Error PABError) effs - , Forall (Output schema) JSON.ToJSON - , Forall (Input schema) JSON.ToJSON - , Monoid w - , JSON.ToJSON w - ) - => Contract w schema Text () - -> Eff effs (PartiallyDecodedResponse ContractPABRequest) -doContractInit contract = either throwError pure $ do - let value = ContractState.initialiseContract contract - fromString $ fmap (fmap C.unContractHandlerRequest) $ JSON.eitherDecode $ JSON.encode value - -doContractUpdate :: - forall w schema effs. - ( Member (Error PABError) effs - , AllUniqueLabels (Input schema) - , Forall (Input schema) JSON.FromJSON - , Forall (Input schema) JSON.ToJSON - , Forall (Output schema) JSON.ToJSON - , Member (LogMsg ContractEffectMsg) effs - , Monoid w - , JSON.ToJSON w - ) - => Contract w schema Text () - -> PartiallyDecodedResponse ContractPABRequest - -> Response C.ContractResponse - -> Eff effs (PartiallyDecodedResponse ContractPABRequest) -doContractUpdate contract oldState response = do - let C.PartiallyDecodedResponse{..} = oldState - oldState' <- traverse fromJSON newState - typedResp <- traverse (fromJSON . JSON.toJSON . C.ContractHandlersResponse) response - let conReq = ContractRequest{oldState = oldState', event = typedResp } - logDebug $ SendContractRequest (fmap JSON.toJSON conReq) - let response' = mkResponse $ ContractState.insertAndUpdateContract contract conReq - logDebug $ ReceiveContractResponse response' - pure response' - -fromString :: Either String a -> Either PABError a -fromString = first (ContractCommandError 0 . pack) - -mkResponse :: - forall w schema err. - ( Forall (Output schema) JSON.ToJSON - , Forall (Input schema) JSON.ToJSON - , JSON.ToJSON err - , JSON.ToJSON w - ) - => ContractResponse w err (Event schema) (Handlers schema) - -> PartiallyDecodedResponse ContractPABRequest -mkResponse ContractResponse{newState, hooks, logs, observableState, err} = - C.PartiallyDecodedResponse - { C.newState = fmap JSON.toJSON newState - , C.hooks = fmap (fmap (encodeRequest @schema)) hooks - , C.logs = logs - , C.observableState = JSON.toJSON observableState - , C.err = fmap JSON.toJSON err - } - -encodeRequest :: - forall schema. - ( Forall (Output schema) JSON.ToJSON - ) - => Handlers schema - -> ContractPABRequest -encodeRequest = either error C.unContractHandlerRequest . JSON.eitherDecode . JSON.encode - -fromJSON :: (Member (Error PABError) effs, JSON.FromJSON a) => JSON.Value -> Eff effs a -fromJSON = - either (throwError . OtherError . pack) pure - . JSON.parseEither JSON.parseJSON +handleAaveContract = Builtin.handleBuiltin getSchema getContract where + getSchema = \case + AaveUser _ -> Builtin.endpointsToSchemas @(Aave.AaveUserSchema .\\ BlockchainActions) + AaveStart -> Builtin.endpointsToSchemas @(Aave.AaveOwnerSchema .\\ BlockchainActions) + Init -> Builtin.endpointsToSchemas @Empty + getContract = \case + AaveUser us -> SomeBuiltin $ Aave.userEndpoints us + AaveStart -> SomeBuiltin Aave.ownerEndpoint + Init -> SomeBuiltin initContract + +handlers :: SimulatorEffectHandlers (Builtin AaveContracts) +handlers = + Simulator.mkSimulatorHandlers @(Builtin AaveContracts) [] -- [Init, AaveStart, AaveUser ???] + $ interpret handleAaveContract diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index 363ee4dfc..c1836e0dd 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -19,7 +19,7 @@ module Plutus.Contracts.LendingPool ( Coin (..) , coin, coinValueOf , Aave (..), aave - , AaveUserSchema, UserContractState (..) + , AaveUserSchema, AaveOwnerSchema, UserContractState (..) , start, create, close , ownerEndpoint, userEndpoints ) where @@ -53,6 +53,7 @@ aaveProtocolName = "Aave" aaveTokenName = "aToken" poolStateTokenName = "Pool State" +-- TODO use AssetClass instead of Coin -- | A pair consisting of a 'CurrencySymbol' and a 'TokenName'. -- Coins are the entities that can be swapped in the exchange. data Coin = Coin @@ -448,6 +449,10 @@ ownerEndpoint = do Left err -> Left err Right aa -> Right aa +type AaveOwnerSchema = + BlockchainActions + .\/ Endpoint "start" () + -- | Schema for the endpoints for users of Aave. type AaveUserSchema = BlockchainActions From faea23340ddea206363896951a8f79fd0c644f77 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 5 May 2021 14:44:28 +0700 Subject: [PATCH 012/169] change pab initialization --- MetaLamp/lending-pool/pab/Main.hs | 32 +++++++++---------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index d9c53bc3e..104fa750e 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -13,7 +13,7 @@ module Main ( main ) where -import Control.Monad (forM, void) +import Control.Monad ( forM, void, forM_, when ) import Control.Monad.Freer (Eff, Member, interpret, type (~>)) import Control.Monad.Freer.Error (Error) import Control.Monad.Freer.Extras.Log (LogMsg) @@ -21,12 +21,10 @@ import Control.Monad.IO.Class (MonadIO (..)) import Data.Aeson (FromJSON, Result (..), ToJSON, encode, fromJSON) import qualified Data.Map.Strict as Map import qualified Data.Monoid as Monoid -import qualified Data.Semigroup as Semigroup import Data.Text (Text) import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) import GHC.Generics (Generic) -import Ledger.Ada (adaSymbol, adaToken) -import qualified Plutus.Contracts.Currency as Currency +import Ledger.Ada (adaSymbol, adaToken, adaValueOf,lovelaceValueOf) import qualified Plutus.Contracts.LendingPool as Aave import Plutus.PAB.Effects.Contract (ContractEffect (..)) import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), type (.\\)) @@ -37,8 +35,6 @@ import qualified Plutus.PAB.Simulator as Simulator import Plutus.PAB.Types (PABError (..)) import qualified Plutus.PAB.Webserver.Server as PAB.Server import Prelude hiding (init) -import Wallet.Emulator.Types (Wallet (..)) -import Control.Monad (forM_, when) import qualified Data.Semigroup as Semigroup import Ledger import Ledger.Constraints @@ -50,46 +46,36 @@ import Wallet.Emulator.Types (Wallet (..), walletPubKey) initContract :: Contract (Maybe (Semigroup.Last Currency.OneShotCurrency)) Currency.CurrencySchema Currency.CurrencyError () initContract = do ownPK <- pubKeyHash <$> ownPubKey - cur <- Currency.forgeContract ownPK [(tn, fromIntegral (length wallets) * amount) | tn <- tokenNames] - let cs = Currency.currencySymbol cur - v = mconcat [Value.singleton cs tn amount | tn <- tokenNames] + let v = lovelaceValueOf amount forM_ wallets $ \w -> do let pkh = pubKeyHash $ walletPubKey w when (pkh /= ownPK) $ do tx <- submitTx $ mustPayToPubKey pkh v awaitTxConfirmed $ txId tx - tell $ Just $ Semigroup.Last cur where amount = 1000000 wallets :: [Wallet] wallets = [Wallet i | i <- [1 .. 4]] -tokenNames :: [TokenName] -tokenNames = ["A", "B", "C", "D"] - - main :: IO () main = void $ Simulator.runSimulationWith handlers $ do Simulator.logString @(Builtin AaveContracts) "Starting Aave PAB webserver on port 8080. Press enter to exit." shutdown <- PAB.Server.startServerDebug cidInit <- Simulator.activateContract (Wallet 1) Init - cs <- flip Simulator.waitForState cidInit $ \json -> case fromJSON json of - Success (Just (Semigroup.Last cur)) -> Just $ Currency.currencySymbol cur - _ -> Nothing _ <- Simulator.waitUntilFinished cidInit - Simulator.logString @(Builtin AaveContracts) $ "Initialization finished. Minted: " ++ show cs - + Simulator.logString @(Builtin AaveContracts) "Initialization finished." + cidStart <- Simulator.activateContract (Wallet 1) AaveStart - us <- flip Simulator.waitForState cidStart $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.Aave))) of - Success (Monoid.Last (Just (Right us))) -> Just us + aa <- flip Simulator.waitForState cidStart $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.Aave))) of + Success (Monoid.Last (Just (Right aa))) -> Just aa _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Aave instance created: " ++ show us + Simulator.logString @(Builtin AaveContracts) $ "Aave instance created: " ++ show aa cids <- fmap Map.fromList $ forM wallets $ \w -> do - cid <- Simulator.activateContract w $ AaveUser us + cid <- Simulator.activateContract w $ AaveUser aa Simulator.logString @(Builtin AaveContracts) $ "Aave user contract started for " ++ show w return (w, cid) From 4a0bec64ac0e534ccf10205de2aa6e845f94e548 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 5 May 2021 15:26:45 +0700 Subject: [PATCH 013/169] use asset class instead of coin --- .../src/Plutus/Contracts/LendingPool.hs | 141 ++++++------------ 1 file changed, 43 insertions(+), 98 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index c1836e0dd..b6a6d5197 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -15,9 +15,9 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} +{-# LANGUAGE StandaloneDeriving #-} module Plutus.Contracts.LendingPool - ( Coin (..) - , coin, coinValueOf + ( AssetClass (..) , Aave (..), aave , AaveUserSchema, AaveOwnerSchema, UserContractState (..) , start, create, close @@ -53,61 +53,10 @@ aaveProtocolName = "Aave" aaveTokenName = "aToken" poolStateTokenName = "Pool State" --- TODO use AssetClass instead of Coin --- | A pair consisting of a 'CurrencySymbol' and a 'TokenName'. --- Coins are the entities that can be swapped in the exchange. -data Coin = Coin - { cCurrency :: CurrencySymbol - , cToken :: TokenName - } deriving (Show, Generic, ToJSON, FromJSON, ToSchema) - -PlutusTx.unstableMakeIsData ''Coin -PlutusTx.makeLift ''Coin - -instance Eq Coin where - {-# INLINABLE (==) #-} - c == d = cCurrency c == cCurrency d && cToken c == cToken d - -instance Prelude.Eq Coin where - (==) = (==) - -{-# INLINABLE compareCoins #-} -compareCoins :: Coin -> Coin -> Ordering -compareCoins c d = case compare (cCurrency c) (cCurrency d) of - LT -> LT - GT -> GT - EQ -> compare (cToken c) (cToken d) - -instance Prelude.Ord Coin where - compare = compareCoins - -{-# INLINABLE coinLT #-} -coinLT :: Coin -> Coin -> Bool -coinLT c d = case compareCoins c d of - LT -> True - _ -> False - -{-# INLINABLE coin #-} --- | @'coin' c n@ denotes the value given by @n@ units of @'Coin'@ @c@. -coin :: Coin -- ^ The 'Coin'. - -> Integer -- ^ The desired number coins. - -> Value -- ^ The 'Value' consisting of the given number of units of the given 'Coin'. -coin Coin{..} = Value.singleton cCurrency cToken - -{-# INLINABLE coinValueOf #-} --- | Calculates how many units of the specified 'Coin' are contained in the --- given 'Value'. -coinValueOf :: Value -- ^ The 'Value' to inspect. - -> Coin -- ^ The 'Coin' to look for. - -> Integer -- ^ The number of units of the given 'Coin' contained in the given 'Value'. -coinValueOf v Coin{..} = valueOf v cCurrency cToken - -{-# INLINABLE hashCoin #-} -hashCoin :: Coin -> ByteString -hashCoin Coin{..} = sha2_256 $ concatenate (unCurrencySymbol cCurrency) (unTokenName cToken) +deriving anyclass instance ToSchema AssetClass data LendingPool = LendingPool - { lpCoin :: Coin, + { lpCoin :: AssetClass, lpIssuer :: PubKeyHash } deriving stock (Show, Generic) @@ -120,13 +69,9 @@ instance Eq LendingPool where {-# INLINABLE (==) #-} x == y = lpCoin x == lpCoin y && lpIssuer x == lpIssuer y -{-# INLINABLE hashLendingPool #-} -hashLendingPool :: LendingPool -> ByteString -hashLendingPool LendingPool{..} = sha2_256 $ hashCoin lpCoin <> getPubKeyHash lpIssuer - data Aave = Aave - { aaveProtocolInst :: Coin, - aaveToken :: Coin + { aaveProtocolInst :: AssetClass, + aaveToken :: AssetClass } deriving stock (Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) @@ -167,20 +112,20 @@ valueWithin = txOutValue . txInInfoResolved {-# INLINABLE validateCreate #-} validateCreate :: Aave - -> Coin + -> AssetClass -> [LendingPool] -> LendingPool -> ScriptContext -> Bool validateCreate Aave{..} c lps lp@LendingPool{..} ctx = - traceIfFalse "Aave coin not present" (coinValueOf (valueWithin $ findOwnInput' ctx) aaveProtocolInst == 1) && + traceIfFalse "Aave assetClassValue not present" (assetClassValueOf (valueWithin $ findOwnInput' ctx) aaveProtocolInst == 1) && notElem lp lps && - Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ coin aaveProtocolInst 1) && - (coinValueOf forged c == 1) && - Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp aTokensNum) $ coin c 1) + Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ assetClassValue aaveProtocolInst 1) && + (assetClassValueOf forged c == 1) && + Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp aTokensNum) $ assetClassValue c 1) where poolOutput :: TxOut - poolOutput = case [o | o <- getContinuingOutputs ctx, coinValueOf (txOutValue o) c == 1] of + poolOutput = case [o | o <- getContinuingOutputs ctx, assetClassValueOf (txOutValue o) c == 1] of [o] -> o _ -> traceError "expected exactly one pool output" @@ -188,15 +133,15 @@ validateCreate Aave{..} c lps lp@LendingPool{..} ctx = forged = txInfoForge $ scriptContextTxInfo ctx aTokensNum :: Integer - aTokensNum = coinValueOf forged aaveToken + aTokensNum = assetClassValueOf forged aaveToken {-# INLINABLE validateCloseFactory #-} -validateCloseFactory :: Aave -> Coin -> [LendingPool] -> ScriptContext -> Bool +validateCloseFactory :: Aave -> AssetClass -> [LendingPool] -> ScriptContext -> Bool validateCloseFactory aa c lps ctx = - traceIfFalse "Aave coin not present" (coinValueOf (valueWithin $ findOwnInput' ctx) aaC == 1) && - traceIfFalse "wrong forge value" (txInfoForge info == negate (coin c 1)) && + traceIfFalse "Aave assetClassValue not present" (assetClassValueOf (valueWithin $ findOwnInput' ctx) aaC == 1) && + traceIfFalse "wrong forge value" (txInfoForge info == negate (assetClassValue c 1)) && traceIfFalse "factory output wrong" - (Constraints.checkOwnOutputConstraint ctx $ OutputConstraint (Factory $ filter (/= fst lpLiquidity) lps) $ coin aaC 1) + (Constraints.checkOwnOutputConstraint ctx $ OutputConstraint (Factory $ filter (/= fst lpLiquidity) lps) $ assetClassValue aaC 1) where info :: TxInfo info = scriptContextTxInfo ctx @@ -204,7 +149,7 @@ validateCloseFactory aa c lps ctx = poolInput :: TxInInfo poolInput = case [ i | i <- txInfoInputs info - , coinValueOf (valueWithin i) c == 1 + , assetClassValueOf (valueWithin i) c == 1 ] of [i] -> i _ -> traceError "expected exactly one pool input" @@ -214,7 +159,7 @@ validateCloseFactory aa c lps ctx = Nothing -> traceError "pool input witness missing" Just h -> findPoolDatum info h - aaC :: Coin + aaC :: AssetClass aaC = aaveProtocolInst aa {-# INLINABLE validateClosePool #-} @@ -227,7 +172,7 @@ validateClosePool aa ctx = hasFactoryInput hasFactoryInput :: Bool hasFactoryInput = traceIfFalse "Aave factory input expected" $ - coinValueOf (valueSpent info) (aaveProtocolInst aa) == 1 + assetClassValueOf (valueSpent info) (aaveProtocolInst aa) == 1 {-# INLINABLE findPoolDatum #-} @@ -239,7 +184,7 @@ findPoolDatum info h = case findDatum h info of _ -> traceError "pool input datum not found" mkAaveValidator :: Aave - -> Coin + -> AssetClass -> AaveDatum -> AaveAction -> ScriptContext @@ -253,16 +198,16 @@ validateLiquidityForging :: Aave -> TokenName -> ScriptContext -> Bool validateLiquidityForging aa tn ctx = case [ i | i <- txInfoInputs $ scriptContextTxInfo ctx , let v = valueWithin i - , (coinValueOf v aaC == 1) || - (coinValueOf v lpC == 1) + , (assetClassValueOf v aaC == 1) || + (assetClassValueOf v lpC == 1) ] of [_] -> True [_, _] -> True _ -> traceError "pool state forging without Aave input" where - aaC, lpC :: Coin + aaC, lpC :: AssetClass aaC = aaveProtocolInst aa - lpC = Coin (ownCurrencySymbol ctx) tn + lpC = assetClass (ownCurrencySymbol ctx) tn aaveInstance :: Aave -> Scripts.ScriptInstance AaveScript aaveInstance aa = Scripts.validator @AaveScript @@ -271,7 +216,7 @@ aaveInstance aa = Scripts.validator @AaveScript `PlutusTx.applyCode` PlutusTx.liftCode c) $$(PlutusTx.compile [|| wrap ||]) where - c :: Coin + c :: AssetClass c = poolStateCoin aa wrap = Scripts.wrapValidator @AaveDatum @AaveAction @@ -286,7 +231,7 @@ aaveAddress :: Aave -> Ledger.Address aaveAddress = Ledger.scriptAddress . aaveScript aave :: CurrencySymbol -> CurrencySymbol -> Aave -aave protocol token = Aave (Coin protocol aaveProtocolName) (Coin token aaveTokenName) +aave protocol token = Aave (assetClass protocol aaveProtocolName) (assetClass token aaveTokenName) liquidityPolicy :: Aave -> MonetaryPolicy liquidityPolicy aa = mkMonetaryPolicyScript $ @@ -297,8 +242,8 @@ liquidityPolicy aa = mkMonetaryPolicyScript $ liquidityCurrency :: Aave -> CurrencySymbol liquidityCurrency = scriptCurrencySymbol . liquidityPolicy -poolStateCoin :: Aave -> Coin -poolStateCoin = flip Coin poolStateTokenName . liquidityCurrency +poolStateCoin :: Aave -> AssetClass +poolStateCoin = flip assetClass poolStateTokenName . liquidityCurrency -- | Creates a Aave "factory". This factory will keep track of the existing liquidity pools and enforce that there will be at most one liquidity pool -- for any pair of tokens at any given time. @@ -311,11 +256,11 @@ start = do token <- fmap Currency.currencySymbol $ mapError (pack . show @Currency.CurrencyError) $ Currency.forgeContract pkh [(aaveTokenName, 0)] - let c = Coin cs aaveProtocolName - let tokenCoin = Coin token aaveTokenName + let c = assetClass cs aaveProtocolName + let tokenCoin = assetClass token aaveTokenName aa = aave cs token inst = aaveInstance aa - tx = mustPayToTheScript (Factory []) $ coin c 1 <> coin tokenCoin 0 + tx = mustPayToTheScript (Factory []) $ assetClassValue c 1 <> assetClassValue tokenCoin 0 ledgerTx <- submitTxConstraints inst tx void $ awaitTxConfirmed $ txId ledgerTx @@ -330,15 +275,15 @@ create aa aTokensNum = do mapError (pack . show @Currency.CurrencyError) $ Currency.forgeContract pkh [(poolStateTokenName, 1)] (oref, o, lps) <- findAaveFactory aa - let c = Coin cs poolStateTokenName + let c = assetClass cs poolStateTokenName let lp = LendingPool c pkh let aaInst = aaveInstance aa aaScript = aaveScript aa aaDat1 = Factory $ lp : lps aaDat2 = Pool lp aTokensNum psC = poolStateCoin aa - aaVal = coin (aaveProtocolInst aa) 1 - lpVal = coin psC 1 <> lovelaceValueOf aTokensNum + aaVal = assetClassValue (aaveProtocolInst aa) 1 + lpVal = assetClassValue psC 1 <> lovelaceValueOf aTokensNum lookups = Constraints.scriptInstanceLookups aaInst <> Constraints.otherScript aaScript <> @@ -347,7 +292,7 @@ create aa aTokensNum = do tx = Constraints.mustPayToTheScript aaDat1 aaVal <> Constraints.mustPayToTheScript aaDat2 lpVal <> - Constraints.mustForgeValue (coin psC 1 <> coin (aaveToken aa) aTokensNum) <> + Constraints.mustForgeValue (assetClassValue psC 1 <> assetClassValue (aaveToken aa) aTokensNum) <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ Create lp) ledgerTx <- submitTxConstraintsWith lookups tx @@ -356,7 +301,7 @@ create aa aTokensNum = do logInfo $ "created liquidity pool: " ++ show lp -- | Closes a liquidity pool by burning all remaining liquidity tokens in exchange for all liquidity remaining in the pool. -close :: HasBlockchainActions s => Aave -> Coin -> Contract w s Text () +close :: HasBlockchainActions s => Aave -> AssetClass -> Contract w s Text () close aa poolCoin = do pkh <- pubKeyHash <$> ownPubKey ((oref1, o1, lps), (oref2, o2, lp, liquidity)) <- findAaveFactoryAndPool aa $ LendingPool poolCoin pkh @@ -366,8 +311,8 @@ close aa poolCoin = do aaDat = Factory $ filter (/= lp) lps aaC = aaveProtocolInst aa psC = poolStateCoin aa - aaVal = coin aaC 1 - psVal = coin psC 1 + aaVal = assetClassValue aaC 1 + psVal = assetClassValue psC 1 redeemer = Redeemer $ PlutusTx.toData Close lookups = Constraints.scriptInstanceLookups aaInst <> @@ -396,12 +341,12 @@ getAaveDatum o = case txOutDatumHash $ txOutTxOut o of Nothing -> throwError "datum has wrong type" Just d -> return d -findAaveInstance :: HasBlockchainActions s => Aave -> Coin -> (AaveDatum -> Maybe a) -> Contract w s Text (TxOutRef, TxOutTx, a) +findAaveInstance :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text (TxOutRef, TxOutTx, a) findAaveInstance aa c f = do let addr = aaveAddress aa - logInfo @String $ printf "looking for Aave instance at address %s containing coin %s " (show addr) (show c) + logInfo @String $ printf "looking for Aave instance at address %s containing assetClassValue %s " (show addr) (show c) utxos <- utxoAt addr - go [x | x@(_, o) <- Map.toList utxos, coinValueOf (txOutValue $ txOutTxOut o) c == 1] + go [x | x@(_, o) <- Map.toList utxos, assetClassValueOf (txOutValue $ txOutTxOut o) c == 1] where go [] = throwError "Aave instance not found" go ((oref, o) : xs) = do @@ -457,7 +402,7 @@ type AaveOwnerSchema = type AaveUserSchema = BlockchainActions .\/ Endpoint "create" Integer - .\/ Endpoint "close" Coin + .\/ Endpoint "close" AssetClass .\/ Endpoint "stop" () -- | Type of the Aave user contract state. From 7c36b2fc1057bae406255cac4d64cd2bc23f8f05 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 5 May 2021 18:59:52 +0700 Subject: [PATCH 014/169] wip forge aave tokens for a pool --- .../src/Plutus/Contracts/LendingPool.hs | 115 +++++++----------- 1 file changed, 47 insertions(+), 68 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index b6a6d5197..ed14266e2 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -48,16 +48,14 @@ import qualified Prelude import Text.Printf (printf) import Plutus.V1.Ledger.Ada ( lovelaceValueOf ) -aaveProtocolName, aaveTokenName, poolStateTokenName :: TokenName +aaveProtocolName, aaveTokenName :: TokenName aaveProtocolName = "Aave" aaveTokenName = "aToken" -poolStateTokenName = "Pool State" deriving anyclass instance ToSchema AssetClass -data LendingPool = LendingPool - { lpCoin :: AssetClass, - lpIssuer :: PubKeyHash +newtype LendingPool = LendingPool + { lpToken :: AssetClass } deriving stock (Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) @@ -67,11 +65,10 @@ PlutusTx.makeLift ''LendingPool instance Eq LendingPool where {-# INLINABLE (==) #-} - x == y = lpCoin x == lpCoin y && lpIssuer x == lpIssuer y + x == y = lpToken x == lpToken y -data Aave = Aave - { aaveProtocolInst :: AssetClass, - aaveToken :: AssetClass +newtype Aave = Aave + { aaveProtocolInst :: AssetClass } deriving stock (Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) @@ -112,20 +109,19 @@ valueWithin = txOutValue . txInInfoResolved {-# INLINABLE validateCreate #-} validateCreate :: Aave - -> AssetClass -> [LendingPool] -> LendingPool -> ScriptContext -> Bool -validateCreate Aave{..} c lps lp@LendingPool{..} ctx = +validateCreate Aave{..} lps lp@LendingPool{..} ctx = traceIfFalse "Aave assetClassValue not present" (assetClassValueOf (valueWithin $ findOwnInput' ctx) aaveProtocolInst == 1) && notElem lp lps && Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ assetClassValue aaveProtocolInst 1) && - (assetClassValueOf forged c == 1) && - Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp aTokensNum) $ assetClassValue c 1) + (assetClassValueOf forged lpToken == aTokensNum) && + Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp aTokensNum) $ assetClassValue lpToken aTokensNum) where poolOutput :: TxOut - poolOutput = case [o | o <- getContinuingOutputs ctx, assetClassValueOf (txOutValue o) c == 1] of + poolOutput = case [o | o <- getContinuingOutputs ctx, assetClassValueOf (txOutValue o) lpToken == 1] of [o] -> o _ -> traceError "expected exactly one pool output" @@ -133,31 +129,31 @@ validateCreate Aave{..} c lps lp@LendingPool{..} ctx = forged = txInfoForge $ scriptContextTxInfo ctx aTokensNum :: Integer - aTokensNum = assetClassValueOf forged aaveToken + aTokensNum = assetClassValueOf forged lpToken {-# INLINABLE validateCloseFactory #-} -validateCloseFactory :: Aave -> AssetClass -> [LendingPool] -> ScriptContext -> Bool -validateCloseFactory aa c lps ctx = - traceIfFalse "Aave assetClassValue not present" (assetClassValueOf (valueWithin $ findOwnInput' ctx) aaC == 1) && - traceIfFalse "wrong forge value" (txInfoForge info == negate (assetClassValue c 1)) && - traceIfFalse "factory output wrong" - (Constraints.checkOwnOutputConstraint ctx $ OutputConstraint (Factory $ filter (/= fst lpLiquidity) lps) $ assetClassValue aaC 1) +validateCloseFactory :: Aave -> [LendingPool] -> ScriptContext -> Bool +validateCloseFactory aa lps ctx = + traceIfFalse "Aave assetClassValue not present" (assetClassValueOf (valueWithin $ findOwnInput' ctx) aaC == 1) + -- traceIfFalse "wrong forge value" (txInfoForge info == negate (assetClassValue c 1)) && + -- traceIfFalse "factory output wrong" + -- (Constraints.checkOwnOutputConstraint ctx $ OutputConstraint (Factory $ filter (/= fst lpLiquidity) lps) $ assetClassValue aaC 1) where info :: TxInfo info = scriptContextTxInfo ctx - poolInput :: TxInInfo - poolInput = case [ i - | i <- txInfoInputs info - , assetClassValueOf (valueWithin i) c == 1 - ] of - [i] -> i - _ -> traceError "expected exactly one pool input" + -- poolInput :: TxInInfo + -- poolInput = case [ i + -- | i <- txInfoInputs info + -- , assetClassValueOf (valueWithin i) c == 1 + -- ] of + -- [i] -> i + -- _ -> traceError "expected exactly one pool input" - lpLiquidity :: (LendingPool, Integer) - lpLiquidity = case txOutDatumHash . txInInfoResolved $ poolInput of - Nothing -> traceError "pool input witness missing" - Just h -> findPoolDatum info h + -- lpLiquidity :: (LendingPool, Integer) + -- lpLiquidity = case txOutDatumHash . txInInfoResolved $ poolInput of + -- Nothing -> traceError "pool input witness missing" + -- Just h -> findPoolDatum info h aaC :: AssetClass aaC = aaveProtocolInst aa @@ -184,15 +180,14 @@ findPoolDatum info h = case findDatum h info of _ -> traceError "pool input datum not found" mkAaveValidator :: Aave - -> AssetClass -> AaveDatum -> AaveAction -> ScriptContext -> Bool -mkAaveValidator aa c (Factory lps) (Create lp) ctx = validateCreate aa c lps lp ctx -mkAaveValidator aa c (Factory lps) Close ctx = validateCloseFactory aa c lps ctx -mkAaveValidator aa _ (Pool _ _) Close ctx = validateClosePool aa ctx -mkAaveValidator _ _ _ _ _ = False +mkAaveValidator aa (Factory lps) (Create lp) ctx = validateCreate aa lps lp ctx +mkAaveValidator aa (Factory lps) Close ctx = validateCloseFactory aa lps ctx +mkAaveValidator aa (Pool _ _) Close ctx = validateClosePool aa ctx +mkAaveValidator _ _ _ _ = False validateLiquidityForging :: Aave -> TokenName -> ScriptContext -> Bool validateLiquidityForging aa tn ctx = case [ i @@ -212,13 +207,9 @@ validateLiquidityForging aa tn ctx = case [ i aaveInstance :: Aave -> Scripts.ScriptInstance AaveScript aaveInstance aa = Scripts.validator @AaveScript ($$(PlutusTx.compile [|| mkAaveValidator ||]) - `PlutusTx.applyCode` PlutusTx.liftCode aa - `PlutusTx.applyCode` PlutusTx.liftCode c) + `PlutusTx.applyCode` PlutusTx.liftCode aa) $$(PlutusTx.compile [|| wrap ||]) where - c :: AssetClass - c = poolStateCoin aa - wrap = Scripts.wrapValidator @AaveDatum @AaveAction aaveScript :: Aave -> Validator @@ -230,20 +221,14 @@ aaveHash = Scripts.validatorHash . aaveScript aaveAddress :: Aave -> Ledger.Address aaveAddress = Ledger.scriptAddress . aaveScript -aave :: CurrencySymbol -> CurrencySymbol -> Aave -aave protocol token = Aave (assetClass protocol aaveProtocolName) (assetClass token aaveTokenName) +aave :: CurrencySymbol -> Aave +aave protocol = Aave (assetClass protocol aaveProtocolName) liquidityPolicy :: Aave -> MonetaryPolicy liquidityPolicy aa = mkMonetaryPolicyScript $ $$(PlutusTx.compile [|| \a t -> Scripts.wrapMonetaryPolicy (validateLiquidityForging a t) ||]) `PlutusTx.applyCode` PlutusTx.liftCode aa - `PlutusTx.applyCode` PlutusTx.liftCode poolStateTokenName - -liquidityCurrency :: Aave -> CurrencySymbol -liquidityCurrency = scriptCurrencySymbol . liquidityPolicy - -poolStateCoin :: Aave -> AssetClass -poolStateCoin = flip assetClass poolStateTokenName . liquidityCurrency + `PlutusTx.applyCode` PlutusTx.liftCode aaveTokenName -- | Creates a Aave "factory". This factory will keep track of the existing liquidity pools and enforce that there will be at most one liquidity pool -- for any pair of tokens at any given time. @@ -253,14 +238,10 @@ start = do cs <- fmap Currency.currencySymbol $ mapError (pack . show @Currency.CurrencyError) $ Currency.forgeContract pkh [(aaveProtocolName, 1)] - token <- fmap Currency.currencySymbol $ - mapError (pack . show @Currency.CurrencyError) $ - Currency.forgeContract pkh [(aaveTokenName, 0)] let c = assetClass cs aaveProtocolName - let tokenCoin = assetClass token aaveTokenName - aa = aave cs token + let aa = aave cs inst = aaveInstance aa - tx = mustPayToTheScript (Factory []) $ assetClassValue c 1 <> assetClassValue tokenCoin 0 + tx = mustPayToTheScript (Factory []) $ assetClassValue c 1 ledgerTx <- submitTxConstraints inst tx void $ awaitTxConfirmed $ txId ledgerTx @@ -273,17 +254,16 @@ create aa aTokensNum = do pkh <- pubKeyHash <$> ownPubKey cs <- fmap Currency.currencySymbol $ mapError (pack . show @Currency.CurrencyError) $ - Currency.forgeContract pkh [(poolStateTokenName, 1)] + Currency.forgeContract pkh [(aaveTokenName, aTokensNum)] (oref, o, lps) <- findAaveFactory aa - let c = assetClass cs poolStateTokenName - let lp = LendingPool c pkh + let c = assetClass cs aaveTokenName + let lp = LendingPool c let aaInst = aaveInstance aa aaScript = aaveScript aa aaDat1 = Factory $ lp : lps aaDat2 = Pool lp aTokensNum - psC = poolStateCoin aa aaVal = assetClassValue (aaveProtocolInst aa) 1 - lpVal = assetClassValue psC 1 <> lovelaceValueOf aTokensNum + lpVal = lovelaceValueOf aTokensNum lookups = Constraints.scriptInstanceLookups aaInst <> Constraints.otherScript aaScript <> @@ -292,7 +272,7 @@ create aa aTokensNum = do tx = Constraints.mustPayToTheScript aaDat1 aaVal <> Constraints.mustPayToTheScript aaDat2 lpVal <> - Constraints.mustForgeValue (assetClassValue psC 1 <> assetClassValue (aaveToken aa) aTokensNum) <> + Constraints.mustForgeValue (assetClassValue c aTokensNum) <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ Create lp) ledgerTx <- submitTxConstraintsWith lookups tx @@ -300,19 +280,18 @@ create aa aTokensNum = do logInfo $ "created liquidity pool: " ++ show lp +-- TODO fix close and validateClose -- | Closes a liquidity pool by burning all remaining liquidity tokens in exchange for all liquidity remaining in the pool. close :: HasBlockchainActions s => Aave -> AssetClass -> Contract w s Text () close aa poolCoin = do pkh <- pubKeyHash <$> ownPubKey - ((oref1, o1, lps), (oref2, o2, lp, liquidity)) <- findAaveFactoryAndPool aa $ LendingPool poolCoin pkh - pkh <- pubKeyHash <$> ownPubKey + ((oref1, o1, lps), (oref2, o2, lp, liquidity)) <- findAaveFactoryAndPool aa $ LendingPool poolCoin let aaInst = aaveInstance aa aaScript = aaveScript aa aaDat = Factory $ filter (/= lp) lps aaC = aaveProtocolInst aa - psC = poolStateCoin aa aaVal = assetClassValue aaC 1 - psVal = assetClassValue psC 1 + psVal = assetClassValue poolCoin 1 redeemer = Redeemer $ PlutusTx.toData Close lookups = Constraints.scriptInstanceLookups aaInst <> @@ -363,7 +342,7 @@ findAaveFactory aa@Aave{..} = findAaveInstance aa aaveProtocolInst $ \case Pool _ _ -> Nothing findAavePool :: HasBlockchainActions s => Aave -> LendingPool -> Contract w s Text (TxOutRef, TxOutTx, Integer) -findAavePool aa lp = findAaveInstance aa (poolStateCoin aa) $ \case +findAavePool aa lp = findAaveInstance aa (lpToken lp) $ \case Pool lp' l | lp == lp' -> Just l _ -> Nothing From 1de0a01359ceed0b0d85346baea80560ab962bac Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 7 May 2021 13:49:50 +0700 Subject: [PATCH 015/169] rm close endpoints --- .../src/Plutus/Contracts/LendingPool.hs | 98 +------------------ 1 file changed, 4 insertions(+), 94 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index ed14266e2..c6c5d0d8f 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -20,7 +20,7 @@ module Plutus.Contracts.LendingPool ( AssetClass (..) , Aave (..), aave , AaveUserSchema, AaveOwnerSchema, UserContractState (..) - , start, create, close + , start, create , ownerEndpoint, userEndpoints ) where @@ -80,7 +80,7 @@ instance Prelude.Eq Aave where instance Prelude.Ord Aave where compare u v = Prelude.compare (aaveProtocolInst u) (aaveProtocolInst v) -data AaveAction = Create LendingPool | Close +data AaveAction = Create LendingPool deriving Show PlutusTx.unstableMakeIsData ''AaveAction @@ -131,46 +131,6 @@ validateCreate Aave{..} lps lp@LendingPool{..} ctx = aTokensNum :: Integer aTokensNum = assetClassValueOf forged lpToken -{-# INLINABLE validateCloseFactory #-} -validateCloseFactory :: Aave -> [LendingPool] -> ScriptContext -> Bool -validateCloseFactory aa lps ctx = - traceIfFalse "Aave assetClassValue not present" (assetClassValueOf (valueWithin $ findOwnInput' ctx) aaC == 1) - -- traceIfFalse "wrong forge value" (txInfoForge info == negate (assetClassValue c 1)) && - -- traceIfFalse "factory output wrong" - -- (Constraints.checkOwnOutputConstraint ctx $ OutputConstraint (Factory $ filter (/= fst lpLiquidity) lps) $ assetClassValue aaC 1) - where - info :: TxInfo - info = scriptContextTxInfo ctx - - -- poolInput :: TxInInfo - -- poolInput = case [ i - -- | i <- txInfoInputs info - -- , assetClassValueOf (valueWithin i) c == 1 - -- ] of - -- [i] -> i - -- _ -> traceError "expected exactly one pool input" - - -- lpLiquidity :: (LendingPool, Integer) - -- lpLiquidity = case txOutDatumHash . txInInfoResolved $ poolInput of - -- Nothing -> traceError "pool input witness missing" - -- Just h -> findPoolDatum info h - - aaC :: AssetClass - aaC = aaveProtocolInst aa - -{-# INLINABLE validateClosePool #-} -validateClosePool :: Aave -> ScriptContext -> Bool -validateClosePool aa ctx = hasFactoryInput - where - info :: TxInfo - info = scriptContextTxInfo ctx - - hasFactoryInput :: Bool - hasFactoryInput = - traceIfFalse "Aave factory input expected" $ - assetClassValueOf (valueSpent info) (aaveProtocolInst aa) == 1 - - {-# INLINABLE findPoolDatum #-} findPoolDatum :: TxInfo -> DatumHash -> (LendingPool, Integer) findPoolDatum info h = case findDatum h info of @@ -185,8 +145,6 @@ mkAaveValidator :: Aave -> ScriptContext -> Bool mkAaveValidator aa (Factory lps) (Create lp) ctx = validateCreate aa lps lp ctx -mkAaveValidator aa (Factory lps) Close ctx = validateCloseFactory aa lps ctx -mkAaveValidator aa (Pool _ _) Close ctx = validateClosePool aa ctx mkAaveValidator _ _ _ _ = False validateLiquidityForging :: Aave -> TokenName -> ScriptContext -> Bool @@ -280,37 +238,6 @@ create aa aTokensNum = do logInfo $ "created liquidity pool: " ++ show lp --- TODO fix close and validateClose --- | Closes a liquidity pool by burning all remaining liquidity tokens in exchange for all liquidity remaining in the pool. -close :: HasBlockchainActions s => Aave -> AssetClass -> Contract w s Text () -close aa poolCoin = do - pkh <- pubKeyHash <$> ownPubKey - ((oref1, o1, lps), (oref2, o2, lp, liquidity)) <- findAaveFactoryAndPool aa $ LendingPool poolCoin - let aaInst = aaveInstance aa - aaScript = aaveScript aa - aaDat = Factory $ filter (/= lp) lps - aaC = aaveProtocolInst aa - aaVal = assetClassValue aaC 1 - psVal = assetClassValue poolCoin 1 - redeemer = Redeemer $ PlutusTx.toData Close - - lookups = Constraints.scriptInstanceLookups aaInst <> - Constraints.otherScript aaScript <> - Constraints.monetaryPolicy (liquidityPolicy aa) <> - Constraints.ownPubKeyHash pkh <> - Constraints.unspentOutputs (Map.singleton oref1 o1 <> Map.singleton oref2 o2) - - tx = Constraints.mustPayToTheScript aaDat aaVal <> - Constraints.mustForgeValue (negate psVal) <> - Constraints.mustSpendScriptOutput oref1 redeemer <> - Constraints.mustSpendScriptOutput oref2 redeemer <> - Constraints.mustIncludeDatum (Datum $ PlutusTx.toData $ Pool lp liquidity) - - ledgerTx <- submitTxConstraintsWith lookups tx - void $ awaitTxConfirmed $ txId ledgerTx - - logInfo $ "closed liquidity pool: " ++ show lp - getAaveDatum :: TxOutTx -> Contract w s Text AaveDatum getAaveDatum o = case txOutDatumHash $ txOutTxOut o of Nothing -> throwError "datumHash not found" @@ -381,27 +308,17 @@ type AaveOwnerSchema = type AaveUserSchema = BlockchainActions .\/ Endpoint "create" Integer - .\/ Endpoint "close" AssetClass - .\/ Endpoint "stop" () -- | Type of the Aave user contract state. data UserContractState = Created - | Closed - | Stopped deriving (Show, Generic, FromJSON, ToJSON) -- | Provides the following endpoints for users of a Aave instance: -- -- [@create@]: Creates a liquidity pool for a pair of coins. The creator provides liquidity for both coins and gets liquidity tokens in return. --- [@close@]: Closes a liquidity pool by burning all remaining liquidity tokens in exchange for all liquidity remaining in the pool. --- [@stop@]: Stops the contract. userEndpoints :: Aave -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () -userEndpoints aa = - stop - `select` - ((f (Proxy @"create") (const Created) create `select` - f (Proxy @"close") (const Closed) close ) - >> userEndpoints aa) +userEndpoints aa = f (Proxy @"create") (const Created) create + >> userEndpoints aa where f :: forall l a p. HasEndpoint l p AaveUserSchema @@ -416,10 +333,3 @@ userEndpoints aa = tell $ Last $ Just $ case e of Left err -> Left err Right a -> Right $ g a - - stop :: Contract (Last (Either Text UserContractState)) AaveUserSchema Void () - stop = do - e <- runError $ endpoint @"stop" - tell $ Last $ Just $ case e of - Left err -> Left err - Right () -> Right Stopped From b93eab7bf40b7ccfce1dbaaca3a7226889fc5222 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 7 May 2021 15:15:10 +0700 Subject: [PATCH 016/169] wip fix create endpoint --- MetaLamp/lending-pool/pab/Main.hs | 5 +-- .../src/Plutus/Contracts/LendingPool.hs | 39 ++++++++----------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index 104fa750e..521549909 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -79,9 +79,8 @@ main = void $ Simulator.runSimulationWith handlers $ do Simulator.logString @(Builtin AaveContracts) $ "Aave user contract started for " ++ show w return (w, cid) - let cp = 10000 :: Integer - Simulator.logString @(Builtin AaveContracts) $ "creating liquidity pool: " ++ show (encode cp) - _ <- Simulator.callEndpointOnInstance (cids Map.! Wallet 2) "create" cp + Simulator.logString @(Builtin AaveContracts) "creating liquidity pool" + _ <- Simulator.callEndpointOnInstance (cids Map.! Wallet 2) "create" () flip Simulator.waitForState (cids Map.! Wallet 2) $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of Success (Monoid.Last (Just (Right Aave.Created))) -> Just () _ -> Nothing diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index c6c5d0d8f..02afc8907 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -48,9 +48,9 @@ import qualified Prelude import Text.Printf (printf) import Plutus.V1.Ledger.Ada ( lovelaceValueOf ) -aaveProtocolName, aaveTokenName :: TokenName +aaveProtocolName, aavePoolName :: TokenName aaveProtocolName = "Aave" -aaveTokenName = "aToken" +aavePoolName = "Aave Lending Pool" deriving anyclass instance ToSchema AssetClass @@ -117,8 +117,8 @@ validateCreate Aave{..} lps lp@LendingPool{..} ctx = traceIfFalse "Aave assetClassValue not present" (assetClassValueOf (valueWithin $ findOwnInput' ctx) aaveProtocolInst == 1) && notElem lp lps && Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ assetClassValue aaveProtocolInst 1) && - (assetClassValueOf forged lpToken == aTokensNum) && - Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp aTokensNum) $ assetClassValue lpToken aTokensNum) + (assetClassValueOf forged lpToken == 1) && + Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp 0) $ assetClassValue lpToken 1) where poolOutput :: TxOut poolOutput = case [o | o <- getContinuingOutputs ctx, assetClassValueOf (txOutValue o) lpToken == 1] of @@ -128,9 +128,6 @@ validateCreate Aave{..} lps lp@LendingPool{..} ctx = forged :: Value forged = txInfoForge $ scriptContextTxInfo ctx - aTokensNum :: Integer - aTokensNum = assetClassValueOf forged lpToken - {-# INLINABLE findPoolDatum #-} findPoolDatum :: TxInfo -> DatumHash -> (LendingPool, Integer) findPoolDatum info h = case findDatum h info of @@ -186,7 +183,7 @@ liquidityPolicy :: Aave -> MonetaryPolicy liquidityPolicy aa = mkMonetaryPolicyScript $ $$(PlutusTx.compile [|| \a t -> Scripts.wrapMonetaryPolicy (validateLiquidityForging a t) ||]) `PlutusTx.applyCode` PlutusTx.liftCode aa - `PlutusTx.applyCode` PlutusTx.liftCode aaveTokenName + `PlutusTx.applyCode` PlutusTx.liftCode aavePoolName -- | Creates a Aave "factory". This factory will keep track of the existing liquidity pools and enforce that there will be at most one liquidity pool -- for any pair of tokens at any given time. @@ -207,21 +204,21 @@ start = do return aa -- | Creates a liquidity pool for a pair of coins. The creator provides liquidity for both coins and gets liquidity tokens in return. -create :: HasBlockchainActions s => Aave -> Integer -> Contract w s Text () -create aa aTokensNum = do +create :: HasBlockchainActions s => Aave -> Contract w s Text () +create aa = do pkh <- pubKeyHash <$> ownPubKey cs <- fmap Currency.currencySymbol $ mapError (pack . show @Currency.CurrencyError) $ - Currency.forgeContract pkh [(aaveTokenName, aTokensNum)] + Currency.forgeContract pkh [(aavePoolName, 1)] (oref, o, lps) <- findAaveFactory aa - let c = assetClass cs aaveTokenName + let c = assetClass cs aavePoolName let lp = LendingPool c let aaInst = aaveInstance aa aaScript = aaveScript aa aaDat1 = Factory $ lp : lps - aaDat2 = Pool lp aTokensNum + aaDat2 = Pool lp 0 aaVal = assetClassValue (aaveProtocolInst aa) 1 - lpVal = lovelaceValueOf aTokensNum + lpVal = assetClassValue c 1 lookups = Constraints.scriptInstanceLookups aaInst <> Constraints.otherScript aaScript <> @@ -230,7 +227,7 @@ create aa aTokensNum = do tx = Constraints.mustPayToTheScript aaDat1 aaVal <> Constraints.mustPayToTheScript aaDat2 lpVal <> - Constraints.mustForgeValue (assetClassValue c aTokensNum) <> + Constraints.mustForgeValue lpVal <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ Create lp) ledgerTx <- submitTxConstraintsWith lookups tx @@ -307,7 +304,7 @@ type AaveOwnerSchema = -- | Schema for the endpoints for users of Aave. type AaveUserSchema = BlockchainActions - .\/ Endpoint "create" Integer + .\/ Endpoint "create" () -- | Type of the Aave user contract state. data UserContractState = Created @@ -317,19 +314,17 @@ data UserContractState = Created -- -- [@create@]: Creates a liquidity pool for a pair of coins. The creator provides liquidity for both coins and gets liquidity tokens in return. userEndpoints :: Aave -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () -userEndpoints aa = f (Proxy @"create") (const Created) create - >> userEndpoints aa +userEndpoints aa = forever $ f (Proxy @"create") (const Created) create where f :: forall l a p. - HasEndpoint l p AaveUserSchema + HasEndpoint l () AaveUserSchema => Proxy l -> (a -> UserContractState) - -> (Aave -> p -> Contract (Last (Either Text UserContractState)) AaveUserSchema Text a) + -> (Aave -> Contract (Last (Either Text UserContractState)) AaveUserSchema Text a) -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () f _ g c = do e <- runError $ do - p <- endpoint @l - c aa p + c aa tell $ Last $ Just $ case e of Left err -> Left err Right a -> Right $ g a From 5ffafe00efb3dcf3c65d7e7b6d59694359111954 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 7 May 2021 15:38:08 +0700 Subject: [PATCH 017/169] fix infinite pool creation --- MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index 02afc8907..2b867fc77 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -324,6 +324,7 @@ userEndpoints aa = forever $ f (Proxy @"create") (const Created) create -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () f _ g c = do e <- runError $ do + _ <- endpoint @l c aa tell $ Last $ Just $ case e of Left err -> Left err From 6f096fcfe05d83d7ab9e0cddf91000a536e28200 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 7 May 2021 16:17:14 +0700 Subject: [PATCH 018/169] fix create endpoint --- .../src/Plutus/Contracts/LendingPool.hs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index 2b867fc77..bcc77f86c 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -39,7 +39,6 @@ import qualified Ledger.Typed.Scripts as Scripts import Ledger.Value as Value import Playground.Contract import Plutus.Contract hiding (when) --- TODO remove that dep Plutus.Contracts.Currency (?) import qualified Plutus.Contracts.Currency as Currency import qualified PlutusTx import PlutusTx.Prelude hiding (Semigroup (..), unless) @@ -117,16 +116,7 @@ validateCreate Aave{..} lps lp@LendingPool{..} ctx = traceIfFalse "Aave assetClassValue not present" (assetClassValueOf (valueWithin $ findOwnInput' ctx) aaveProtocolInst == 1) && notElem lp lps && Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ assetClassValue aaveProtocolInst 1) && - (assetClassValueOf forged lpToken == 1) && Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp 0) $ assetClassValue lpToken 1) - where - poolOutput :: TxOut - poolOutput = case [o | o <- getContinuingOutputs ctx, assetClassValueOf (txOutValue o) lpToken == 1] of - [o] -> o - _ -> traceError "expected exactly one pool output" - - forged :: Value - forged = txInfoForge $ scriptContextTxInfo ctx {-# INLINABLE findPoolDatum #-} findPoolDatum :: TxInfo -> DatumHash -> (LendingPool, Integer) @@ -222,12 +212,12 @@ create aa = do lookups = Constraints.scriptInstanceLookups aaInst <> Constraints.otherScript aaScript <> - Constraints.monetaryPolicy (liquidityPolicy aa) <> + -- Constraints.monetaryPolicy (liquidityPolicy aa) <> Constraints.unspentOutputs (Map.singleton oref o) tx = Constraints.mustPayToTheScript aaDat1 aaVal <> Constraints.mustPayToTheScript aaDat2 lpVal <> - Constraints.mustForgeValue lpVal <> + -- Constraints.mustForgeValue lpVal <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ Create lp) ledgerTx <- submitTxConstraintsWith lookups tx From f5165593101158eb2dc1736ee26e8ebf26d8df83 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 7 May 2021 16:27:07 +0700 Subject: [PATCH 019/169] rm not used functions --- .../src/Plutus/Contracts/LendingPool.hs | 34 +++---------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index bcc77f86c..5f8e746ba 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -134,21 +134,6 @@ mkAaveValidator :: Aave mkAaveValidator aa (Factory lps) (Create lp) ctx = validateCreate aa lps lp ctx mkAaveValidator _ _ _ _ = False -validateLiquidityForging :: Aave -> TokenName -> ScriptContext -> Bool -validateLiquidityForging aa tn ctx = case [ i - | i <- txInfoInputs $ scriptContextTxInfo ctx - , let v = valueWithin i - , (assetClassValueOf v aaC == 1) || - (assetClassValueOf v lpC == 1) - ] of - [_] -> True - [_, _] -> True - _ -> traceError "pool state forging without Aave input" - where - aaC, lpC :: AssetClass - aaC = aaveProtocolInst aa - lpC = assetClass (ownCurrencySymbol ctx) tn - aaveInstance :: Aave -> Scripts.ScriptInstance AaveScript aaveInstance aa = Scripts.validator @AaveScript ($$(PlutusTx.compile [|| mkAaveValidator ||]) @@ -169,14 +154,7 @@ aaveAddress = Ledger.scriptAddress . aaveScript aave :: CurrencySymbol -> Aave aave protocol = Aave (assetClass protocol aaveProtocolName) -liquidityPolicy :: Aave -> MonetaryPolicy -liquidityPolicy aa = mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| \a t -> Scripts.wrapMonetaryPolicy (validateLiquidityForging a t) ||]) - `PlutusTx.applyCode` PlutusTx.liftCode aa - `PlutusTx.applyCode` PlutusTx.liftCode aavePoolName - --- | Creates a Aave "factory". This factory will keep track of the existing liquidity pools and enforce that there will be at most one liquidity pool --- for any pair of tokens at any given time. +-- | Creates a Aave "factory". This factory will keep track of the existing lending pools start :: HasBlockchainActions s => Contract w s Text Aave start = do pkh <- pubKeyHash <$> ownPubKey @@ -193,7 +171,7 @@ start = do logInfo @String $ printf "started Aave %s at address %s" (show aa) (show $ aaveAddress aa) return aa --- | Creates a liquidity pool for a pair of coins. The creator provides liquidity for both coins and gets liquidity tokens in return. +-- | Creates a lending pool. create :: HasBlockchainActions s => Aave -> Contract w s Text () create aa = do pkh <- pubKeyHash <$> ownPubKey @@ -212,18 +190,16 @@ create aa = do lookups = Constraints.scriptInstanceLookups aaInst <> Constraints.otherScript aaScript <> - -- Constraints.monetaryPolicy (liquidityPolicy aa) <> Constraints.unspentOutputs (Map.singleton oref o) tx = Constraints.mustPayToTheScript aaDat1 aaVal <> Constraints.mustPayToTheScript aaDat2 lpVal <> - -- Constraints.mustForgeValue lpVal <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ Create lp) ledgerTx <- submitTxConstraintsWith lookups tx void $ awaitTxConfirmed $ txId ledgerTx - logInfo $ "created liquidity pool: " ++ show lp + logInfo $ "created lending pool: " ++ show lp getAaveDatum :: TxOutTx -> Contract w s Text AaveDatum getAaveDatum o = case txOutDatumHash $ txOutTxOut o of @@ -278,7 +254,7 @@ findAaveFactoryAndPool aa lpToFind = do return ( (oref1, o1, lps) , (oref2, o2, lp, a) ) - _ -> throwError "liquidity pool not found" + _ -> throwError "lending pool not found" ownerEndpoint :: Contract (Last (Either Text Aave)) BlockchainActions Void () ownerEndpoint = do @@ -302,7 +278,7 @@ data UserContractState = Created -- | Provides the following endpoints for users of a Aave instance: -- --- [@create@]: Creates a liquidity pool for a pair of coins. The creator provides liquidity for both coins and gets liquidity tokens in return. +-- [@create@]: Creates a lending pool. userEndpoints :: Aave -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () userEndpoints aa = forever $ f (Proxy @"create") (const Created) create where From 34cc66d7f6f3e20679a38afe64e551608c6253a4 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 7 May 2021 16:36:15 +0700 Subject: [PATCH 020/169] fix readme --- MetaLamp/lending-pool/README.md | 138 +++----------------------------- 1 file changed, 12 insertions(+), 126 deletions(-) diff --git a/MetaLamp/lending-pool/README.md b/MetaLamp/lending-pool/README.md index 9912e989f..90b1b830c 100644 --- a/MetaLamp/lending-pool/README.md +++ b/MetaLamp/lending-pool/README.md @@ -4,146 +4,32 @@ This project gives a simple starter project for using the Plutus Platform. ## Setting up -For now, the only supported tooling setup is to use the provided VSCode devcontainer to get an environment with the correct tools set up. - -- Install Docker -- Install VSCode - - Install the [Remote Development extension pack](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) - - You do *not* need to install the Haskell extension -- Get the docker image (for now, we need to build this with Nix) - - Clone https://github.com/input-output-hk/plutus - - Set up your machine to build things with Nix, following the Plutus README (make sure to set up the binary cache!) - - Build and load the docker container: `docker load < $(nix-build default.nix -A devcontainer)` -- Clone this repository and open it in VSCode - - It will ask if you want to open it in the container, say yes. - - `cabal build` from the terminal should work - - Opening a Haskell file should give you IDE features (it takes a little while to set up the first time) - +- Install nix +- Clone https://github.com/input-output-hk/plutus +- Set up your machine to build things with Nix, following the Plutus README (make sure to set up the binary cache!) ## The Plutus Application Backend (PAB) example We have provided an example PAB application in `./pab`. With the PAB we can serve and interact with contracts over a web API. You can read more about the PAB here: [PAB Architecture](https://github.com/input-output-hk/plutus/blob/master/plutus-pab/ARCHITECTURE.adoc). -Here, the PAB is configured with one contract, the `Game` contract from `./examples/src/Plutus/Contracts/Game.hs`. - -Here's an example of running and interacting with this contract via the API. For this it will help if you -have `jq` installed. - -1. Build the PAB executable: +1. Enter the nix shell (cd to the cloned Plutus repo): ``` -cabal build plutus-starter-pab +git checkout 58bf9ed626d498c140c69a859a508da03843d097 +nix-shell ``` -2. Run the PAB binary: +2. Build the PAB executable (cd to plutus-use-cases/MetaLamp/lending-pool): ``` -cabal exec -- plutus-starter-pab -```` - -This will then start up the server on port 8080. The devcontainer process will then automatically expose this port so that you can connect to it from any terminal (it doesn't have to be a terminal running in the devcontainer). - -First, let's verify that the game is present in the server: - -3. Check what contracts are present: - +cabal build ``` -curl -s http://localhost:8080/api/new/contract/definitions | jq -``` - -You should receive a list of contracts and the endpoints that can be called on them, and the arguments -required for those endpoints. -We're interested in the `GameContract` one. +3. Run the PAB binary: -#### Playing the guessing game over the API - -The game has two players (wallets). One will initialise the contract and lock a value inside. Another -wallet will then make guesses. Supposing they guess correctly, they'll receive the funds that were -locked; otherwise, they won't! - -1. Start the instances: - -``` -# Wallet 1 -curl -s -H "Content-Type: application/json" \ - --request POST \ - --data '{"caID": "GameContract", "caWallet":{"getWallet": 1}}' \ - http://localhost:8080/api/new/contract/activate | jq - -# Wallet 2 -curl -s -H "Content-Type: application/json" \ - --request POST \ - --data '{"caID": "GameContract", "caWallet":{"getWallet": 2}}' \ - http://localhost:8080/api/new/contract/activate | jq -``` - -From these two queries you will get back two contract instance IDs. These will be needed -in the subsequent steps for running actions against. We can optionally take a look at the state -of the contract with the `status` API: - -2. Get the status - -``` -export INSTANCE_ID=... -curl -s http://localhost:8080/api/new/contract/instance/$INSTANCE_ID/status | jq ``` +cabal run plutus-starter-pab +```` -This has a lot of information; and in particular we can see what endpoints are still available -to call. - -3. Start the game by locking some value inside - -Now, let's call the `lock` endpoint to start the game. In order to do so, we need to construct -a JSON representation of the `LockParams` that the endpoint takes (look at `Game.hs`). The easiest -way is to simply build the term in haskell and ask `aeson` to encode it. From the terminal: - -``` -cabal repl -> import Plutus.Contracts.Game -> import Ledger.Ada -> args = LockParams { secretWord = "eagle", amount = lovelaceValueOf 90 } -> import Data.Aeson -> import Data.ByteString.Lazy.Char8 as BSL -> BSL.putStrLn $ encode args -{"amount":{"getValue":[[{"unCurrencySymbol":""},[[{"unTokenName":""},90]]]]},"secretWord":"eagle"} -``` - -Great! This is all we need to call the `lock` endpoint, so let's do that now with -the instance from Wallet 1: - -4. Lock some value (Wallet 1) - -``` -export INSTANCE_ID=... -curl -H "Content-Type: application/json" \ - --request POST \ - --data '{"amount":{"getValue":[[{"unCurrencySymbol":""},[[{"unTokenName":""},90]]]]},"secretWord":"eagle"}' \ - http://localhost:8080/api/new/contract/instance/$INSTANCE_ID/endpoint/lock -``` - -We can do likewise to work out what the JSON for `GuessParams` is, and then make a guess from -Wallet 2: - -5. Make a guess (Wallet 2) - -``` -export INSTANCE_ID=... -curl -H "Content-Type: application/json" \ - --request POST \ - --data '{"guessWord": "duck"}' \ - http://localhost:8080/api/new/contract/instance/$INSTANCE_ID/endpoint/guess -``` - -Note that this guess is wrong, so in the log of the server we will see that the transaction -didn't validate. - -As an exercise, you can now spin up another instance for Wallet 2 and make a correct guess, and -confirm that the transaction validates and the Ada is transferred into the right wallet. - -Note that you can verify the balances by looking at the log of `plutus-starter-pab` -when exiting it by pressing return. - -Finally, also node that the PAB also exposes a websocket, which you can read about in -the general [PAB Architecture documentation](https://github.com/input-output-hk/plutus/blob/master/plutus-pab/ARCHITECTURE.adoc). \ No newline at end of file +This will then start up the server on port 8080. From edd886d9b22fea36a8c63b7457d82625e5ee6c97 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 11 May 2021 17:56:19 +0700 Subject: [PATCH 021/169] add fmt command --- MetaLamp/lending-pool/Makefile | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 MetaLamp/lending-pool/Makefile diff --git a/MetaLamp/lending-pool/Makefile b/MetaLamp/lending-pool/Makefile new file mode 100644 index 000000000..c2c2dd4ea --- /dev/null +++ b/MetaLamp/lending-pool/Makefile @@ -0,0 +1,3 @@ +fmt: + find . -type f -name \*.hs -exec \ + stylish-haskell --inplace '{}' + From 82b86f83ff0bd9f756f6aa0a4a45fd52c407cf16 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 11 May 2021 17:58:29 +0700 Subject: [PATCH 022/169] run fmt --- MetaLamp/lending-pool/Makefile | 2 +- MetaLamp/lending-pool/pab/Main.hs | 63 ++++++++++--------- .../src/Plutus/Contracts/LendingPool.hs | 7 ++- 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/MetaLamp/lending-pool/Makefile b/MetaLamp/lending-pool/Makefile index c2c2dd4ea..78eafd665 100644 --- a/MetaLamp/lending-pool/Makefile +++ b/MetaLamp/lending-pool/Makefile @@ -1,3 +1,3 @@ fmt: - find . -type f -name \*.hs -exec \ + find pab src -type f -name \*.hs -exec \ stylish-haskell --inplace '{}' + diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index 521549909..e6ee3acf8 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -13,35 +13,40 @@ module Main ( main ) where -import Control.Monad ( forM, void, forM_, when ) -import Control.Monad.Freer (Eff, Member, interpret, type (~>)) -import Control.Monad.Freer.Error (Error) -import Control.Monad.Freer.Extras.Log (LogMsg) -import Control.Monad.IO.Class (MonadIO (..)) -import Data.Aeson (FromJSON, Result (..), ToJSON, encode, fromJSON) -import qualified Data.Map.Strict as Map -import qualified Data.Monoid as Monoid -import Data.Text (Text) -import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) -import GHC.Generics (Generic) -import Ledger.Ada (adaSymbol, adaToken, adaValueOf,lovelaceValueOf) -import qualified Plutus.Contracts.LendingPool as Aave -import Plutus.PAB.Effects.Contract (ContractEffect (..)) -import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), type (.\\)) -import qualified Plutus.PAB.Effects.Contract.Builtin as Builtin -import Plutus.PAB.Monitoring.PABLogMsg (PABMultiAgentMsg) -import Plutus.PAB.Simulator (SimulatorEffectHandlers) -import qualified Plutus.PAB.Simulator as Simulator -import Plutus.PAB.Types (PABError (..)) -import qualified Plutus.PAB.Webserver.Server as PAB.Server -import Prelude hiding (init) -import qualified Data.Semigroup as Semigroup +import Control.Monad (forM, forM_, void, when) +import Control.Monad.Freer (Eff, Member, interpret, + type (~>)) +import Control.Monad.Freer.Error (Error) +import Control.Monad.Freer.Extras.Log (LogMsg) +import Control.Monad.IO.Class (MonadIO (..)) +import Data.Aeson (FromJSON, Result (..), + ToJSON, encode, fromJSON) +import qualified Data.Map.Strict as Map +import qualified Data.Monoid as Monoid +import qualified Data.Semigroup as Semigroup +import Data.Text (Text) +import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) +import GHC.Generics (Generic) import Ledger +import Ledger.Ada (adaSymbol, adaToken, + adaValueOf, + lovelaceValueOf) import Ledger.Constraints -import Ledger.Value as Value -import Plutus.Contract hiding (when) -import qualified Plutus.Contracts.Currency as Currency -import Wallet.Emulator.Types (Wallet (..), walletPubKey) +import Ledger.Value as Value +import Plutus.Contract hiding (when) +import qualified Plutus.Contracts.Currency as Currency +import qualified Plutus.Contracts.LendingPool as Aave +import Plutus.PAB.Effects.Contract (ContractEffect (..)) +import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), + type (.\\)) +import qualified Plutus.PAB.Effects.Contract.Builtin as Builtin +import Plutus.PAB.Monitoring.PABLogMsg (PABMultiAgentMsg) +import Plutus.PAB.Simulator (SimulatorEffectHandlers) +import qualified Plutus.PAB.Simulator as Simulator +import Plutus.PAB.Types (PABError (..)) +import qualified Plutus.PAB.Webserver.Server as PAB.Server +import Prelude hiding (init) +import Wallet.Emulator.Types (Wallet (..), walletPubKey) initContract :: Contract (Maybe (Semigroup.Last Currency.OneShotCurrency)) Currency.CurrencySchema Currency.CurrencyError () initContract = do @@ -83,7 +88,7 @@ main = void $ Simulator.runSimulationWith handlers $ do _ <- Simulator.callEndpointOnInstance (cids Map.! Wallet 2) "create" () flip Simulator.waitForState (cids Map.! Wallet 2) $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of Success (Monoid.Last (Just (Right Aave.Created))) -> Just () - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) "liquidity pool created" _ <- liftIO getLine @@ -113,7 +118,7 @@ handleAaveContract = Builtin.handleBuiltin getSchema getContract where getContract = \case AaveUser us -> SomeBuiltin $ Aave.userEndpoints us AaveStart -> SomeBuiltin Aave.ownerEndpoint - Init -> SomeBuiltin initContract + Init -> SomeBuiltin initContract handlers :: SimulatorEffectHandlers (Builtin AaveContracts) handlers = diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs index 5f8e746ba..62324364b 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs @@ -15,7 +15,7 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE StandaloneDeriving #-} module Plutus.Contracts.LendingPool ( AssetClass (..) , Aave (..), aave @@ -40,12 +40,13 @@ import Ledger.Value as Value import Playground.Contract import Plutus.Contract hiding (when) import qualified Plutus.Contracts.Currency as Currency +import Plutus.V1.Ledger.Ada (lovelaceValueOf) import qualified PlutusTx -import PlutusTx.Prelude hiding (Semigroup (..), unless) +import PlutusTx.Prelude hiding (Semigroup (..), + unless) import Prelude (Semigroup (..)) import qualified Prelude import Text.Printf (printf) -import Plutus.V1.Ledger.Ada ( lovelaceValueOf ) aaveProtocolName, aavePoolName :: TokenName aaveProtocolName = "Aave" From 0ef48e82c8e4056b5406a40f91f54fa4a919d45c Mon Sep 17 00:00:00 2001 From: megakaban Date: Fri, 14 May 2021 13:06:09 +0700 Subject: [PATCH 023/169] Add deposit/withdraw logic --- MetaLamp/lending-pool/pab/Main.hs | 165 +++++++--- MetaLamp/lending-pool/plutus-starter.cabal | 6 +- .../src/Plutus/Contracts/AToken.hs | 86 +++++ .../lending-pool/src/Plutus/Contracts/Core.hs | 169 ++++++++++ .../src/Plutus/Contracts/Endpoints.hs | 238 ++++++++++++++ .../src/Plutus/Contracts/FungibleToken.hs | 20 ++ .../src/Plutus/Contracts/LendingPool.hs | 297 ------------------ .../src/Plutus/Contracts/State.hs | 185 +++++++++++ 8 files changed, 821 insertions(+), 345 deletions(-) create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs delete mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/State.hs diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index 521549909..022e04675 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -9,55 +9,83 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} + module Main ( main ) where -import Control.Monad ( forM, void, forM_, when ) -import Control.Monad.Freer (Eff, Member, interpret, type (~>)) -import Control.Monad.Freer.Error (Error) -import Control.Monad.Freer.Extras.Log (LogMsg) -import Control.Monad.IO.Class (MonadIO (..)) -import Data.Aeson (FromJSON, Result (..), ToJSON, encode, fromJSON) -import qualified Data.Map.Strict as Map -import qualified Data.Monoid as Monoid -import Data.Text (Text) -import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) -import GHC.Generics (Generic) -import Ledger.Ada (adaSymbol, adaToken, adaValueOf,lovelaceValueOf) -import qualified Plutus.Contracts.LendingPool as Aave -import Plutus.PAB.Effects.Contract (ContractEffect (..)) -import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), type (.\\)) -import qualified Plutus.PAB.Effects.Contract.Builtin as Builtin -import Plutus.PAB.Monitoring.PABLogMsg (PABMultiAgentMsg) -import Plutus.PAB.Simulator (SimulatorEffectHandlers) -import qualified Plutus.PAB.Simulator as Simulator -import Plutus.PAB.Types (PABError (..)) -import qualified Plutus.PAB.Webserver.Server as PAB.Server -import Prelude hiding (init) -import qualified Data.Semigroup as Semigroup +import Control.Monad (forM, forM_, void, when) +import Control.Monad.Freer (Eff, Member, interpret, + type (~>)) +import Control.Monad.Freer.Error (Error) +import Control.Monad.Freer.Extras.Log (LogMsg) +import Control.Monad.IO.Class (MonadIO (..)) +import Data.Aeson (FromJSON, Result (..), + ToJSON, encode, fromJSON) +import qualified Data.ByteString as BS +import qualified Data.Map.Strict as Map +import qualified Data.Monoid as Monoid +import qualified Data.Semigroup as Semigroup +import Data.Text (Text) +import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) +import GHC.Generics (Generic) import Ledger +import Ledger.Ada (adaSymbol, adaToken, + adaValueOf, + lovelaceValueOf) import Ledger.Constraints -import Ledger.Value as Value -import Plutus.Contract hiding (when) -import qualified Plutus.Contracts.Currency as Currency -import Wallet.Emulator.Types (Wallet (..), walletPubKey) +import qualified Ledger.Constraints.OffChain as Constraints +import qualified Ledger.Typed.Scripts as Scripts +import Ledger.Value as Value +import Plutus.Contract hiding (when) +import Plutus.Contracts.Currency as Currency +import qualified Plutus.Contracts.FungibleToken as FungibleToken +import qualified Plutus.Contracts.Endpoints as Aave +import qualified Plutus.Contracts.Core as Aave +import Plutus.PAB.Effects.Contract (ContractEffect (..)) +import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), + type (.\\)) +import qualified Plutus.PAB.Effects.Contract.Builtin as Builtin +import Plutus.PAB.Monitoring.PABLogMsg (PABMultiAgentMsg) +import Plutus.PAB.Simulator (SimulatorEffectHandlers) +import qualified Plutus.PAB.Simulator as Simulator +import Plutus.PAB.Types (PABError (..)) +import qualified Plutus.PAB.Webserver.Server as PAB.Server +import Plutus.V1.Ledger.Crypto (getPubKeyHash, pubKeyHash) +import Prelude hiding (init) +import Wallet.Emulator.Types (Wallet (..), walletPubKey) + +wallets :: [Wallet] +wallets = [Wallet i | i <- [1 .. 4]] + +testCurrencyNames :: [BS.ByteString] +testCurrencyNames = ["MOGUS"] + +toAsset :: BS.ByteString -> AssetClass +toAsset rawName = + assetClass (scriptCurrencySymbol . FungibleToken.makeLiquidityPolicy $ tokenName) tokenName + where tokenName = Value.tokenName rawName + +testAssets :: [AssetClass] +testAssets = fmap toAsset testCurrencyNames initContract :: Contract (Maybe (Semigroup.Last Currency.OneShotCurrency)) Currency.CurrencySchema Currency.CurrencyError () initContract = do ownPK <- pubKeyHash <$> ownPubKey - let v = lovelaceValueOf amount + let testCurrenciesValue = mconcat $ fmap (`assetClassValue` 1000) testAssets + policyLookups = mconcat $ + fmap (Constraints.monetaryPolicy . FungibleToken.makeLiquidityPolicy . Prelude.snd . unAssetClass) testAssets + adaValue = lovelaceValueOf amount forM_ wallets $ \w -> do let pkh = pubKeyHash $ walletPubKey w + lookups = policyLookups + tx = mustForgeValue testCurrenciesValue <> mustPayToPubKey pkh (adaValue <> testCurrenciesValue) when (pkh /= ownPK) $ do - tx <- submitTx $ mustPayToPubKey pkh v - awaitTxConfirmed $ txId tx + ledgerTx <- submitTxConstraintsWith @Scripts.Any lookups tx + void $ awaitTxConfirmed $ txId ledgerTx where amount = 1000000 -wallets :: [Wallet] -wallets = [Wallet i | i <- [1 .. 4]] - main :: IO () main = void $ Simulator.runSimulationWith handlers $ do Simulator.logString @(Builtin AaveContracts) "Starting Aave PAB webserver on port 8080. Press enter to exit." @@ -68,7 +96,8 @@ main = void $ Simulator.runSimulationWith handlers $ do Simulator.logString @(Builtin AaveContracts) "Initialization finished." - cidStart <- Simulator.activateContract (Wallet 1) AaveStart + let params = fmap Aave.CreateParams testAssets + cidStart <- Simulator.activateContract (Wallet 1) (AaveStart params) aa <- flip Simulator.waitForState cidStart $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.Aave))) of Success (Monoid.Last (Just (Right aa))) -> Just aa _ -> Nothing @@ -79,21 +108,65 @@ main = void $ Simulator.runSimulationWith handlers $ do Simulator.logString @(Builtin AaveContracts) $ "Aave user contract started for " ++ show w return (w, cid) - Simulator.logString @(Builtin AaveContracts) "creating liquidity pool" - _ <- Simulator.callEndpointOnInstance (cids Map.! Wallet 2) "create" () - flip Simulator.waitForState (cids Map.! Wallet 2) $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right Aave.Created))) -> Just () - _ -> Nothing - Simulator.logString @(Builtin AaveContracts) "liquidity pool created" + let userCid = cids Map.! Wallet 2 + sender = pubKeyHash . walletPubKey $ Wallet 2 + + Simulator.logString @(Builtin AaveContracts) $ "Send:" <> show sender + + _ <- + Simulator.callEndpointOnInstance userCid "deposit" $ + Aave.DepositParams { Aave.dpAsset = head testAssets, Aave.dpOnBehalfOf = sender, Aave.dpAmount = 100 } + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right Aave.Deposited))) -> Just () + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Successful deposit" + + _ <- + Simulator.callEndpointOnInstance userCid "withdraw" $ + Aave.WithdrawParams { Aave.wpAsset = head testAssets, Aave.wpTo = sender, Aave.wpFrom = sender, Aave.wpAmount = 50 } + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right Aave.Withdrawn))) -> Just () + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Successful withdraw" + + _ <- Simulator.callEndpointOnInstance userCid "fundsAt" sender + v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right (Aave.FundsAt v)))) -> Just v + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Final user funds: " <> show v + + _ <- Simulator.callEndpointOnInstance userCid "factory" () + v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right (Aave.FactoryEndpoint v)))) -> Just v + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Final factory: " <> show v + + _ <- Simulator.callEndpointOnInstance userCid "pools" () + pools <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right (Aave.Pools pools)))) -> Just pools + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Final pools: " <> show pools + + _ <- Simulator.callEndpointOnInstance userCid "poolFunds" () + v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right (Aave.PoolFunds v)))) -> Just v + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Final pool funds: " <> show v + + _ <- Simulator.callEndpointOnInstance userCid "users" () + v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right (Aave.Users v)))) -> Just v + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Final users: " <> show v _ <- liftIO getLine shutdown data AaveContracts = Init - | AaveStart + | AaveStart [Aave.CreateParams] | AaveUser Aave.Aave - deriving (Eq, Ord, Show, Generic) + deriving (Show, Generic) deriving anyclass (FromJSON, ToJSON) instance Pretty AaveContracts where @@ -108,12 +181,12 @@ handleAaveContract :: handleAaveContract = Builtin.handleBuiltin getSchema getContract where getSchema = \case AaveUser _ -> Builtin.endpointsToSchemas @(Aave.AaveUserSchema .\\ BlockchainActions) - AaveStart -> Builtin.endpointsToSchemas @(Aave.AaveOwnerSchema .\\ BlockchainActions) + AaveStart _ -> Builtin.endpointsToSchemas @(Aave.AaveOwnerSchema .\\ BlockchainActions) Init -> Builtin.endpointsToSchemas @Empty getContract = \case - AaveUser us -> SomeBuiltin $ Aave.userEndpoints us - AaveStart -> SomeBuiltin Aave.ownerEndpoint - Init -> SomeBuiltin initContract + AaveUser us -> SomeBuiltin $ Aave.userEndpoints us + AaveStart params -> SomeBuiltin $ Aave.ownerEndpoint params + Init -> SomeBuiltin initContract handlers :: SimulatorEffectHandlers (Builtin AaveContracts) handlers = diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index cb889f48b..a7346d46a 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -23,7 +23,7 @@ maintainer: Your email library exposed-modules: - Plutus.Contracts.LendingPool + Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.State build-depends: base >= 4.9 && < 5, aeson, @@ -64,4 +64,6 @@ executable plutus-starter-pab plutus-pab, plutus-starter, playground-common, - plutus-use-cases + plutus-use-cases, + plutus-ledger-api, + bytestring diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs new file mode 100644 index 000000000..072bf351e --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -0,0 +1,86 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + +module Plutus.Contracts.AToken where + +import Data.ByteString (ByteString) +import Data.Text (Text) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import Ledger.Typed.Scripts (MonetaryPolicy) +import qualified Ledger.Typed.Scripts as Scripts +import Plutus.Contract +import Plutus.Contracts.Core (Aave, LendingPool (..)) +import qualified Plutus.Contracts.Core as Core +import Plutus.V1.Ledger.Contexts (ScriptContext, + scriptCurrencySymbol) +import qualified Plutus.V1.Ledger.Scripts as Scripts +import Plutus.V1.Ledger.Value +import Plutus.V1.Ledger.Value (AssetClass (unAssetClass), + TokenName (..), assetClass, assetClassValue) +import qualified PlutusTx +import PlutusTx.Prelude hiding (Semigroup (..)) +import Prelude (Semigroup (..)) +import qualified Prelude + +-- TODO: check that ScriptContext has enough liquidity +validator :: AssetClass -> ScriptContext -> Bool +validator _ _ = True + +makeLiquidityPolicy :: AssetClass -> MonetaryPolicy +makeLiquidityPolicy asset = Scripts.mkMonetaryPolicyScript $ + $$(PlutusTx.compile [|| Scripts.wrapMonetaryPolicy . validator ||]) + `PlutusTx.applyCode` + PlutusTx.liftCode asset + +makeAToken :: AssetClass -> AssetClass +makeAToken asset = assetClass (scriptCurrencySymbol . makeLiquidityPolicy $ asset) (TokenName aTokenName) + where + (_, tokenName) = unAssetClass asset + aTokenName = "a" <> unTokenName tokenName + +forgeATokensFrom :: (HasBlockchainActions s) => Aave -> LendingPool -> PubKeyHash -> Integer -> Contract w s Text () +forgeATokensFrom aave reserve pkh amount = do + let script = Core.aaveInstance aave + policy = makeLiquidityPolicy (lpCurrency reserve) + lookups = Constraints.scriptInstanceLookups script + <> Constraints.monetaryPolicy policy + <> Constraints.ownPubKeyHash pkh + aTokenAmount = amount -- / lpLiquidityIndex reserve -- TODO: how should we divide? + outValue = assetClassValue (lpAToken reserve) aTokenAmount + tx = mustForgeValue outValue <> mustPayToPubKey pkh outValue + ledgerTx <- submitTxConstraintsWith lookups tx + _ <- awaitTxConfirmed $ txId ledgerTx + pure () + +burnATokensFrom :: (HasBlockchainActions s) => Aave -> LendingPool -> PubKeyHash -> Integer -> Contract w s Text () +burnATokensFrom aave reserve pkh amount = do + logInfo @String "BURN" + let script = Core.aaveInstance aave + policy = makeLiquidityPolicy (lpCurrency reserve) + lookups = Constraints.scriptInstanceLookups script + <> Constraints.monetaryPolicy policy + <> Constraints.ownPubKeyHash pkh + aTokenAmount = amount -- / lpLiquidityIndex reserve -- TODO: how should we divide? + outValue = negate (assetClassValue (lpAToken reserve) aTokenAmount) + tx = mustForgeValue outValue <> mustPayToPubKey pkh (assetClassValue (lpCurrency reserve) aTokenAmount) + ledgerTx <- submitTxConstraintsWith lookups tx + _ <- awaitTxConfirmed $ txId ledgerTx + pure () diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs new file mode 100644 index 000000000..e83facd3f --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -0,0 +1,169 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} + +module Plutus.Contracts.Core where + +import Control.Monad hiding (fmap) +import qualified Data.ByteString as BS +import qualified Data.Map as Map +import Data.Text (Text, pack) +import Data.Void (Void) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as Scripts +import qualified Ledger.Typed.Scripts as Scripts +import Playground.Contract +import Plutus.Contract hiding (when) +import Plutus.V1.Ledger.Value +import qualified PlutusTx +import PlutusTx.Prelude hiding (Semigroup (..), + unless) +import Prelude (Semigroup (..)) +import qualified Prelude + +deriving anyclass instance ToSchema AssetClass + +newtype Aave = Aave + { aaveProtocolInst :: AssetClass + } deriving stock (Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.makeLift ''Aave + +instance Prelude.Eq Aave where + u == v = aaveProtocolInst u Prelude.== aaveProtocolInst v + +instance Prelude.Ord Aave where + compare u v = Prelude.compare (aaveProtocolInst u) (aaveProtocolInst v) + +type LendingPoolId = AssetClass + +type AnyAddress = BS.ByteString + +data LendingPool = LendingPool + { lpCurrency :: LendingPoolId, + lpAToken :: AssetClass, + lpAmount :: Integer, + lpDebtToken :: AssetClass, + lpLiquidityIndex :: Integer + } + deriving stock (Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''LendingPool +PlutusTx.makeLift ''LendingPool + +data UserConfig = UserConfig + { ucAddress :: PubKeyHash, + ucReserveId :: LendingPoolId, + ucUsingAsCollateral :: Bool + } + deriving stock (Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''UserConfig +PlutusTx.makeLift ''UserConfig + +type Factory = [LendingPoolId] +data AaveAction = CreateLendingPool LendingPool | UpdateLendingPool | CreateUser UserConfig | UpdateUser | Withdraw + deriving Show + +PlutusTx.unstableMakeIsData ''AaveAction +PlutusTx.makeLift ''AaveAction + +data AaveDatum = Factory Factory | Pool LendingPool | User UserConfig | Deposit deriving stock (Show) + +PlutusTx.unstableMakeIsData ''AaveDatum +PlutusTx.makeLift ''AaveDatum + +data AaveScript +instance Scripts.ScriptType AaveScript where + type instance RedeemerType AaveScript = AaveAction + type instance DatumType AaveScript = AaveDatum + +-- Main validator +-- Each state field must have one or more associated actions(Redeemer types), +-- produced on state update, which are then validated here +-- TODO: write validations +makeAaveValidator :: Aave + -> AaveDatum + -> AaveAction + -> ScriptContext + -> Bool +makeAaveValidator _ _ (CreateLendingPool _) _ = True +makeAaveValidator _ _ UpdateLendingPool _ = True +makeAaveValidator _ _ (CreateUser _) _ = True +makeAaveValidator _ _ UpdateUser _ = True +makeAaveValidator _ _ Withdraw _ = True +makeAaveValidator _ _ _ _ = False + +aaveProtocolName :: TokenName +aaveProtocolName = "Aave" + +aaveInstance :: Aave -> Scripts.ScriptInstance AaveScript +aaveInstance aave = Scripts.validator @AaveScript + ($$(PlutusTx.compile [|| makeAaveValidator ||]) + `PlutusTx.applyCode` PlutusTx.liftCode aave) + $$(PlutusTx.compile [|| wrap ||]) + where + wrap = Scripts.wrapValidator @AaveDatum @AaveAction + +aaveScript :: Aave -> Validator +aaveScript = Scripts.validatorScript . aaveInstance + +aaveHash :: Aave -> Ledger.ValidatorHash +aaveHash = Scripts.validatorHash . aaveScript + +aaveAddress :: Aave -> Ledger.Address +aaveAddress = Ledger.scriptAddress . aaveScript + +aave :: CurrencySymbol -> Aave +aave protocol = Aave (assetClass protocol aaveProtocolName) + +-- State forging validator/policy +-- TODO: Fix +validateStateForging :: Aave -> TokenName -> ScriptContext -> Bool +validateStateForging aave tn ctx = True +{-case [ i + | i <- txInfoInputs $ scriptContextTxInfo ctx + , let v = valueWithin i + , (assetClassValueOf v aaveToken == 1) || + (assetClassValueOf v stateToken == 1) + ] of + [_] -> True + [_, _] -> True + _ -> traceError "State forging without Aave input" + where + aaveToken = aaveProtocolInst aave + stateToken = assetClass (ownCurrencySymbol ctx) tn + valueWithin = txOutValue . txInInfoResolved +-} + +makeStatePolicy :: TokenName -> Aave -> MonetaryPolicy +makeStatePolicy tokenName aave = mkMonetaryPolicyScript $ + $$(PlutusTx.compile [|| \u t -> Scripts.wrapMonetaryPolicy (validateStateForging u t) ||]) + `PlutusTx.applyCode` PlutusTx.liftCode aave + `PlutusTx.applyCode` PlutusTx.liftCode tokenName + +makeStateCurrency :: TokenName -> Aave -> CurrencySymbol +makeStateCurrency tokenName = scriptCurrencySymbol . makeStatePolicy tokenName + +makeStateToken :: TokenName -> Aave -> AssetClass +makeStateToken tokenName = flip assetClass tokenName . makeStateCurrency tokenName + +poolStateToken, userStateToken :: Aave -> AssetClass +poolStateToken = makeStateToken "aaveLendingPool" +userStateToken = makeStateToken "aaveUser" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs new file mode 100644 index 000000000..0f5615f9c --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -0,0 +1,238 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + +module Plutus.Contracts.Endpoints where + +import Control.Monad hiding (fmap) +import qualified Data.Map as Map +import Data.Monoid (Last (..)) +import Data.Proxy (Proxy (..)) +import Data.Text (Text, pack) +import Data.Void (Void) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as Scripts +import qualified Ledger.Typed.Scripts as Scripts +import Playground.Contract +import Plutus.Contract hiding (when) +-- TODO remove that dep Plutus.Contracts.Currency (?) +import qualified Data.ByteString as BS +import qualified Plutus.Contracts.AToken as AToken +import Plutus.Contracts.Core (Aave, AaveAction (..), + AaveDatum (..), Factory, + LendingPool (..), + LendingPoolId, + UserConfig (..)) +import qualified Plutus.Contracts.Core as Core +import Plutus.Contracts.Currency as Currency +import qualified Plutus.Contracts.FungibleToken as FungibleToken +import Plutus.Contracts.State (StateOutput (..)) +import qualified Plutus.Contracts.State as State +import Plutus.V1.Ledger.Ada (adaValueOf, lovelaceValueOf) +import Plutus.V1.Ledger.Value as Value +import qualified PlutusTx +import PlutusTx.Prelude hiding (Semigroup (..), + unless) +import Prelude (Semigroup (..)) +import qualified Prelude +import Text.Printf (printf) +import qualified Plutus.V1.Ledger.Address as Addr + +errorHandler t = logInfo @Text ("Error submiting the transaction!: " <> t) + +newtype CreateParams = + CreateParams + { cpAsset :: AssetClass } + deriving (Show, Generic) + deriving anyclass (FromJSON, ToJSON, ToSchema) + +PlutusTx.makeLift ''CreateParams + +createPool :: CreateParams -> LendingPool +createPool CreateParams {..} = + LendingPool + { lpCurrency = cpAsset, + lpAmount = 0, + lpAToken = AToken.makeAToken cpAsset, + lpDebtToken = cpAsset, + lpLiquidityIndex = 1 } + +start :: HasBlockchainActions s => [CreateParams] -> Contract w s Text Aave +start params = do + pkh <- pubKeyHash <$> ownPubKey + aaveToken <- fmap Currency.currencySymbol $ + mapError (pack . show @Currency.CurrencyError) $ + Currency.forgeContract pkh [(Core.aaveProtocolName, 1)] + let aave = Core.aave aaveToken + let pools = fmap createPool params + let factoryCoin = assetClass aaveToken Core.aaveProtocolName + inst = Core.aaveInstance aave + tx = mustPayToTheScript (Factory (fmap lpCurrency pools)) $ assetClassValue factoryCoin 1 + ledgerTx <- submitTxConstraints inst tx + void $ awaitTxConfirmed $ txId ledgerTx + traverse_ (State.putPool aave) pools + logInfo @String $ printf "started Aave %s at address %s" (show aave) (show $ Core.aaveAddress aave) + pure aave + +ownerEndpoint :: [CreateParams] -> Contract (Last (Either Text Aave)) BlockchainActions Void () +ownerEndpoint params = do + e <- runError $ start params + tell $ Last $ Just $ case e of + Left err -> Left err + Right aa -> Right aa + +type AaveOwnerSchema = + BlockchainActions + .\/ Endpoint "start" () + +factory :: forall w s. HasBlockchainActions s => Aave -> Contract w s Text Factory +factory = fmap soDatum . State.findAaveFactory + +pools :: forall w s. HasBlockchainActions s => Aave -> Contract w s Text [LendingPool] +pools aave = Prelude.fmap soDatum <$> State.findOutputsBy aave (Core.poolStateToken aave) State.pickPool + +users :: forall w s. HasBlockchainActions s => Aave -> Contract w s Text [UserConfig] +users aave = Prelude.fmap soDatum <$> State.findOutputsBy aave (Core.userStateToken aave) State.pickUser + +valueAt :: HasBlockchainActions s => Address -> Contract w s Text Value +valueAt address = do + os <- map snd . Map.toList <$> utxoAt address + pure $ mconcat [txOutValue $ txOutTxOut o | o <- os] + +fundsAt :: HasBlockchainActions s => PubKeyHash -> Contract w s Text Value +fundsAt pkh = valueAt (pubKeyHashAddress pkh) + +balanceAt :: HasBlockchainActions s => PubKeyHash -> AssetClass -> Contract w s Text Integer +balanceAt pkh asset = flip assetClassValueOf asset <$> fundsAt pkh + +poolFunds :: forall w s. HasBlockchainActions s => Aave -> Contract w s Text Value +poolFunds aave = valueAt (Core.aaveAddress aave) + +data DepositParams = + DepositParams { + dpAsset :: AssetClass, + dpOnBehalfOf :: PubKeyHash, + dpAmount :: Integer + } + deriving stock (Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''DepositParams +PlutusTx.makeLift ''DepositParams + +deposit :: (HasBlockchainActions s) => Aave -> DepositParams -> Contract w s Text () +deposit aave DepositParams {..} = do + reserveOutput <- State.findAavePool aave dpAsset + let reserve = soDatum reserveOutput + lookups = Constraints.ownPubKeyHash dpOnBehalfOf + <> Constraints.scriptInstanceLookups (Core.aaveInstance aave) + outValue = assetClassValue (lpCurrency reserve) dpAmount + tx = mustPayToTheScript Core.Deposit outValue + ledgerTx <- submitTxConstraintsWith lookups tx + _ <- awaitTxConfirmed $ txId ledgerTx + + logInfo @String $ "HASH " <> show dpOnBehalfOf + + wasZeroBalance <- (== 0) <$> balanceAt dpOnBehalfOf (lpAToken reserve) + _ <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount + when wasZeroBalance $ do + userOutputs <- State.findOutputsBy aave (Core.userStateToken aave) State.pickUser + case userOutputs of + [] -> void $ + State.putUser aave $ UserConfig { ucAddress = dpOnBehalfOf, ucReserveId = lpCurrency reserve, ucUsingAsCollateral = True } + [userOutput] -> void $ + State.updateUser aave $ Prelude.fmap (\u -> u { ucUsingAsCollateral = True }) userOutput + _ -> throwError "Invalid state: multiple users" + + void $ State.updatePool aave $ Prelude.fmap (\r -> r { lpAmount = lpAmount r + dpAmount }) reserveOutput + +data WithdrawParams = + WithdrawParams { + wpAsset :: AssetClass, + wpTo :: PubKeyHash, + wpFrom :: PubKeyHash, + wpAmount :: Integer + } + deriving stock (Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''WithdrawParams +PlutusTx.makeLift ''WithdrawParams + +withdraw :: (HasBlockchainActions s) => Aave -> WithdrawParams -> Contract w s Text () +withdraw aave WithdrawParams {..} = do + reserveOutput <- State.findAavePool aave wpAsset + let reserve = soDatum reserveOutput + + balance <- balanceAt wpFrom (lpAToken reserve) + when (wpAmount == balance) $ do + userOutput <- State.findAaveUser aave wpFrom wpAsset + void $ + State.updateUser aave $ Prelude.fmap (\u -> u { ucUsingAsCollateral = False }) userOutput + + _ <- AToken.burnATokensFrom aave reserve wpTo wpAmount + + void $ State.updatePool aave $ Prelude.fmap (\r -> r { lpAmount = lpAmount r - wpAmount }) reserveOutput + +type AaveUserSchema = + BlockchainActions + .\/ Endpoint "deposit" DepositParams + .\/ Endpoint "withdraw" WithdrawParams + .\/ Endpoint "fundsAt" PubKeyHash + .\/ Endpoint "poolFunds" () + .\/ Endpoint "factory" () + .\/ Endpoint "pools" () + .\/ Endpoint "users" () + +data UserContractState = Created + | Closed + | Stopped + | Deposited + | Withdrawn + | FundsAt Value + | PoolFunds Value + | FactoryEndpoint Factory + | Pools [LendingPool] + | Users [UserConfig] + deriving (Show, Generic, FromJSON, ToJSON) + +userEndpoints :: Aave -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () +userEndpoints aa = forever $ + f (Proxy @"deposit") (const Deposited) deposit + `select` f (Proxy @"withdraw") (const Withdrawn) withdraw + `select` f (Proxy @"fundsAt") FundsAt (\_ pkh -> fundsAt pkh) + `select` f (Proxy @"poolFunds") PoolFunds (\aave () -> poolFunds aave) + `select` f (Proxy @"factory") FactoryEndpoint (\aave () -> factory aave) + `select` f (Proxy @"pools") Pools (\aave () -> pools aave) + `select` f (Proxy @"users") Users (\aave () -> users aave) + where + f :: forall l a p. + HasEndpoint l p AaveUserSchema + => Proxy l + -> (a -> UserContractState) + -> (Aave -> p -> Contract (Last (Either Text UserContractState)) AaveUserSchema Text a) + -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () + f _ g c = do + e <- runError $ do + p <- endpoint @l + c aa p + tell $ Last $ Just $ case e of + Left err -> Left err + Right a -> Right $ g a diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs new file mode 100644 index 000000000..11ffe6f2e --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs @@ -0,0 +1,20 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE TemplateHaskell #-} + +module Plutus.Contracts.FungibleToken where + +import Ledger.Typed.Scripts (MonetaryPolicy) +import qualified Ledger.Typed.Scripts as Scripts +import Plutus.V1.Ledger.Contexts (ScriptContext) +import qualified Plutus.V1.Ledger.Scripts as Scripts +import Plutus.V1.Ledger.Value (TokenName, Value) +import qualified PlutusTx + +validator :: TokenName -> ScriptContext -> Bool +validator _ _ = True + +makeLiquidityPolicy :: TokenName -> MonetaryPolicy +makeLiquidityPolicy tokenName = Scripts.mkMonetaryPolicyScript $ + $$(PlutusTx.compile [|| Scripts.wrapMonetaryPolicy . validator ||]) + `PlutusTx.applyCode` + PlutusTx.liftCode tokenName diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs deleted file mode 100644 index 5f8e746ba..000000000 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool.hs +++ /dev/null @@ -1,297 +0,0 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} - -{-# LANGUAGE StandaloneDeriving #-} -module Plutus.Contracts.LendingPool - ( AssetClass (..) - , Aave (..), aave - , AaveUserSchema, AaveOwnerSchema, UserContractState (..) - , start, create - , ownerEndpoint, userEndpoints - ) where - -import Control.Monad hiding (fmap) -import qualified Data.Map as Map -import Data.Monoid (Last (..)) -import Data.Proxy (Proxy (..)) -import Data.Text (Text, pack) -import Data.Void (Void) -import Ledger hiding (singleton) -import Ledger.Constraints as Constraints -import Ledger.Constraints.OnChain as Constraints -import Ledger.Constraints.TxConstraints as Constraints -import qualified Ledger.Scripts as Scripts -import qualified Ledger.Typed.Scripts as Scripts -import Ledger.Value as Value -import Playground.Contract -import Plutus.Contract hiding (when) -import qualified Plutus.Contracts.Currency as Currency -import qualified PlutusTx -import PlutusTx.Prelude hiding (Semigroup (..), unless) -import Prelude (Semigroup (..)) -import qualified Prelude -import Text.Printf (printf) -import Plutus.V1.Ledger.Ada ( lovelaceValueOf ) - -aaveProtocolName, aavePoolName :: TokenName -aaveProtocolName = "Aave" -aavePoolName = "Aave Lending Pool" - -deriving anyclass instance ToSchema AssetClass - -newtype LendingPool = LendingPool - { lpToken :: AssetClass - } - deriving stock (Show, Generic) - deriving anyclass (ToJSON, FromJSON, ToSchema) - -PlutusTx.unstableMakeIsData ''LendingPool -PlutusTx.makeLift ''LendingPool - -instance Eq LendingPool where - {-# INLINABLE (==) #-} - x == y = lpToken x == lpToken y - -newtype Aave = Aave - { aaveProtocolInst :: AssetClass - } deriving stock (Show, Generic) - deriving anyclass (ToJSON, FromJSON, ToSchema) - -PlutusTx.makeLift ''Aave - -instance Prelude.Eq Aave where - u == v = aaveProtocolInst u Prelude.== aaveProtocolInst v - -instance Prelude.Ord Aave where - compare u v = Prelude.compare (aaveProtocolInst u) (aaveProtocolInst v) - -data AaveAction = Create LendingPool - deriving Show - -PlutusTx.unstableMakeIsData ''AaveAction -PlutusTx.makeLift ''AaveAction - -data AaveDatum = - Factory [LendingPool] - | Pool LendingPool Integer -- Pool consisting of lending pool link and aTokens amount - deriving stock (Show) - -PlutusTx.unstableMakeIsData ''AaveDatum -PlutusTx.makeLift ''AaveDatum - -data AaveScript -instance Scripts.ScriptType AaveScript where - type instance RedeemerType AaveScript = AaveAction - type instance DatumType AaveScript = AaveDatum - -{-# INLINABLE findOwnInput' #-} -findOwnInput' :: ScriptContext -> TxInInfo -findOwnInput' ctx = fromMaybe (error ()) (findOwnInput ctx) - -{-# INLINABLE valueWithin #-} -valueWithin :: TxInInfo -> Value -valueWithin = txOutValue . txInInfoResolved - -{-# INLINABLE validateCreate #-} -validateCreate :: Aave - -> [LendingPool] - -> LendingPool - -> ScriptContext - -> Bool -validateCreate Aave{..} lps lp@LendingPool{..} ctx = - traceIfFalse "Aave assetClassValue not present" (assetClassValueOf (valueWithin $ findOwnInput' ctx) aaveProtocolInst == 1) && - notElem lp lps && - Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Factory $ lp : lps) $ assetClassValue aaveProtocolInst 1) && - Constraints.checkOwnOutputConstraint ctx (OutputConstraint (Pool lp 0) $ assetClassValue lpToken 1) - -{-# INLINABLE findPoolDatum #-} -findPoolDatum :: TxInfo -> DatumHash -> (LendingPool, Integer) -findPoolDatum info h = case findDatum h info of - Just (Datum d) -> case PlutusTx.fromData d of - Just (Pool lp a) -> (lp, a) - _ -> traceError "error decoding data" - _ -> traceError "pool input datum not found" - -mkAaveValidator :: Aave - -> AaveDatum - -> AaveAction - -> ScriptContext - -> Bool -mkAaveValidator aa (Factory lps) (Create lp) ctx = validateCreate aa lps lp ctx -mkAaveValidator _ _ _ _ = False - -aaveInstance :: Aave -> Scripts.ScriptInstance AaveScript -aaveInstance aa = Scripts.validator @AaveScript - ($$(PlutusTx.compile [|| mkAaveValidator ||]) - `PlutusTx.applyCode` PlutusTx.liftCode aa) - $$(PlutusTx.compile [|| wrap ||]) - where - wrap = Scripts.wrapValidator @AaveDatum @AaveAction - -aaveScript :: Aave -> Validator -aaveScript = Scripts.validatorScript . aaveInstance - -aaveHash :: Aave -> Ledger.ValidatorHash -aaveHash = Scripts.validatorHash . aaveScript - -aaveAddress :: Aave -> Ledger.Address -aaveAddress = Ledger.scriptAddress . aaveScript - -aave :: CurrencySymbol -> Aave -aave protocol = Aave (assetClass protocol aaveProtocolName) - --- | Creates a Aave "factory". This factory will keep track of the existing lending pools -start :: HasBlockchainActions s => Contract w s Text Aave -start = do - pkh <- pubKeyHash <$> ownPubKey - cs <- fmap Currency.currencySymbol $ - mapError (pack . show @Currency.CurrencyError) $ - Currency.forgeContract pkh [(aaveProtocolName, 1)] - let c = assetClass cs aaveProtocolName - let aa = aave cs - inst = aaveInstance aa - tx = mustPayToTheScript (Factory []) $ assetClassValue c 1 - ledgerTx <- submitTxConstraints inst tx - void $ awaitTxConfirmed $ txId ledgerTx - - logInfo @String $ printf "started Aave %s at address %s" (show aa) (show $ aaveAddress aa) - return aa - --- | Creates a lending pool. -create :: HasBlockchainActions s => Aave -> Contract w s Text () -create aa = do - pkh <- pubKeyHash <$> ownPubKey - cs <- fmap Currency.currencySymbol $ - mapError (pack . show @Currency.CurrencyError) $ - Currency.forgeContract pkh [(aavePoolName, 1)] - (oref, o, lps) <- findAaveFactory aa - let c = assetClass cs aavePoolName - let lp = LendingPool c - let aaInst = aaveInstance aa - aaScript = aaveScript aa - aaDat1 = Factory $ lp : lps - aaDat2 = Pool lp 0 - aaVal = assetClassValue (aaveProtocolInst aa) 1 - lpVal = assetClassValue c 1 - - lookups = Constraints.scriptInstanceLookups aaInst <> - Constraints.otherScript aaScript <> - Constraints.unspentOutputs (Map.singleton oref o) - - tx = Constraints.mustPayToTheScript aaDat1 aaVal <> - Constraints.mustPayToTheScript aaDat2 lpVal <> - Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ Create lp) - - ledgerTx <- submitTxConstraintsWith lookups tx - void $ awaitTxConfirmed $ txId ledgerTx - - logInfo $ "created lending pool: " ++ show lp - -getAaveDatum :: TxOutTx -> Contract w s Text AaveDatum -getAaveDatum o = case txOutDatumHash $ txOutTxOut o of - Nothing -> throwError "datumHash not found" - Just h -> case Map.lookup h $ txData $ txOutTxTx o of - Nothing -> throwError "datum not found" - Just (Datum e) -> case PlutusTx.fromData e of - Nothing -> throwError "datum has wrong type" - Just d -> return d - -findAaveInstance :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text (TxOutRef, TxOutTx, a) -findAaveInstance aa c f = do - let addr = aaveAddress aa - logInfo @String $ printf "looking for Aave instance at address %s containing assetClassValue %s " (show addr) (show c) - utxos <- utxoAt addr - go [x | x@(_, o) <- Map.toList utxos, assetClassValueOf (txOutValue $ txOutTxOut o) c == 1] - where - go [] = throwError "Aave instance not found" - go ((oref, o) : xs) = do - d <- getAaveDatum o - case f d of - Nothing -> go xs - Just a -> do - logInfo @String $ printf "found Aave instance with datum: %s" (show d) - return (oref, o, a) - -findAaveFactory :: HasBlockchainActions s => Aave -> Contract w s Text (TxOutRef, TxOutTx, [LendingPool]) -findAaveFactory aa@Aave{..} = findAaveInstance aa aaveProtocolInst $ \case - Factory lps -> Just lps - Pool _ _ -> Nothing - -findAavePool :: HasBlockchainActions s => Aave -> LendingPool -> Contract w s Text (TxOutRef, TxOutTx, Integer) -findAavePool aa lp = findAaveInstance aa (lpToken lp) $ \case - Pool lp' l - | lp == lp' -> Just l - _ -> Nothing - -findAaveFactoryAndPool :: HasBlockchainActions s - => Aave - -> LendingPool - -> Contract w s Text ( (TxOutRef, TxOutTx, [LendingPool]) - , (TxOutRef, TxOutTx, LendingPool, Integer) - ) -findAaveFactoryAndPool aa lpToFind = do - (oref1, o1, lps) <- findAaveFactory aa - case [ lp' - | lp' <- lps - , lp' == lpToFind - ] of - [lp] -> do - (oref2, o2, a) <- findAavePool aa lp - return ( (oref1, o1, lps) - , (oref2, o2, lp, a) - ) - _ -> throwError "lending pool not found" - -ownerEndpoint :: Contract (Last (Either Text Aave)) BlockchainActions Void () -ownerEndpoint = do - e <- runError start - tell $ Last $ Just $ case e of - Left err -> Left err - Right aa -> Right aa - -type AaveOwnerSchema = - BlockchainActions - .\/ Endpoint "start" () - --- | Schema for the endpoints for users of Aave. -type AaveUserSchema = - BlockchainActions - .\/ Endpoint "create" () - --- | Type of the Aave user contract state. -data UserContractState = Created - deriving (Show, Generic, FromJSON, ToJSON) - --- | Provides the following endpoints for users of a Aave instance: --- --- [@create@]: Creates a lending pool. -userEndpoints :: Aave -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () -userEndpoints aa = forever $ f (Proxy @"create") (const Created) create - where - f :: forall l a p. - HasEndpoint l () AaveUserSchema - => Proxy l - -> (a -> UserContractState) - -> (Aave -> Contract (Last (Either Text UserContractState)) AaveUserSchema Text a) - -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () - f _ g c = do - e <- runError $ do - _ <- endpoint @l - c aa - tell $ Last $ Just $ case e of - Left err -> Left err - Right a -> Right $ g a diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs new file mode 100644 index 000000000..b755508ac --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -0,0 +1,185 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + +module Plutus.Contracts.State where + +import Control.Monad hiding (fmap) +import qualified Data.ByteString as BS +import qualified Data.Map as Map +import Data.Monoid (Last (..)) +import Data.Proxy (Proxy (..)) +import Data.Text (Text, pack) +import qualified Data.Text as Text +import Data.Void (Void) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as Scripts +import qualified Ledger.Typed.Scripts as Scripts +import Playground.Contract +import Plutus.Contract hiding (when) +import qualified Plutus.Contracts.AToken as AToken +import Plutus.Contracts.Core (Aave (..), AaveAction (..), + AaveDatum (..), Factory, + LendingPool (..), + LendingPoolId, + UserConfig (..)) +import qualified Plutus.Contracts.Core as Core +import Plutus.Contracts.Currency as Currency +import qualified Plutus.Contracts.FungibleToken as FungibleToken +import Plutus.V1.Ledger.Ada (adaValueOf, lovelaceValueOf) +import Plutus.V1.Ledger.Value as Value +import qualified PlutusTx +import PlutusTx.Prelude hiding (Functor (..), + Semigroup (..), unless) +import Prelude (Semigroup (..), fmap) +import qualified Prelude + +data StateOutput a = + StateOutput { + soOutRef :: TxOutRef, + soOutTx :: TxOutTx, + soDatum :: a + } deriving (Prelude.Show, Prelude.Functor) + +getAaveDatum :: TxOutTx -> Contract w s Text AaveDatum +getAaveDatum o = case txOutDatumHash $ txOutTxOut o of + Nothing -> throwError "datumHash not found" + Just h -> case Map.lookup h $ txData $ txOutTxTx o of + Nothing -> throwError "datum not found" + Just (Datum e) -> case PlutusTx.fromData e of + Nothing -> throwError "datum has wrong type" + Just d -> return d + +getAaveState :: HasBlockchainActions s => Aave -> Contract w s Text [StateOutput AaveDatum] +getAaveState aave = do + utxos <- utxoAt (Core.aaveAddress aave) + traverse getDatum . Map.toList $ utxos + where + getDatum (oref, o) = do + d <- getAaveDatum o + pure $ StateOutput oref o d + +findOutputsBy :: forall w s a. HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text [StateOutput a] +findOutputsBy aave stateToken mapDatum = mapMaybe checkStateToken <$> getAaveState aave + where + checkStateToken (StateOutput oref outTx datum) = + if assetClassValueOf (txOutValue $ txOutTxOut outTx) stateToken == 1 + then fmap (StateOutput oref outTx) (mapDatum datum) + else Nothing + +findOutputBy :: forall w s a. HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text (StateOutput a) +findOutputBy aave stateToken mapDatum = do + outputs <- findOutputsBy aave stateToken mapDatum + let stateName = Text.pack . Prelude.show . Prelude.snd . unAssetClass $ stateToken + case outputs of + [output] -> pure output + [] -> throwError $ stateName <> " not found" + xs -> throwError $ "Multiple " <> stateName <> " found" + +pickFactory :: AaveDatum -> Maybe Factory +pickFactory (Factory f) = Just f +pickFactory _ = Nothing + +findAaveFactory :: HasBlockchainActions s => Aave -> Contract w s Text (StateOutput Factory) +findAaveFactory aave@Aave{..} = findOutputBy aave aaveProtocolInst pickFactory + +findAavePool :: HasBlockchainActions s => Aave -> LendingPoolId -> Contract w s Text (StateOutput LendingPool) +findAavePool aave poolId = findOutputBy aave (Core.poolStateToken aave) mapState + where + mapState (Pool lp) = + if lpCurrency lp == poolId + then Just lp + else Nothing + mapState _ = Nothing + +findAaveUser :: HasBlockchainActions s => Aave -> PubKeyHash -> LendingPoolId -> Contract w s Text (StateOutput UserConfig) +findAaveUser aave userAddress poolId = findOutputBy aave (Core.userStateToken aave) mapState + where + mapState (User user) = + if ucAddress user == userAddress && ucReserveId user == poolId + then Just user + else Nothing + mapState _ = Nothing + +data StateHandle a = StateHandle { + getToken :: Aave -> AssetClass, + toDatum :: a -> AaveDatum, + toAction :: a -> AaveAction +} + +putState :: (HasBlockchainActions s) => StateHandle a -> Aave -> a -> Contract w s Text a +putState StateHandle{..} aave datum = do + let stateToken = getToken aave + lookups = Constraints.scriptInstanceLookups (Core.aaveInstance aave) + <> Constraints.monetaryPolicy (Core.makeStatePolicy (Prelude.snd . unAssetClass $ stateToken) aave) + tx = mustForgeValue (assetClassValue stateToken 1) + <> mustPayToTheScript (toDatum datum) (assetClassValue stateToken 1) + ledgerTx <- submitTxConstraintsWith lookups tx + _ <- awaitTxConfirmed $ txId ledgerTx + pure datum + +updateState :: (HasBlockchainActions s) => StateHandle a -> Aave -> StateOutput a -> Contract w s Text a +updateState StateHandle{..} aave (StateOutput oref o datum) = do + let stateToken = getToken aave + lookups = Constraints.scriptInstanceLookups (Core.aaveInstance aave) + <> Constraints.otherScript (Core.aaveScript aave) + <> Constraints.unspentOutputs (Map.singleton oref o) + tx = mustPayToTheScript (toDatum datum) (assetClassValue stateToken 1) + <> mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData (toAction datum)) + ledgerTx <- submitTxConstraintsWith lookups tx + _ <- awaitTxConfirmed $ txId ledgerTx + pure datum + +makePoolHandle :: (LendingPool -> AaveAction) -> StateHandle LendingPool +makePoolHandle toAction = + StateHandle { + getToken = Core.poolStateToken, + toDatum = Pool, + toAction = toAction + } + +pickPool :: AaveDatum -> Maybe LendingPool +pickPool (Pool lp) = Just lp +pickPool _ = Nothing + +putPool :: (HasBlockchainActions s) => Aave -> LendingPool -> Contract w s Text LendingPool +putPool = putState $ makePoolHandle Core.CreateLendingPool + +updatePool :: (HasBlockchainActions s) => Aave -> StateOutput LendingPool -> Contract w s Text LendingPool +updatePool = updateState $ makePoolHandle (const Core.UpdateLendingPool) + +makeUserHandle :: (UserConfig -> AaveAction) -> StateHandle UserConfig +makeUserHandle toAction = + StateHandle { + getToken = Core.userStateToken, + toDatum = Core.User, + toAction = toAction + } + +pickUser :: AaveDatum -> Maybe UserConfig +pickUser (User user) = Just user +pickUser _ = Nothing + +putUser :: (HasBlockchainActions s) => Aave -> UserConfig -> Contract w s Text UserConfig +putUser = putState $ makeUserHandle Core.CreateUser + +updateUser :: (HasBlockchainActions s) => Aave -> StateOutput UserConfig -> Contract w s Text UserConfig +updateUser = updateState $ makeUserHandle (const Core.UpdateUser) From b9cb31c856dedae2a7fe105376eb29b30e7ebb2a Mon Sep 17 00:00:00 2001 From: megakaban Date: Fri, 14 May 2021 14:19:40 +0700 Subject: [PATCH 024/169] Merge formatter --- MetaLamp/lending-pool/Makefile | 3 +++ MetaLamp/lending-pool/pab/Main.hs | 10 +++++----- MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs | 3 ++- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 8 ++++---- .../lending-pool/src/Plutus/Contracts/Endpoints.hs | 2 +- MetaLamp/lending-pool/src/Plutus/Contracts/State.hs | 8 ++++---- 6 files changed, 19 insertions(+), 15 deletions(-) create mode 100644 MetaLamp/lending-pool/Makefile diff --git a/MetaLamp/lending-pool/Makefile b/MetaLamp/lending-pool/Makefile new file mode 100644 index 000000000..78eafd665 --- /dev/null +++ b/MetaLamp/lending-pool/Makefile @@ -0,0 +1,3 @@ +fmt: + find pab src -type f -name \*.hs -exec \ + stylish-haskell --inplace '{}' + diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index 022e04675..a420b288d 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -38,10 +38,10 @@ import qualified Ledger.Constraints.OffChain as Constraints import qualified Ledger.Typed.Scripts as Scripts import Ledger.Value as Value import Plutus.Contract hiding (when) +import qualified Plutus.Contracts.Core as Aave import Plutus.Contracts.Currency as Currency +import qualified Plutus.Contracts.Endpoints as Aave import qualified Plutus.Contracts.FungibleToken as FungibleToken -import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Contracts.Core as Aave import Plutus.PAB.Effects.Contract (ContractEffect (..)) import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), type (.\\)) @@ -132,7 +132,7 @@ main = void $ Simulator.runSimulationWith handlers $ do _ <- Simulator.callEndpointOnInstance userCid "fundsAt" sender v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of Success (Monoid.Last (Just (Right (Aave.FundsAt v)))) -> Just v - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final user funds: " <> show v _ <- Simulator.callEndpointOnInstance userCid "factory" () @@ -150,13 +150,13 @@ main = void $ Simulator.runSimulationWith handlers $ do _ <- Simulator.callEndpointOnInstance userCid "poolFunds" () v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of Success (Monoid.Last (Just (Right (Aave.PoolFunds v)))) -> Just v - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final pool funds: " <> show v _ <- Simulator.callEndpointOnInstance userCid "users" () v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of Success (Monoid.Last (Just (Right (Aave.Users v)))) -> Just v - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final users: " <> show v _ <- liftIO getLine diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 072bf351e..f9c29e283 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -34,7 +34,8 @@ import Plutus.V1.Ledger.Contexts (ScriptContext, import qualified Plutus.V1.Ledger.Scripts as Scripts import Plutus.V1.Ledger.Value import Plutus.V1.Ledger.Value (AssetClass (unAssetClass), - TokenName (..), assetClass, assetClassValue) + TokenName (..), assetClass, + assetClassValue) import qualified PlutusTx import PlutusTx.Prelude hiding (Semigroup (..)) import Prelude (Semigroup (..)) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index e83facd3f..2957fe4a9 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -105,10 +105,10 @@ makeAaveValidator :: Aave -> Bool makeAaveValidator _ _ (CreateLendingPool _) _ = True makeAaveValidator _ _ UpdateLendingPool _ = True -makeAaveValidator _ _ (CreateUser _) _ = True -makeAaveValidator _ _ UpdateUser _ = True -makeAaveValidator _ _ Withdraw _ = True -makeAaveValidator _ _ _ _ = False +makeAaveValidator _ _ (CreateUser _) _ = True +makeAaveValidator _ _ UpdateUser _ = True +makeAaveValidator _ _ Withdraw _ = True +makeAaveValidator _ _ _ _ = False aaveProtocolName :: TokenName aaveProtocolName = "Aave" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 0f5615f9c..17004ee75 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -46,6 +46,7 @@ import qualified Plutus.Contracts.FungibleToken as FungibleToken import Plutus.Contracts.State (StateOutput (..)) import qualified Plutus.Contracts.State as State import Plutus.V1.Ledger.Ada (adaValueOf, lovelaceValueOf) +import qualified Plutus.V1.Ledger.Address as Addr import Plutus.V1.Ledger.Value as Value import qualified PlutusTx import PlutusTx.Prelude hiding (Semigroup (..), @@ -53,7 +54,6 @@ import PlutusTx.Prelude hiding (Semigroup (..), import Prelude (Semigroup (..)) import qualified Prelude import Text.Printf (printf) -import qualified Plutus.V1.Ledger.Address as Addr errorHandler t = logInfo @Text ("Error submiting the transaction!: " <> t) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index b755508ac..c6ed303c0 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -91,12 +91,12 @@ findOutputBy aave stateToken mapDatum = do let stateName = Text.pack . Prelude.show . Prelude.snd . unAssetClass $ stateToken case outputs of [output] -> pure output - [] -> throwError $ stateName <> " not found" - xs -> throwError $ "Multiple " <> stateName <> " found" + [] -> throwError $ stateName <> " not found" + xs -> throwError $ "Multiple " <> stateName <> " found" pickFactory :: AaveDatum -> Maybe Factory pickFactory (Factory f) = Just f -pickFactory _ = Nothing +pickFactory _ = Nothing findAaveFactory :: HasBlockchainActions s => Aave -> Contract w s Text (StateOutput Factory) findAaveFactory aave@Aave{..} = findOutputBy aave aaveProtocolInst pickFactory @@ -176,7 +176,7 @@ makeUserHandle toAction = pickUser :: AaveDatum -> Maybe UserConfig pickUser (User user) = Just user -pickUser _ = Nothing +pickUser _ = Nothing putUser :: (HasBlockchainActions s) => Aave -> UserConfig -> Contract w s Text UserConfig putUser = putState $ makeUserHandle Core.CreateUser From 719d004f6616e647d282d8be637292d3df17da55 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 14 May 2021 14:58:13 +0700 Subject: [PATCH 025/169] add inlineable pragmas --- MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs | 1 + MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 1 + MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs | 1 + 3 files changed, 3 insertions(+) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index f9c29e283..2f3ef443f 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -41,6 +41,7 @@ import PlutusTx.Prelude hiding (Semigroup (..)) import Prelude (Semigroup (..)) import qualified Prelude +{-# INLINABLE validator #-} -- TODO: check that ScriptContext has enough liquidity validator :: AssetClass -> ScriptContext -> Bool validator _ _ = True diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 2957fe4a9..c139a11c0 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -94,6 +94,7 @@ instance Scripts.ScriptType AaveScript where type instance RedeemerType AaveScript = AaveAction type instance DatumType AaveScript = AaveDatum +{-# INLINABLE makeAaveValidator #-} -- Main validator -- Each state field must have one or more associated actions(Redeemer types), -- produced on state update, which are then validated here diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs index 11ffe6f2e..bda06bf37 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs @@ -10,6 +10,7 @@ import qualified Plutus.V1.Ledger.Scripts as Scripts import Plutus.V1.Ledger.Value (TokenName, Value) import qualified PlutusTx +{-# INLINABLE validator #-} validator :: TokenName -> ScriptContext -> Bool validator _ _ = True From ae461b435fcc57ecfb34202ac61a59c67f022e56 Mon Sep 17 00:00:00 2001 From: megakaban Date: Fri, 14 May 2021 15:48:39 +0700 Subject: [PATCH 026/169] Finish burnATokensFrom - send liqudity to the caller --- MetaLamp/lending-pool/pab/Main.hs | 4 +-- .../src/Plutus/Contracts/AToken.hs | 34 +++++++++++++++---- .../lending-pool/src/Plutus/Contracts/Core.hs | 3 +- .../src/Plutus/Contracts/State.hs | 1 - 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index a420b288d..7a73fd0a5 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -111,8 +111,6 @@ main = void $ Simulator.runSimulationWith handlers $ do let userCid = cids Map.! Wallet 2 sender = pubKeyHash . walletPubKey $ Wallet 2 - Simulator.logString @(Builtin AaveContracts) $ "Send:" <> show sender - _ <- Simulator.callEndpointOnInstance userCid "deposit" $ Aave.DepositParams { Aave.dpAsset = head testAssets, Aave.dpOnBehalfOf = sender, Aave.dpAmount = 100 } @@ -123,7 +121,7 @@ main = void $ Simulator.runSimulationWith handlers $ do _ <- Simulator.callEndpointOnInstance userCid "withdraw" $ - Aave.WithdrawParams { Aave.wpAsset = head testAssets, Aave.wpTo = sender, Aave.wpFrom = sender, Aave.wpAmount = 50 } + Aave.WithdrawParams { Aave.wpAsset = head testAssets, Aave.wpTo = sender, Aave.wpFrom = sender, Aave.wpAmount = 30 } flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of Success (Monoid.Last (Just (Right Aave.Withdrawn))) -> Just () _ -> Nothing diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 2f3ef443f..1e782958c 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -18,8 +18,11 @@ module Plutus.Contracts.AToken where +import Control.Monad (void) import Data.ByteString (ByteString) +import qualified Data.Map as Map import Data.Text (Text) +import Data.Void (Void) import Ledger hiding (singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints @@ -29,6 +32,8 @@ import qualified Ledger.Typed.Scripts as Scripts import Plutus.Contract import Plutus.Contracts.Core (Aave, LendingPool (..)) import qualified Plutus.Contracts.Core as Core +import qualified Plutus.Contracts.FungibleToken as FungibleToken +import qualified Plutus.Contracts.State as State import Plutus.V1.Ledger.Contexts (ScriptContext, scriptCurrencySymbol) import qualified Plutus.V1.Ledger.Scripts as Scripts @@ -74,15 +79,30 @@ forgeATokensFrom aave reserve pkh amount = do burnATokensFrom :: (HasBlockchainActions s) => Aave -> LendingPool -> PubKeyHash -> Integer -> Contract w s Text () burnATokensFrom aave reserve pkh amount = do - logInfo @String "BURN" - let script = Core.aaveInstance aave - policy = makeLiquidityPolicy (lpCurrency reserve) + let asset = lpCurrency reserve + utxos <- + Map.filter ((> 0) . flip assetClassValueOf asset . txOutValue . txOutTxOut) + <$> utxoAt (Core.aaveAddress aave) + + let aTokenAmount = amount + toPubKey = assetClassValue asset aTokenAmount + balance = mconcat . fmap (txOutValue . txOutTxOut) . map snd . Map.toList $ utxos + remainder = assetClassValueOf balance asset - aTokenAmount + script = Core.aaveInstance aave + policy = makeLiquidityPolicy asset + orefs = fst <$> Map.toList utxos lookups = Constraints.scriptInstanceLookups script - <> Constraints.monetaryPolicy policy + <> Constraints.otherScript (Core.aaveScript aave) + <> Constraints.unspentOutputs utxos <> Constraints.ownPubKeyHash pkh - aTokenAmount = amount -- / lpLiquidityIndex reserve -- TODO: how should we divide? - outValue = negate (assetClassValue (lpAToken reserve) aTokenAmount) - tx = mustForgeValue outValue <> mustPayToPubKey pkh (assetClassValue (lpCurrency reserve) aTokenAmount) + <> Constraints.monetaryPolicy policy + outValue = negate $ assetClassValue (lpAToken reserve) aTokenAmount + spendTx = mconcat $ fmap (\ref -> mustSpendScriptOutput ref $ Redeemer $ PlutusTx.toData Core.Withdraw) orefs + tx = mustForgeValue outValue + <> mustPayToPubKey pkh toPubKey + <> spendTx + <> mustPayToTheScript Core.Deposit (assetClassValue asset remainder) + ledgerTx <- submitTxConstraintsWith lookups tx _ <- awaitTxConfirmed $ txId ledgerTx pure () diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index c139a11c0..2b925234c 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -78,7 +78,7 @@ PlutusTx.unstableMakeIsData ''UserConfig PlutusTx.makeLift ''UserConfig type Factory = [LendingPoolId] -data AaveAction = CreateLendingPool LendingPool | UpdateLendingPool | CreateUser UserConfig | UpdateUser | Withdraw +data AaveAction = CreateLendingPool LendingPool | UpdateLendingPool | CreateUser UserConfig | UpdateUser | Withdraw | Payment deriving Show PlutusTx.unstableMakeIsData ''AaveAction @@ -109,6 +109,7 @@ makeAaveValidator _ _ UpdateLendingPool _ = True makeAaveValidator _ _ (CreateUser _) _ = True makeAaveValidator _ _ UpdateUser _ = True makeAaveValidator _ _ Withdraw _ = True +makeAaveValidator _ _ Payment _ = True makeAaveValidator _ _ _ _ = False aaveProtocolName :: TokenName diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index c6ed303c0..8124182b3 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -35,7 +35,6 @@ import qualified Ledger.Scripts as Scripts import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract import Plutus.Contract hiding (when) -import qualified Plutus.Contracts.AToken as AToken import Plutus.Contracts.Core (Aave (..), AaveAction (..), AaveDatum (..), Factory, LendingPool (..), From 1e361af59fda91d42ace3becf43044a915f88d5e Mon Sep 17 00:00:00 2001 From: megakaban Date: Fri, 14 May 2021 17:13:18 +0700 Subject: [PATCH 027/169] Rename LendingPool->Reserve, add Datum and Redeemer postfixes --- MetaLamp/lending-pool/pab/Main.hs | 8 +-- .../src/Plutus/Contracts/AToken.hs | 20 +++--- .../lending-pool/src/Plutus/Contracts/Core.hs | 62 ++++++++--------- .../src/Plutus/Contracts/Endpoints.hs | 65 +++++++++--------- .../src/Plutus/Contracts/State.hs | 67 +++++++++---------- 5 files changed, 109 insertions(+), 113 deletions(-) diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index 7a73fd0a5..4c7dfb9f4 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -139,11 +139,11 @@ main = void $ Simulator.runSimulationWith handlers $ do _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final factory: " <> show v - _ <- Simulator.callEndpointOnInstance userCid "pools" () - pools <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right (Aave.Pools pools)))) -> Just pools + _ <- Simulator.callEndpointOnInstance userCid "reserves" () + reserves <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right (Aave.Reserves reserves)))) -> Just reserves _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Final pools: " <> show pools + Simulator.logString @(Builtin AaveContracts) $ "Final reserves: " <> show reserves _ <- Simulator.callEndpointOnInstance userCid "poolFunds" () v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 1e782958c..08165a320 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -30,7 +30,7 @@ import Ledger.Constraints.TxConstraints as Constraints import Ledger.Typed.Scripts (MonetaryPolicy) import qualified Ledger.Typed.Scripts as Scripts import Plutus.Contract -import Plutus.Contracts.Core (Aave, LendingPool (..)) +import Plutus.Contracts.Core (Aave, Reserve (..)) import qualified Plutus.Contracts.Core as Core import qualified Plutus.Contracts.FungibleToken as FungibleToken import qualified Plutus.Contracts.State as State @@ -63,23 +63,23 @@ makeAToken asset = assetClass (scriptCurrencySymbol . makeLiquidityPolicy $ asse (_, tokenName) = unAssetClass asset aTokenName = "a" <> unTokenName tokenName -forgeATokensFrom :: (HasBlockchainActions s) => Aave -> LendingPool -> PubKeyHash -> Integer -> Contract w s Text () +forgeATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text () forgeATokensFrom aave reserve pkh amount = do let script = Core.aaveInstance aave - policy = makeLiquidityPolicy (lpCurrency reserve) + policy = makeLiquidityPolicy (rCurrency reserve) lookups = Constraints.scriptInstanceLookups script <> Constraints.monetaryPolicy policy <> Constraints.ownPubKeyHash pkh - aTokenAmount = amount -- / lpLiquidityIndex reserve -- TODO: how should we divide? - outValue = assetClassValue (lpAToken reserve) aTokenAmount + aTokenAmount = amount -- / rLiquidityIndex reserve -- TODO: how should we divide? + outValue = assetClassValue (rAToken reserve) aTokenAmount tx = mustForgeValue outValue <> mustPayToPubKey pkh outValue ledgerTx <- submitTxConstraintsWith lookups tx _ <- awaitTxConfirmed $ txId ledgerTx pure () -burnATokensFrom :: (HasBlockchainActions s) => Aave -> LendingPool -> PubKeyHash -> Integer -> Contract w s Text () +burnATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text () burnATokensFrom aave reserve pkh amount = do - let asset = lpCurrency reserve + let asset = rCurrency reserve utxos <- Map.filter ((> 0) . flip assetClassValueOf asset . txOutValue . txOutTxOut) <$> utxoAt (Core.aaveAddress aave) @@ -96,12 +96,12 @@ burnATokensFrom aave reserve pkh amount = do <> Constraints.unspentOutputs utxos <> Constraints.ownPubKeyHash pkh <> Constraints.monetaryPolicy policy - outValue = negate $ assetClassValue (lpAToken reserve) aTokenAmount - spendTx = mconcat $ fmap (\ref -> mustSpendScriptOutput ref $ Redeemer $ PlutusTx.toData Core.Withdraw) orefs + outValue = negate $ assetClassValue (rAToken reserve) aTokenAmount + spendTx = mconcat $ fmap (\ref -> mustSpendScriptOutput ref $ Redeemer $ PlutusTx.toData Core.WithdrawRedeemer) orefs tx = mustForgeValue outValue <> mustPayToPubKey pkh toPubKey <> spendTx - <> mustPayToTheScript Core.Deposit (assetClassValue asset remainder) + <> mustPayToTheScript Core.DepositDatum (assetClassValue asset remainder) ledgerTx <- submitTxConstraintsWith lookups tx _ <- awaitTxConfirmed $ txId ledgerTx diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 2b925234c..92dbb02b1 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -49,26 +49,24 @@ instance Prelude.Eq Aave where instance Prelude.Ord Aave where compare u v = Prelude.compare (aaveProtocolInst u) (aaveProtocolInst v) -type LendingPoolId = AssetClass - -type AnyAddress = BS.ByteString - -data LendingPool = LendingPool - { lpCurrency :: LendingPoolId, - lpAToken :: AssetClass, - lpAmount :: Integer, - lpDebtToken :: AssetClass, - lpLiquidityIndex :: Integer +type ReserveId = AssetClass + +data Reserve = Reserve + { rCurrency :: ReserveId, + rAToken :: AssetClass, + rAmount :: Integer, + rDebtToken :: AssetClass, + rLiquidityIndex :: Integer } deriving stock (Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) -PlutusTx.unstableMakeIsData ''LendingPool -PlutusTx.makeLift ''LendingPool +PlutusTx.unstableMakeIsData ''Reserve +PlutusTx.makeLift ''Reserve data UserConfig = UserConfig { ucAddress :: PubKeyHash, - ucReserveId :: LendingPoolId, + ucReserveId :: ReserveId, ucUsingAsCollateral :: Bool } deriving stock (Show, Generic) @@ -77,21 +75,26 @@ data UserConfig = UserConfig PlutusTx.unstableMakeIsData ''UserConfig PlutusTx.makeLift ''UserConfig -type Factory = [LendingPoolId] -data AaveAction = CreateLendingPool LendingPool | UpdateLendingPool | CreateUser UserConfig | UpdateUser | Withdraw | Payment +type Factory = [ReserveId] +data AaveRedeemer = + CreateReserveRedeemer Reserve + | UpdateReserveRedeemer + | CreateUserRedeemer UserConfig + | UpdateUserRedeemer + | WithdrawRedeemer deriving Show -PlutusTx.unstableMakeIsData ''AaveAction -PlutusTx.makeLift ''AaveAction +PlutusTx.unstableMakeIsData ''AaveRedeemer +PlutusTx.makeLift ''AaveRedeemer -data AaveDatum = Factory Factory | Pool LendingPool | User UserConfig | Deposit deriving stock (Show) +data AaveDatum = FactoryDatum Factory | ReserveDatum Reserve | UserConfigDatum UserConfig | DepositDatum deriving stock (Show) PlutusTx.unstableMakeIsData ''AaveDatum PlutusTx.makeLift ''AaveDatum data AaveScript instance Scripts.ScriptType AaveScript where - type instance RedeemerType AaveScript = AaveAction + type instance RedeemerType AaveScript = AaveRedeemer type instance DatumType AaveScript = AaveDatum {-# INLINABLE makeAaveValidator #-} @@ -101,16 +104,15 @@ instance Scripts.ScriptType AaveScript where -- TODO: write validations makeAaveValidator :: Aave -> AaveDatum - -> AaveAction + -> AaveRedeemer -> ScriptContext -> Bool -makeAaveValidator _ _ (CreateLendingPool _) _ = True -makeAaveValidator _ _ UpdateLendingPool _ = True -makeAaveValidator _ _ (CreateUser _) _ = True -makeAaveValidator _ _ UpdateUser _ = True -makeAaveValidator _ _ Withdraw _ = True -makeAaveValidator _ _ Payment _ = True -makeAaveValidator _ _ _ _ = False +makeAaveValidator _ _ (CreateReserveRedeemer _) _ = True +makeAaveValidator _ _ UpdateReserveRedeemer _ = True +makeAaveValidator _ _ (CreateUserRedeemer _) _ = True +makeAaveValidator _ _ UpdateUserRedeemer _ = True +makeAaveValidator _ _ WithdrawRedeemer _ = True +makeAaveValidator _ _ _ _ = False aaveProtocolName :: TokenName aaveProtocolName = "Aave" @@ -121,7 +123,7 @@ aaveInstance aave = Scripts.validator @AaveScript `PlutusTx.applyCode` PlutusTx.liftCode aave) $$(PlutusTx.compile [|| wrap ||]) where - wrap = Scripts.wrapValidator @AaveDatum @AaveAction + wrap = Scripts.wrapValidator @AaveDatum @AaveRedeemer aaveScript :: Aave -> Validator aaveScript = Scripts.validatorScript . aaveInstance @@ -166,6 +168,6 @@ makeStateCurrency tokenName = scriptCurrencySymbol . makeStatePolicy tokenName makeStateToken :: TokenName -> Aave -> AssetClass makeStateToken tokenName = flip assetClass tokenName . makeStateCurrency tokenName -poolStateToken, userStateToken :: Aave -> AssetClass -poolStateToken = makeStateToken "aaveLendingPool" +reserveStateToken, userStateToken :: Aave -> AssetClass +reserveStateToken = makeStateToken "aaveReserve" userStateToken = makeStateToken "aaveUser" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 17004ee75..478d0c526 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -35,10 +35,9 @@ import Plutus.Contract hiding (when) -- TODO remove that dep Plutus.Contracts.Currency (?) import qualified Data.ByteString as BS import qualified Plutus.Contracts.AToken as AToken -import Plutus.Contracts.Core (Aave, AaveAction (..), - AaveDatum (..), Factory, - LendingPool (..), - LendingPoolId, +import Plutus.Contracts.Core (Aave, AaveDatum (..), + AaveRedeemer (..), Factory, + Reserve (..), ReserveId, UserConfig (..)) import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency @@ -55,8 +54,6 @@ import Prelude (Semigroup (..)) import qualified Prelude import Text.Printf (printf) -errorHandler t = logInfo @Text ("Error submiting the transaction!: " <> t) - newtype CreateParams = CreateParams { cpAsset :: AssetClass } @@ -65,14 +62,14 @@ newtype CreateParams = PlutusTx.makeLift ''CreateParams -createPool :: CreateParams -> LendingPool -createPool CreateParams {..} = - LendingPool - { lpCurrency = cpAsset, - lpAmount = 0, - lpAToken = AToken.makeAToken cpAsset, - lpDebtToken = cpAsset, - lpLiquidityIndex = 1 } +createReserve :: CreateParams -> Reserve +createReserve CreateParams {..} = + Reserve + { rCurrency = cpAsset, + rAmount = 0, + rAToken = AToken.makeAToken cpAsset, + rDebtToken = cpAsset, + rLiquidityIndex = 1 } start :: HasBlockchainActions s => [CreateParams] -> Contract w s Text Aave start params = do @@ -81,13 +78,13 @@ start params = do mapError (pack . show @Currency.CurrencyError) $ Currency.forgeContract pkh [(Core.aaveProtocolName, 1)] let aave = Core.aave aaveToken - let pools = fmap createPool params + let reserves = fmap createReserve params let factoryCoin = assetClass aaveToken Core.aaveProtocolName inst = Core.aaveInstance aave - tx = mustPayToTheScript (Factory (fmap lpCurrency pools)) $ assetClassValue factoryCoin 1 + tx = mustPayToTheScript (Core.FactoryDatum (fmap rCurrency reserves)) $ assetClassValue factoryCoin 1 ledgerTx <- submitTxConstraints inst tx void $ awaitTxConfirmed $ txId ledgerTx - traverse_ (State.putPool aave) pools + traverse_ (State.putReserve aave) reserves logInfo @String $ printf "started Aave %s at address %s" (show aave) (show $ Core.aaveAddress aave) pure aave @@ -105,11 +102,11 @@ type AaveOwnerSchema = factory :: forall w s. HasBlockchainActions s => Aave -> Contract w s Text Factory factory = fmap soDatum . State.findAaveFactory -pools :: forall w s. HasBlockchainActions s => Aave -> Contract w s Text [LendingPool] -pools aave = Prelude.fmap soDatum <$> State.findOutputsBy aave (Core.poolStateToken aave) State.pickPool +reserves :: forall w s. HasBlockchainActions s => Aave -> Contract w s Text [Reserve] +reserves aave = Prelude.fmap soDatum <$> State.findOutputsBy aave (Core.reserveStateToken aave) State.pickReserve users :: forall w s. HasBlockchainActions s => Aave -> Contract w s Text [UserConfig] -users aave = Prelude.fmap soDatum <$> State.findOutputsBy aave (Core.userStateToken aave) State.pickUser +users aave = Prelude.fmap soDatum <$> State.findOutputsBy aave (Core.userStateToken aave) State.pickUserConfig valueAt :: HasBlockchainActions s => Address -> Contract w s Text Value valueAt address = do @@ -139,29 +136,27 @@ PlutusTx.makeLift ''DepositParams deposit :: (HasBlockchainActions s) => Aave -> DepositParams -> Contract w s Text () deposit aave DepositParams {..} = do - reserveOutput <- State.findAavePool aave dpAsset + reserveOutput <- State.findAaveReserve aave dpAsset let reserve = soDatum reserveOutput lookups = Constraints.ownPubKeyHash dpOnBehalfOf <> Constraints.scriptInstanceLookups (Core.aaveInstance aave) - outValue = assetClassValue (lpCurrency reserve) dpAmount - tx = mustPayToTheScript Core.Deposit outValue + outValue = assetClassValue (rCurrency reserve) dpAmount + tx = mustPayToTheScript Core.DepositDatum outValue ledgerTx <- submitTxConstraintsWith lookups tx _ <- awaitTxConfirmed $ txId ledgerTx - logInfo @String $ "HASH " <> show dpOnBehalfOf - - wasZeroBalance <- (== 0) <$> balanceAt dpOnBehalfOf (lpAToken reserve) + wasZeroBalance <- (== 0) <$> balanceAt dpOnBehalfOf (rAToken reserve) _ <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount when wasZeroBalance $ do - userOutputs <- State.findOutputsBy aave (Core.userStateToken aave) State.pickUser + userOutputs <- State.findOutputsBy aave (Core.userStateToken aave) State.pickUserConfig case userOutputs of [] -> void $ - State.putUser aave $ UserConfig { ucAddress = dpOnBehalfOf, ucReserveId = lpCurrency reserve, ucUsingAsCollateral = True } + State.putUser aave $ UserConfig { ucAddress = dpOnBehalfOf, ucReserveId = rCurrency reserve, ucUsingAsCollateral = True } [userOutput] -> void $ State.updateUser aave $ Prelude.fmap (\u -> u { ucUsingAsCollateral = True }) userOutput _ -> throwError "Invalid state: multiple users" - void $ State.updatePool aave $ Prelude.fmap (\r -> r { lpAmount = lpAmount r + dpAmount }) reserveOutput + void $ State.updateReserve aave $ Prelude.fmap (\r -> r { rAmount = rAmount r + dpAmount }) reserveOutput data WithdrawParams = WithdrawParams { @@ -178,10 +173,10 @@ PlutusTx.makeLift ''WithdrawParams withdraw :: (HasBlockchainActions s) => Aave -> WithdrawParams -> Contract w s Text () withdraw aave WithdrawParams {..} = do - reserveOutput <- State.findAavePool aave wpAsset + reserveOutput <- State.findAaveReserve aave wpAsset let reserve = soDatum reserveOutput - balance <- balanceAt wpFrom (lpAToken reserve) + balance <- balanceAt wpFrom (rAToken reserve) when (wpAmount == balance) $ do userOutput <- State.findAaveUser aave wpFrom wpAsset void $ @@ -189,7 +184,7 @@ withdraw aave WithdrawParams {..} = do _ <- AToken.burnATokensFrom aave reserve wpTo wpAmount - void $ State.updatePool aave $ Prelude.fmap (\r -> r { lpAmount = lpAmount r - wpAmount }) reserveOutput + void $ State.updateReserve aave $ Prelude.fmap (\r -> r { rAmount = rAmount r - wpAmount }) reserveOutput type AaveUserSchema = BlockchainActions @@ -198,7 +193,7 @@ type AaveUserSchema = .\/ Endpoint "fundsAt" PubKeyHash .\/ Endpoint "poolFunds" () .\/ Endpoint "factory" () - .\/ Endpoint "pools" () + .\/ Endpoint "reserves" () .\/ Endpoint "users" () data UserContractState = Created @@ -209,7 +204,7 @@ data UserContractState = Created | FundsAt Value | PoolFunds Value | FactoryEndpoint Factory - | Pools [LendingPool] + | Reserves [Reserve] | Users [UserConfig] deriving (Show, Generic, FromJSON, ToJSON) @@ -220,7 +215,7 @@ userEndpoints aa = forever $ `select` f (Proxy @"fundsAt") FundsAt (\_ pkh -> fundsAt pkh) `select` f (Proxy @"poolFunds") PoolFunds (\aave () -> poolFunds aave) `select` f (Proxy @"factory") FactoryEndpoint (\aave () -> factory aave) - `select` f (Proxy @"pools") Pools (\aave () -> pools aave) + `select` f (Proxy @"reserves") Reserves (\aave () -> reserves aave) `select` f (Proxy @"users") Users (\aave () -> users aave) where f :: forall l a p. diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 8124182b3..5650dce5a 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -35,10 +35,9 @@ import qualified Ledger.Scripts as Scripts import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract import Plutus.Contract hiding (when) -import Plutus.Contracts.Core (Aave (..), AaveAction (..), - AaveDatum (..), Factory, - LendingPool (..), - LendingPoolId, +import Plutus.Contracts.Core (Aave (..), AaveDatum (..), + AaveRedeemer (..), Factory, + Reserve (..), ReserveId, UserConfig (..)) import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency @@ -94,26 +93,26 @@ findOutputBy aave stateToken mapDatum = do xs -> throwError $ "Multiple " <> stateName <> " found" pickFactory :: AaveDatum -> Maybe Factory -pickFactory (Factory f) = Just f -pickFactory _ = Nothing +pickFactory (FactoryDatum f) = Just f +pickFactory _ = Nothing findAaveFactory :: HasBlockchainActions s => Aave -> Contract w s Text (StateOutput Factory) findAaveFactory aave@Aave{..} = findOutputBy aave aaveProtocolInst pickFactory -findAavePool :: HasBlockchainActions s => Aave -> LendingPoolId -> Contract w s Text (StateOutput LendingPool) -findAavePool aave poolId = findOutputBy aave (Core.poolStateToken aave) mapState +findAaveReserve :: HasBlockchainActions s => Aave -> ReserveId -> Contract w s Text (StateOutput Reserve) +findAaveReserve aave reserveId = findOutputBy aave (Core.reserveStateToken aave) mapState where - mapState (Pool lp) = - if lpCurrency lp == poolId - then Just lp + mapState (Core.ReserveDatum r) = + if rCurrency r == reserveId + then Just r else Nothing mapState _ = Nothing -findAaveUser :: HasBlockchainActions s => Aave -> PubKeyHash -> LendingPoolId -> Contract w s Text (StateOutput UserConfig) -findAaveUser aave userAddress poolId = findOutputBy aave (Core.userStateToken aave) mapState +findAaveUser :: HasBlockchainActions s => Aave -> PubKeyHash -> ReserveId -> Contract w s Text (StateOutput UserConfig) +findAaveUser aave userAddress reserveId = findOutputBy aave (Core.userStateToken aave) mapState where - mapState (User user) = - if ucAddress user == userAddress && ucReserveId user == poolId + mapState (UserConfigDatum user) = + if ucAddress user == userAddress && ucReserveId user == reserveId then Just user else Nothing mapState _ = Nothing @@ -121,7 +120,7 @@ findAaveUser aave userAddress poolId = findOutputBy aave (Core.userStateToken aa data StateHandle a = StateHandle { getToken :: Aave -> AssetClass, toDatum :: a -> AaveDatum, - toAction :: a -> AaveAction + toAction :: a -> AaveRedeemer } putState :: (HasBlockchainActions s) => StateHandle a -> Aave -> a -> Contract w s Text a @@ -147,38 +146,38 @@ updateState StateHandle{..} aave (StateOutput oref o datum) = do _ <- awaitTxConfirmed $ txId ledgerTx pure datum -makePoolHandle :: (LendingPool -> AaveAction) -> StateHandle LendingPool -makePoolHandle toAction = +makeReserveHandle :: (Reserve -> AaveRedeemer) -> StateHandle Reserve +makeReserveHandle toAction = StateHandle { - getToken = Core.poolStateToken, - toDatum = Pool, + getToken = Core.reserveStateToken, + toDatum = Core.ReserveDatum, toAction = toAction } -pickPool :: AaveDatum -> Maybe LendingPool -pickPool (Pool lp) = Just lp -pickPool _ = Nothing +pickReserve :: AaveDatum -> Maybe Reserve +pickReserve (Core.ReserveDatum r) = Just r +pickReserve _ = Nothing -putPool :: (HasBlockchainActions s) => Aave -> LendingPool -> Contract w s Text LendingPool -putPool = putState $ makePoolHandle Core.CreateLendingPool +putReserve :: (HasBlockchainActions s) => Aave -> Reserve -> Contract w s Text Reserve +putReserve = putState $ makeReserveHandle Core.CreateReserveRedeemer -updatePool :: (HasBlockchainActions s) => Aave -> StateOutput LendingPool -> Contract w s Text LendingPool -updatePool = updateState $ makePoolHandle (const Core.UpdateLendingPool) +updateReserve :: (HasBlockchainActions s) => Aave -> StateOutput Reserve -> Contract w s Text Reserve +updateReserve = updateState $ makeReserveHandle (const Core.UpdateReserveRedeemer) -makeUserHandle :: (UserConfig -> AaveAction) -> StateHandle UserConfig +makeUserHandle :: (UserConfig -> AaveRedeemer) -> StateHandle UserConfig makeUserHandle toAction = StateHandle { getToken = Core.userStateToken, - toDatum = Core.User, + toDatum = Core.UserConfigDatum, toAction = toAction } -pickUser :: AaveDatum -> Maybe UserConfig -pickUser (User user) = Just user -pickUser _ = Nothing +pickUserConfig :: AaveDatum -> Maybe UserConfig +pickUserConfig (Core.UserConfigDatum user) = Just user +pickUserConfig _ = Nothing putUser :: (HasBlockchainActions s) => Aave -> UserConfig -> Contract w s Text UserConfig -putUser = putState $ makeUserHandle Core.CreateUser +putUser = putState $ makeUserHandle Core.CreateUserRedeemer updateUser :: (HasBlockchainActions s) => Aave -> StateOutput UserConfig -> Contract w s Text UserConfig -updateUser = updateState $ makeUserHandle (const Core.UpdateUser) +updateUser = updateState $ makeUserHandle (const Core.UpdateUserRedeemer) From 2214941f14ec4361b39e728e4d091430ec12659e Mon Sep 17 00:00:00 2001 From: megakaban Date: Fri, 14 May 2021 17:52:55 +0700 Subject: [PATCH 028/169] Split burnATokensFrom into two submits --- .../src/Plutus/Contracts/AToken.hs | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 08165a320..4eb77b452 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -80,29 +80,33 @@ forgeATokensFrom aave reserve pkh amount = do burnATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text () burnATokensFrom aave reserve pkh amount = do let asset = rCurrency reserve + aTokenAmount = amount + script = Core.aaveInstance aave + policy = makeLiquidityPolicy asset + burnLookups = Constraints.scriptInstanceLookups script + <> Constraints.otherScript (Core.aaveScript aave) + <> Constraints.ownPubKeyHash pkh + <> Constraints.monetaryPolicy policy + outValue = negate $ assetClassValue (rAToken reserve) aTokenAmount + burnTx = mustForgeValue outValue + ledgerTx <- submitTxConstraintsWith burnLookups burnTx + _ <- awaitTxConfirmed $ txId ledgerTx + utxos <- Map.filter ((> 0) . flip assetClassValueOf asset . txOutValue . txOutTxOut) <$> utxoAt (Core.aaveAddress aave) - - let aTokenAmount = amount - toPubKey = assetClassValue asset aTokenAmount - balance = mconcat . fmap (txOutValue . txOutTxOut) . map snd . Map.toList $ utxos + let balance = mconcat . fmap (txOutValue . txOutTxOut) . map snd . Map.toList $ utxos remainder = assetClassValueOf balance asset - aTokenAmount - script = Core.aaveInstance aave - policy = makeLiquidityPolicy asset - orefs = fst <$> Map.toList utxos - lookups = Constraints.scriptInstanceLookups script + withdrawLookups = Constraints.scriptInstanceLookups script <> Constraints.otherScript (Core.aaveScript aave) <> Constraints.unspentOutputs utxos <> Constraints.ownPubKeyHash pkh - <> Constraints.monetaryPolicy policy - outValue = negate $ assetClassValue (rAToken reserve) aTokenAmount + orefs = fst <$> Map.toList utxos spendTx = mconcat $ fmap (\ref -> mustSpendScriptOutput ref $ Redeemer $ PlutusTx.toData Core.WithdrawRedeemer) orefs - tx = mustForgeValue outValue - <> mustPayToPubKey pkh toPubKey + withdrawTx = mustPayToPubKey pkh (assetClassValue asset aTokenAmount) <> spendTx <> mustPayToTheScript Core.DepositDatum (assetClassValue asset remainder) - - ledgerTx <- submitTxConstraintsWith lookups tx + ledgerTx <- submitTxConstraintsWith withdrawLookups withdrawTx _ <- awaitTxConfirmed $ txId ledgerTx + pure () From 70b92e6bd62712a974a77bcc7b78fd5390912945 Mon Sep 17 00:00:00 2001 From: megakaban Date: Fri, 14 May 2021 17:58:05 +0700 Subject: [PATCH 029/169] Use IsString instance to simplify toAsset definition --- MetaLamp/lending-pool/pab/Main.hs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index 4c7dfb9f4..f9fb5b04f 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -58,13 +58,12 @@ import Wallet.Emulator.Types (Wallet (..), walletPubKey) wallets :: [Wallet] wallets = [Wallet i | i <- [1 .. 4]] -testCurrencyNames :: [BS.ByteString] +testCurrencyNames :: [TokenName] testCurrencyNames = ["MOGUS"] -toAsset :: BS.ByteString -> AssetClass -toAsset rawName = +toAsset :: TokenName -> AssetClass +toAsset tokenName = assetClass (scriptCurrencySymbol . FungibleToken.makeLiquidityPolicy $ tokenName) tokenName - where tokenName = Value.tokenName rawName testAssets :: [AssetClass] testAssets = fmap toAsset testCurrencyNames From c7614acc7da80f1fb4f9c510faa70602ca550e4f Mon Sep 17 00:00:00 2001 From: megakaban Date: Mon, 17 May 2021 19:34:30 +0700 Subject: [PATCH 030/169] Fix state validator, pass through aave token --- .../lending-pool/src/Plutus/Contracts/Core.hs | 8 +++---- .../src/Plutus/Contracts/State.hs | 24 ++++++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 92dbb02b1..67b7c86c5 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -137,11 +137,10 @@ aaveAddress = Ledger.scriptAddress . aaveScript aave :: CurrencySymbol -> Aave aave protocol = Aave (assetClass protocol aaveProtocolName) --- State forging validator/policy --- TODO: Fix +-- State token can be only be forged either when input has aave token(first-time creation) +-- or any of the state tokens(modification), assuming that state token was created with aave token at some point validateStateForging :: Aave -> TokenName -> ScriptContext -> Bool -validateStateForging aave tn ctx = True -{-case [ i +validateStateForging aave tn ctx = case [ i | i <- txInfoInputs $ scriptContextTxInfo ctx , let v = valueWithin i , (assetClassValueOf v aaveToken == 1) || @@ -154,7 +153,6 @@ validateStateForging aave tn ctx = True aaveToken = aaveProtocolInst aave stateToken = assetClass (ownCurrencySymbol ctx) tn valueWithin = txOutValue . txInInfoResolved --} makeStatePolicy :: TokenName -> Aave -> MonetaryPolicy makeStatePolicy tokenName aave = mkMonetaryPolicyScript $ diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 5650dce5a..5d9b55c06 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -120,19 +120,25 @@ findAaveUser aave userAddress reserveId = findOutputBy aave (Core.userStateToken data StateHandle a = StateHandle { getToken :: Aave -> AssetClass, toDatum :: a -> AaveDatum, - toAction :: a -> AaveRedeemer + toRedeemer :: a -> AaveRedeemer } putState :: (HasBlockchainActions s) => StateHandle a -> Aave -> a -> Contract w s Text a -putState StateHandle{..} aave datum = do +putState StateHandle{..} aave newState = do + StateOutput oref otx lps <- findAaveFactory aave + let stateToken = getToken aave lookups = Constraints.scriptInstanceLookups (Core.aaveInstance aave) <> Constraints.monetaryPolicy (Core.makeStatePolicy (Prelude.snd . unAssetClass $ stateToken) aave) + <> Constraints.otherScript (Core.aaveScript aave) + <> Constraints.unspentOutputs (Map.singleton oref otx) tx = mustForgeValue (assetClassValue stateToken 1) - <> mustPayToTheScript (toDatum datum) (assetClassValue stateToken 1) + <> mustPayToTheScript (toDatum newState) (assetClassValue stateToken 1) + <> mustPayToTheScript (Core.FactoryDatum lps) (assetClassValue (Core.aaveProtocolInst aave) 1) + <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ toRedeemer newState) ledgerTx <- submitTxConstraintsWith lookups tx _ <- awaitTxConfirmed $ txId ledgerTx - pure datum + pure newState updateState :: (HasBlockchainActions s) => StateHandle a -> Aave -> StateOutput a -> Contract w s Text a updateState StateHandle{..} aave (StateOutput oref o datum) = do @@ -141,17 +147,17 @@ updateState StateHandle{..} aave (StateOutput oref o datum) = do <> Constraints.otherScript (Core.aaveScript aave) <> Constraints.unspentOutputs (Map.singleton oref o) tx = mustPayToTheScript (toDatum datum) (assetClassValue stateToken 1) - <> mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData (toAction datum)) + <> mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData (toRedeemer datum)) ledgerTx <- submitTxConstraintsWith lookups tx _ <- awaitTxConfirmed $ txId ledgerTx pure datum makeReserveHandle :: (Reserve -> AaveRedeemer) -> StateHandle Reserve -makeReserveHandle toAction = +makeReserveHandle toRedeemer = StateHandle { getToken = Core.reserveStateToken, toDatum = Core.ReserveDatum, - toAction = toAction + toRedeemer = toRedeemer } pickReserve :: AaveDatum -> Maybe Reserve @@ -165,11 +171,11 @@ updateReserve :: (HasBlockchainActions s) => Aave -> StateOutput Reserve -> Cont updateReserve = updateState $ makeReserveHandle (const Core.UpdateReserveRedeemer) makeUserHandle :: (UserConfig -> AaveRedeemer) -> StateHandle UserConfig -makeUserHandle toAction = +makeUserHandle toRedeemer = StateHandle { getToken = Core.userStateToken, toDatum = Core.UserConfigDatum, - toAction = toAction + toRedeemer = toRedeemer } pickUserConfig :: AaveDatum -> Maybe UserConfig From 109328c1bf4df04aa889085c026bb589280838b3 Mon Sep 17 00:00:00 2001 From: megakaban Date: Mon, 17 May 2021 23:12:17 +0700 Subject: [PATCH 031/169] Abstract away state management from aave implementation --- MetaLamp/lending-pool/plutus-starter.cabal | 2 +- .../lending-pool/src/Plutus/Contracts/Core.hs | 33 ----- .../src/Plutus/Contracts/Endpoints.hs | 16 +-- .../src/Plutus/Contracts/State.hs | 131 ++++++------------ .../lending-pool/src/Plutus/State/Select.hs | 87 ++++++++++++ .../lending-pool/src/Plutus/State/Update.hs | 120 ++++++++++++++++ 6 files changed, 259 insertions(+), 130 deletions(-) create mode 100644 MetaLamp/lending-pool/src/Plutus/State/Select.hs create mode 100644 MetaLamp/lending-pool/src/Plutus/State/Update.hs diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index a7346d46a..7ad0b89a2 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -23,7 +23,7 @@ maintainer: Your email library exposed-modules: - Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.State + Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.State Plutus.State.Select Plutus.State.Update build-depends: base >= 4.9 && < 5, aeson, diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 67b7c86c5..9948c682f 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -136,36 +136,3 @@ aaveAddress = Ledger.scriptAddress . aaveScript aave :: CurrencySymbol -> Aave aave protocol = Aave (assetClass protocol aaveProtocolName) - --- State token can be only be forged either when input has aave token(first-time creation) --- or any of the state tokens(modification), assuming that state token was created with aave token at some point -validateStateForging :: Aave -> TokenName -> ScriptContext -> Bool -validateStateForging aave tn ctx = case [ i - | i <- txInfoInputs $ scriptContextTxInfo ctx - , let v = valueWithin i - , (assetClassValueOf v aaveToken == 1) || - (assetClassValueOf v stateToken == 1) - ] of - [_] -> True - [_, _] -> True - _ -> traceError "State forging without Aave input" - where - aaveToken = aaveProtocolInst aave - stateToken = assetClass (ownCurrencySymbol ctx) tn - valueWithin = txOutValue . txInInfoResolved - -makeStatePolicy :: TokenName -> Aave -> MonetaryPolicy -makeStatePolicy tokenName aave = mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| \u t -> Scripts.wrapMonetaryPolicy (validateStateForging u t) ||]) - `PlutusTx.applyCode` PlutusTx.liftCode aave - `PlutusTx.applyCode` PlutusTx.liftCode tokenName - -makeStateCurrency :: TokenName -> Aave -> CurrencySymbol -makeStateCurrency tokenName = scriptCurrencySymbol . makeStatePolicy tokenName - -makeStateToken :: TokenName -> Aave -> AssetClass -makeStateToken tokenName = flip assetClass tokenName . makeStateCurrency tokenName - -reserveStateToken, userStateToken :: Aave -> AssetClass -reserveStateToken = makeStateToken "aaveReserve" -userStateToken = makeStateToken "aaveUser" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 478d0c526..50544b8ff 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -42,8 +42,8 @@ import Plutus.Contracts.Core (Aave, AaveDatum (..), import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken -import Plutus.Contracts.State (StateOutput (..)) import qualified Plutus.Contracts.State as State +import Plutus.State.Select (StateOutput (..)) import Plutus.V1.Ledger.Ada (adaValueOf, lovelaceValueOf) import qualified Plutus.V1.Ledger.Address as Addr import Plutus.V1.Ledger.Value as Value @@ -99,14 +99,14 @@ type AaveOwnerSchema = BlockchainActions .\/ Endpoint "start" () -factory :: forall w s. HasBlockchainActions s => Aave -> Contract w s Text Factory +factory :: HasBlockchainActions s => Aave -> Contract w s Text Factory factory = fmap soDatum . State.findAaveFactory -reserves :: forall w s. HasBlockchainActions s => Aave -> Contract w s Text [Reserve] -reserves aave = Prelude.fmap soDatum <$> State.findOutputsBy aave (Core.reserveStateToken aave) State.pickReserve +reserves :: HasBlockchainActions s => Aave -> Contract w s Text [Reserve] +reserves aave = Prelude.fmap soDatum <$> State.findOutputsBy aave (State.reserveStateToken aave) State.pickReserve -users :: forall w s. HasBlockchainActions s => Aave -> Contract w s Text [UserConfig] -users aave = Prelude.fmap soDatum <$> State.findOutputsBy aave (Core.userStateToken aave) State.pickUserConfig +users :: HasBlockchainActions s => Aave -> Contract w s Text [UserConfig] +users aave = Prelude.fmap soDatum <$> State.findOutputsBy aave (State.userStateToken aave) State.pickUserConfig valueAt :: HasBlockchainActions s => Address -> Contract w s Text Value valueAt address = do @@ -119,7 +119,7 @@ fundsAt pkh = valueAt (pubKeyHashAddress pkh) balanceAt :: HasBlockchainActions s => PubKeyHash -> AssetClass -> Contract w s Text Integer balanceAt pkh asset = flip assetClassValueOf asset <$> fundsAt pkh -poolFunds :: forall w s. HasBlockchainActions s => Aave -> Contract w s Text Value +poolFunds :: HasBlockchainActions s => Aave -> Contract w s Text Value poolFunds aave = valueAt (Core.aaveAddress aave) data DepositParams = @@ -148,7 +148,7 @@ deposit aave DepositParams {..} = do wasZeroBalance <- (== 0) <$> balanceAt dpOnBehalfOf (rAToken reserve) _ <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount when wasZeroBalance $ do - userOutputs <- State.findOutputsBy aave (Core.userStateToken aave) State.pickUserConfig + userOutputs <- State.findOutputsBy aave (State.userStateToken aave) State.pickUserConfig case userOutputs of [] -> void $ State.putUser aave $ UserConfig { ucAddress = dpOnBehalfOf, ucReserveId = rCurrency reserve, ucUsingAsCollateral = True } diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 5d9b55c06..6e8310959 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -36,12 +36,18 @@ import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract import Plutus.Contract hiding (when) import Plutus.Contracts.Core (Aave (..), AaveDatum (..), - AaveRedeemer (..), Factory, + AaveRedeemer (..), + AaveScript, Factory, Reserve (..), ReserveId, UserConfig (..)) import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken +import Plutus.State.Select (StateOutput (..)) +import qualified Plutus.State.Select as Select +import Plutus.State.Update (RootStateHandle (..), + StateHandle (..)) +import qualified Plutus.State.Update as Update import Plutus.V1.Ledger.Ada (adaValueOf, lovelaceValueOf) import Plutus.V1.Ledger.Value as Value import qualified PlutusTx @@ -50,47 +56,11 @@ import PlutusTx.Prelude hiding (Functor (..), import Prelude (Semigroup (..), fmap) import qualified Prelude -data StateOutput a = - StateOutput { - soOutRef :: TxOutRef, - soOutTx :: TxOutTx, - soDatum :: a - } deriving (Prelude.Show, Prelude.Functor) - -getAaveDatum :: TxOutTx -> Contract w s Text AaveDatum -getAaveDatum o = case txOutDatumHash $ txOutTxOut o of - Nothing -> throwError "datumHash not found" - Just h -> case Map.lookup h $ txData $ txOutTxTx o of - Nothing -> throwError "datum not found" - Just (Datum e) -> case PlutusTx.fromData e of - Nothing -> throwError "datum has wrong type" - Just d -> return d - -getAaveState :: HasBlockchainActions s => Aave -> Contract w s Text [StateOutput AaveDatum] -getAaveState aave = do - utxos <- utxoAt (Core.aaveAddress aave) - traverse getDatum . Map.toList $ utxos - where - getDatum (oref, o) = do - d <- getAaveDatum o - pure $ StateOutput oref o d - -findOutputsBy :: forall w s a. HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text [StateOutput a] -findOutputsBy aave stateToken mapDatum = mapMaybe checkStateToken <$> getAaveState aave - where - checkStateToken (StateOutput oref outTx datum) = - if assetClassValueOf (txOutValue $ txOutTxOut outTx) stateToken == 1 - then fmap (StateOutput oref outTx) (mapDatum datum) - else Nothing +findOutputsBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text [StateOutput a] +findOutputsBy aave = Select.findOutputsBy (Core.aaveAddress aave) -findOutputBy :: forall w s a. HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text (StateOutput a) -findOutputBy aave stateToken mapDatum = do - outputs <- findOutputsBy aave stateToken mapDatum - let stateName = Text.pack . Prelude.show . Prelude.snd . unAssetClass $ stateToken - case outputs of - [output] -> pure output - [] -> throwError $ stateName <> " not found" - xs -> throwError $ "Multiple " <> stateName <> " found" +findOutputBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text (StateOutput a) +findOutputBy aave = Select.findOutputBy (Core.aaveAddress aave) pickFactory :: AaveDatum -> Maybe Factory pickFactory (FactoryDatum f) = Just f @@ -99,8 +69,12 @@ pickFactory _ = Nothing findAaveFactory :: HasBlockchainActions s => Aave -> Contract w s Text (StateOutput Factory) findAaveFactory aave@Aave{..} = findOutputBy aave aaveProtocolInst pickFactory +reserveStateToken, userStateToken :: Aave -> AssetClass +reserveStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveReserve" +userStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveUser" + findAaveReserve :: HasBlockchainActions s => Aave -> ReserveId -> Contract w s Text (StateOutput Reserve) -findAaveReserve aave reserveId = findOutputBy aave (Core.reserveStateToken aave) mapState +findAaveReserve aave reserveId = findOutputBy aave (reserveStateToken aave) mapState where mapState (Core.ReserveDatum r) = if rCurrency r == reserveId @@ -109,7 +83,7 @@ findAaveReserve aave reserveId = findOutputBy aave (Core.reserveStateToken aave) mapState _ = Nothing findAaveUser :: HasBlockchainActions s => Aave -> PubKeyHash -> ReserveId -> Contract w s Text (StateOutput UserConfig) -findAaveUser aave userAddress reserveId = findOutputBy aave (Core.userStateToken aave) mapState +findAaveUser aave userAddress reserveId = findOutputBy aave (userStateToken aave) mapState where mapState (UserConfigDatum user) = if ucAddress user == userAddress && ucReserveId user == reserveId @@ -117,45 +91,26 @@ findAaveUser aave userAddress reserveId = findOutputBy aave (Core.userStateToken else Nothing mapState _ = Nothing -data StateHandle a = StateHandle { - getToken :: Aave -> AssetClass, - toDatum :: a -> AaveDatum, - toRedeemer :: a -> AaveRedeemer -} - -putState :: (HasBlockchainActions s) => StateHandle a -> Aave -> a -> Contract w s Text a -putState StateHandle{..} aave newState = do - StateOutput oref otx lps <- findAaveFactory aave - - let stateToken = getToken aave - lookups = Constraints.scriptInstanceLookups (Core.aaveInstance aave) - <> Constraints.monetaryPolicy (Core.makeStatePolicy (Prelude.snd . unAssetClass $ stateToken) aave) - <> Constraints.otherScript (Core.aaveScript aave) - <> Constraints.unspentOutputs (Map.singleton oref otx) - tx = mustForgeValue (assetClassValue stateToken 1) - <> mustPayToTheScript (toDatum newState) (assetClassValue stateToken 1) - <> mustPayToTheScript (Core.FactoryDatum lps) (assetClassValue (Core.aaveProtocolInst aave) 1) - <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ toRedeemer newState) - ledgerTx <- submitTxConstraintsWith lookups tx - _ <- awaitTxConfirmed $ txId ledgerTx - pure newState - -updateState :: (HasBlockchainActions s) => StateHandle a -> Aave -> StateOutput a -> Contract w s Text a -updateState StateHandle{..} aave (StateOutput oref o datum) = do - let stateToken = getToken aave - lookups = Constraints.scriptInstanceLookups (Core.aaveInstance aave) - <> Constraints.otherScript (Core.aaveScript aave) - <> Constraints.unspentOutputs (Map.singleton oref o) - tx = mustPayToTheScript (toDatum datum) (assetClassValue stateToken 1) - <> mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData (toRedeemer datum)) - ledgerTx <- submitTxConstraintsWith lookups tx - _ <- awaitTxConfirmed $ txId ledgerTx - pure datum - -makeReserveHandle :: (Reserve -> AaveRedeemer) -> StateHandle Reserve -makeReserveHandle toRedeemer = +stateRootHandle :: (HasBlockchainActions s) => Aave -> Contract w s Text (RootStateHandle AaveScript AaveDatum) +stateRootHandle aave = do + output <- fmap Core.FactoryDatum <$> findOutputBy aave (aaveProtocolInst aave) pickFactory + pure $ + RootStateHandle { script = Core.aaveInstance aave, rootToken = aaveProtocolInst aave, output = output } + +putState :: (HasBlockchainActions s) => Aave -> StateHandle AaveRedeemer AaveDatum a -> a -> Contract w s Text a +putState aave stateHandle newState = do + rootHandle <- stateRootHandle aave + Update.putState rootHandle stateHandle newState + +updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveRedeemer AaveDatum a -> StateOutput a -> Contract w s Text a +updateState aave stateHandle newOutput = do + rootHandle <- stateRootHandle aave + Update.updateState rootHandle stateHandle newOutput + +makeReserveHandle :: Aave -> (Reserve -> AaveRedeemer) -> StateHandle AaveRedeemer AaveDatum Reserve +makeReserveHandle aave toRedeemer = StateHandle { - getToken = Core.reserveStateToken, + stateToken = reserveStateToken aave, toDatum = Core.ReserveDatum, toRedeemer = toRedeemer } @@ -165,15 +120,15 @@ pickReserve (Core.ReserveDatum r) = Just r pickReserve _ = Nothing putReserve :: (HasBlockchainActions s) => Aave -> Reserve -> Contract w s Text Reserve -putReserve = putState $ makeReserveHandle Core.CreateReserveRedeemer +putReserve aave = putState aave $ makeReserveHandle aave Core.CreateReserveRedeemer updateReserve :: (HasBlockchainActions s) => Aave -> StateOutput Reserve -> Contract w s Text Reserve -updateReserve = updateState $ makeReserveHandle (const Core.UpdateReserveRedeemer) +updateReserve aave = updateState aave $ makeReserveHandle aave (const Core.UpdateReserveRedeemer) -makeUserHandle :: (UserConfig -> AaveRedeemer) -> StateHandle UserConfig -makeUserHandle toRedeemer = +makeUserHandle :: Aave -> (UserConfig -> AaveRedeemer) -> StateHandle AaveRedeemer AaveDatum UserConfig +makeUserHandle aave toRedeemer = StateHandle { - getToken = Core.userStateToken, + stateToken = userStateToken aave, toDatum = Core.UserConfigDatum, toRedeemer = toRedeemer } @@ -183,7 +138,7 @@ pickUserConfig (Core.UserConfigDatum user) = Just user pickUserConfig _ = Nothing putUser :: (HasBlockchainActions s) => Aave -> UserConfig -> Contract w s Text UserConfig -putUser = putState $ makeUserHandle Core.CreateUserRedeemer +putUser aave = putState aave $ makeUserHandle aave Core.CreateUserRedeemer updateUser :: (HasBlockchainActions s) => Aave -> StateOutput UserConfig -> Contract w s Text UserConfig -updateUser = updateState $ makeUserHandle (const Core.UpdateUserRedeemer) +updateUser aave = updateState aave $ makeUserHandle aave (const Core.UpdateUserRedeemer) diff --git a/MetaLamp/lending-pool/src/Plutus/State/Select.hs b/MetaLamp/lending-pool/src/Plutus/State/Select.hs new file mode 100644 index 000000000..6cd7f5cc0 --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/State/Select.hs @@ -0,0 +1,87 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} + +module Plutus.State.Select where + +import Control.Monad hiding (fmap) +import qualified Data.ByteString as BS +import qualified Data.Map as Map +import Data.Text (Text, pack) +import qualified Data.Text as Text +import Data.Void (Void) +import Ledger hiding (getDatum, singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as Scripts +import qualified Ledger.Typed.Scripts as Scripts +import Playground.Contract +import Plutus.Contract hiding (when) +import Plutus.V1.Ledger.Value +import qualified PlutusTx +import PlutusTx.Prelude hiding (Semigroup (..), + unless) +import Prelude (Semigroup (..)) +import qualified Prelude + +data StateOutput a = + StateOutput { + soOutRef :: TxOutRef, + soOutTx :: TxOutTx, + soDatum :: a + } deriving (Prelude.Show, Prelude.Functor) + +getDatum :: PlutusTx.IsData a => TxOutTx -> Contract w s Text a +getDatum o = case txOutDatumHash $ txOutTxOut o of + Nothing -> throwError "datumHash not found" + Just h -> case Map.lookup h $ txData $ txOutTxTx o of + Nothing -> throwError "datum not found" + Just (Datum e) -> case PlutusTx.fromData e of + Nothing -> throwError "datum has wrong type" + Just d -> return d + +getState :: (HasBlockchainActions s, PlutusTx.IsData o) => Address -> Contract w s Text [StateOutput o] +getState address = do + utxos <- utxoAt address + traverse getDatum' . Map.toList $ utxos + where + getDatum' (oref, o) = do + d <- getDatum o + pure $ StateOutput oref o d + +findOutputsBy :: (HasBlockchainActions s, PlutusTx.IsData o) => + Address -> + AssetClass -> + (o -> Maybe a) -> + Contract w s Text [StateOutput a] +findOutputsBy address stateToken mapDatum = mapMaybe checkStateToken <$> getState address + where + checkStateToken (StateOutput oref outTx datum) = + if assetClassValueOf (txOutValue $ txOutTxOut outTx) stateToken == 1 + then fmap (StateOutput oref outTx) (mapDatum datum) + else Nothing + +findOutputBy :: (HasBlockchainActions s, PlutusTx.IsData o) => + Address -> + AssetClass -> + (o -> Maybe a) -> + Contract w s Text (StateOutput a) +findOutputBy address stateToken mapDatum = do + outputs <- findOutputsBy address stateToken mapDatum + let stateName = Text.pack . Prelude.show . Prelude.snd . unAssetClass $ stateToken + case outputs of + [output] -> pure output + [] -> throwError $ stateName <> " not found" + xs -> throwError $ "Multiple " <> stateName <> " found" diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs new file mode 100644 index 000000000..5523bbb84 --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -0,0 +1,120 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} + +module Plutus.State.Update where + +import Control.Monad hiding (fmap) +import qualified Data.ByteString as BS +import qualified Data.Map as Map +import Data.Text (Text, pack) +import qualified Data.Text as Text +import Data.Void (Void) +import Ledger hiding (getDatum, singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as Scripts +import Ledger.Typed.Scripts (ScriptType (..)) +import qualified Ledger.Typed.Scripts as Scripts + +import Playground.Contract +import Plutus.Contract hiding (when) +import Plutus.State.Select (StateOutput (..)) +import Plutus.V1.Ledger.Value +import PlutusTx (IsData) +import qualified PlutusTx +import PlutusTx.Prelude hiding (Semigroup (..), + unless) +import Prelude (Semigroup (..)) +import qualified Prelude + +type RootToken = AssetClass + +-- State token can be only be forged either when input has a root token(first-time creation) +-- or any of the state tokens(modification), assuming that state token was created with a root token at some point +validateStateForging :: RootToken -> TokenName -> ScriptContext -> Bool +validateStateForging rootToken tn ctx = case [ i + | i <- txInfoInputs $ scriptContextTxInfo ctx + , let v = valueWithin i + , (assetClassValueOf v rootToken == 1) || + (assetClassValueOf v stateToken == 1) + ] of + [_] -> True + [_, _] -> True + _ -> traceError "State forging without RootToken input" + where + stateToken = assetClass (ownCurrencySymbol ctx) tn + valueWithin = txOutValue . txInInfoResolved + +makeStatePolicy :: RootToken -> TokenName -> MonetaryPolicy +makeStatePolicy rootToken tokenName = mkMonetaryPolicyScript $ + $$(PlutusTx.compile [|| \r t -> Scripts.wrapMonetaryPolicy (validateStateForging r t) ||]) + `PlutusTx.applyCode` PlutusTx.liftCode rootToken + `PlutusTx.applyCode` PlutusTx.liftCode tokenName + +makeStateCurrency :: RootToken -> TokenName -> CurrencySymbol +makeStateCurrency rootToken = scriptCurrencySymbol . makeStatePolicy rootToken + +makeStateToken :: RootToken -> TokenName -> AssetClass +makeStateToken rootToken tokenName = assetClass (makeStateCurrency rootToken tokenName) tokenName + +data RootStateHandle a b = RootStateHandle { + script :: Scripts.ScriptInstance a, + rootToken :: AssetClass, + output :: StateOutput b +} + +data StateHandle i o a = StateHandle { + stateToken :: AssetClass, + toDatum :: a -> o, + toRedeemer :: a -> i +} + +putState :: + (HasBlockchainActions s, IsData (DatumType o), IsData (RedeemerType o)) => + RootStateHandle o (DatumType o) -> + StateHandle (RedeemerType o) (DatumType o) a -> + a -> + Contract w s Text a +putState RootStateHandle {..} StateHandle{..} newState = do + let oref = soOutRef output + otx = soOutTx output + lookups = Constraints.scriptInstanceLookups script + <> Constraints.monetaryPolicy (makeStatePolicy rootToken (Prelude.snd . unAssetClass $ stateToken)) + <> Constraints.otherScript (Scripts.validatorScript script) + <> Constraints.unspentOutputs (Map.singleton oref otx) + tx = mustForgeValue (assetClassValue stateToken 1) + <> Constraints.mustPayToTheScript (toDatum newState) (assetClassValue stateToken 1) + <> Constraints.mustPayToTheScript (soDatum output) (assetClassValue rootToken 1) + <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ toRedeemer newState) + ledgerTx <- submitTxConstraintsWith lookups tx + _ <- awaitTxConfirmed $ txId ledgerTx + pure newState + +updateState :: + (HasBlockchainActions s, IsData (DatumType o), IsData (RedeemerType o)) => + RootStateHandle o (DatumType o) -> + StateHandle (RedeemerType o) (DatumType o) a -> + StateOutput a -> + Contract w s Text a +updateState RootStateHandle{..} StateHandle{..} (StateOutput oref o datum) = do + let lookups = Constraints.scriptInstanceLookups script + <> Constraints.otherScript (Scripts.validatorScript script) + <> Constraints.unspentOutputs (Map.singleton oref o) + tx = Constraints.mustPayToTheScript (toDatum datum) (assetClassValue stateToken 1) + <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData (toRedeemer datum)) + ledgerTx <- submitTxConstraintsWith lookups tx + _ <- awaitTxConfirmed $ txId ledgerTx + pure datum From f0ef46ffd8abee8795e0541625c6f94c90b3d63c Mon Sep 17 00:00:00 2001 From: megakaban Date: Mon, 17 May 2021 23:37:59 +0700 Subject: [PATCH 032/169] Rename Factory, remove ids --- MetaLamp/lending-pool/pab/Main.hs | 6 ------ .../lending-pool/src/Plutus/Contracts/Core.hs | 3 +-- .../src/Plutus/Contracts/Endpoints.hs | 16 ++++------------ .../lending-pool/src/Plutus/Contracts/State.hs | 15 +++++++-------- 4 files changed, 12 insertions(+), 28 deletions(-) diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index f9fb5b04f..b60d8f8f6 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -132,12 +132,6 @@ main = void $ Simulator.runSimulationWith handlers $ do _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final user funds: " <> show v - _ <- Simulator.callEndpointOnInstance userCid "factory" () - v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right (Aave.FactoryEndpoint v)))) -> Just v - _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Final factory: " <> show v - _ <- Simulator.callEndpointOnInstance userCid "reserves" () reserves <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of Success (Monoid.Last (Just (Right (Aave.Reserves reserves)))) -> Just reserves diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 9948c682f..0b9a89f8f 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -75,7 +75,6 @@ data UserConfig = UserConfig PlutusTx.unstableMakeIsData ''UserConfig PlutusTx.makeLift ''UserConfig -type Factory = [ReserveId] data AaveRedeemer = CreateReserveRedeemer Reserve | UpdateReserveRedeemer @@ -87,7 +86,7 @@ data AaveRedeemer = PlutusTx.unstableMakeIsData ''AaveRedeemer PlutusTx.makeLift ''AaveRedeemer -data AaveDatum = FactoryDatum Factory | ReserveDatum Reserve | UserConfigDatum UserConfig | DepositDatum deriving stock (Show) +data AaveDatum = LendingPoolDatum | ReserveDatum Reserve | UserConfigDatum UserConfig | DepositDatum deriving stock (Show) PlutusTx.unstableMakeIsData ''AaveDatum PlutusTx.makeLift ''AaveDatum diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 50544b8ff..9a2f21d1f 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -36,8 +36,7 @@ import Plutus.Contract hiding (when) import qualified Data.ByteString as BS import qualified Plutus.Contracts.AToken as AToken import Plutus.Contracts.Core (Aave, AaveDatum (..), - AaveRedeemer (..), Factory, - Reserve (..), ReserveId, + AaveRedeemer (..), Reserve (..), ReserveId, UserConfig (..)) import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency @@ -78,13 +77,12 @@ start params = do mapError (pack . show @Currency.CurrencyError) $ Currency.forgeContract pkh [(Core.aaveProtocolName, 1)] let aave = Core.aave aaveToken - let reserves = fmap createReserve params - let factoryCoin = assetClass aaveToken Core.aaveProtocolName + let rootToken = assetClass aaveToken Core.aaveProtocolName inst = Core.aaveInstance aave - tx = mustPayToTheScript (Core.FactoryDatum (fmap rCurrency reserves)) $ assetClassValue factoryCoin 1 + tx = mustPayToTheScript Core.LendingPoolDatum $ assetClassValue rootToken 1 ledgerTx <- submitTxConstraints inst tx void $ awaitTxConfirmed $ txId ledgerTx - traverse_ (State.putReserve aave) reserves + traverse_ (State.putReserve aave) $ fmap createReserve params logInfo @String $ printf "started Aave %s at address %s" (show aave) (show $ Core.aaveAddress aave) pure aave @@ -99,9 +97,6 @@ type AaveOwnerSchema = BlockchainActions .\/ Endpoint "start" () -factory :: HasBlockchainActions s => Aave -> Contract w s Text Factory -factory = fmap soDatum . State.findAaveFactory - reserves :: HasBlockchainActions s => Aave -> Contract w s Text [Reserve] reserves aave = Prelude.fmap soDatum <$> State.findOutputsBy aave (State.reserveStateToken aave) State.pickReserve @@ -192,7 +187,6 @@ type AaveUserSchema = .\/ Endpoint "withdraw" WithdrawParams .\/ Endpoint "fundsAt" PubKeyHash .\/ Endpoint "poolFunds" () - .\/ Endpoint "factory" () .\/ Endpoint "reserves" () .\/ Endpoint "users" () @@ -203,7 +197,6 @@ data UserContractState = Created | Withdrawn | FundsAt Value | PoolFunds Value - | FactoryEndpoint Factory | Reserves [Reserve] | Users [UserConfig] deriving (Show, Generic, FromJSON, ToJSON) @@ -214,7 +207,6 @@ userEndpoints aa = forever $ `select` f (Proxy @"withdraw") (const Withdrawn) withdraw `select` f (Proxy @"fundsAt") FundsAt (\_ pkh -> fundsAt pkh) `select` f (Proxy @"poolFunds") PoolFunds (\aave () -> poolFunds aave) - `select` f (Proxy @"factory") FactoryEndpoint (\aave () -> factory aave) `select` f (Proxy @"reserves") Reserves (\aave () -> reserves aave) `select` f (Proxy @"users") Users (\aave () -> users aave) where diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 6e8310959..99e2f53ea 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -37,8 +37,7 @@ import Playground.Contract import Plutus.Contract hiding (when) import Plutus.Contracts.Core (Aave (..), AaveDatum (..), AaveRedeemer (..), - AaveScript, Factory, - Reserve (..), ReserveId, + AaveScript, Reserve (..), ReserveId, UserConfig (..)) import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency @@ -62,12 +61,12 @@ findOutputsBy aave = Select.findOutputsBy (Core.aaveAddress aave) findOutputBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text (StateOutput a) findOutputBy aave = Select.findOutputBy (Core.aaveAddress aave) -pickFactory :: AaveDatum -> Maybe Factory -pickFactory (FactoryDatum f) = Just f -pickFactory _ = Nothing +findAaveRoot :: HasBlockchainActions s => Aave -> Contract w s Text (StateOutput ()) +findAaveRoot aave@Aave{..} = findOutputBy aave aaveProtocolInst pickLendingPool -findAaveFactory :: HasBlockchainActions s => Aave -> Contract w s Text (StateOutput Factory) -findAaveFactory aave@Aave{..} = findOutputBy aave aaveProtocolInst pickFactory +pickLendingPool :: AaveDatum -> Maybe () +pickLendingPool LendingPoolDatum = Just () +pickLendingPool _ = Nothing reserveStateToken, userStateToken :: Aave -> AssetClass reserveStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveReserve" @@ -93,7 +92,7 @@ findAaveUser aave userAddress reserveId = findOutputBy aave (userStateToken aave stateRootHandle :: (HasBlockchainActions s) => Aave -> Contract w s Text (RootStateHandle AaveScript AaveDatum) stateRootHandle aave = do - output <- fmap Core.FactoryDatum <$> findOutputBy aave (aaveProtocolInst aave) pickFactory + output <- fmap (const Core.LendingPoolDatum) <$> findAaveRoot aave pure $ RootStateHandle { script = Core.aaveInstance aave, rootToken = aaveProtocolInst aave, output = output } From 9b40ca33d0801c50a2b3097572097f0527700fba Mon Sep 17 00:00:00 2001 From: megakaban Date: Tue, 18 May 2021 14:23:32 +0700 Subject: [PATCH 033/169] Add inlineable, plutus prelude --- .../src/Plutus/Contracts/AToken.hs | 8 ++--- .../lending-pool/src/Plutus/Contracts/Core.hs | 8 ++--- .../src/Plutus/Contracts/Endpoints.hs | 6 ++-- .../src/Plutus/Contracts/FungibleToken.hs | 6 ++-- .../src/Plutus/Contracts/State.hs | 31 +++++++------------ .../lending-pool/src/Plutus/State/Select.hs | 7 +---- .../lending-pool/src/Plutus/State/Update.hs | 2 ++ 7 files changed, 29 insertions(+), 39 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 4eb77b452..3de2a83ec 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -37,10 +37,10 @@ import qualified Plutus.Contracts.State as State import Plutus.V1.Ledger.Contexts (ScriptContext, scriptCurrencySymbol) import qualified Plutus.V1.Ledger.Scripts as Scripts -import Plutus.V1.Ledger.Value import Plutus.V1.Ledger.Value (AssetClass (unAssetClass), TokenName (..), assetClass, - assetClassValue) + assetClassValue, + assetClassValueOf) import qualified PlutusTx import PlutusTx.Prelude hiding (Semigroup (..)) import Prelude (Semigroup (..)) @@ -84,7 +84,7 @@ burnATokensFrom aave reserve pkh amount = do script = Core.aaveInstance aave policy = makeLiquidityPolicy asset burnLookups = Constraints.scriptInstanceLookups script - <> Constraints.otherScript (Core.aaveScript aave) + <> Constraints.otherScript (Core.aaveValidator aave) <> Constraints.ownPubKeyHash pkh <> Constraints.monetaryPolicy policy outValue = negate $ assetClassValue (rAToken reserve) aTokenAmount @@ -98,7 +98,7 @@ burnATokensFrom aave reserve pkh amount = do let balance = mconcat . fmap (txOutValue . txOutTxOut) . map snd . Map.toList $ utxos remainder = assetClassValueOf balance asset - aTokenAmount withdrawLookups = Constraints.scriptInstanceLookups script - <> Constraints.otherScript (Core.aaveScript aave) + <> Constraints.otherScript (Core.aaveValidator aave) <> Constraints.unspentOutputs utxos <> Constraints.ownPubKeyHash pkh orefs = fst <$> Map.toList utxos diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 0b9a89f8f..8962520d8 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -124,14 +124,14 @@ aaveInstance aave = Scripts.validator @AaveScript where wrap = Scripts.wrapValidator @AaveDatum @AaveRedeemer -aaveScript :: Aave -> Validator -aaveScript = Scripts.validatorScript . aaveInstance +aaveValidator :: Aave -> Validator +aaveValidator = Scripts.validatorScript . aaveInstance aaveHash :: Aave -> Ledger.ValidatorHash -aaveHash = Scripts.validatorHash . aaveScript +aaveHash = Scripts.validatorHash . aaveValidator aaveAddress :: Aave -> Ledger.Address -aaveAddress = Ledger.scriptAddress . aaveScript +aaveAddress = Ledger.scriptAddress . aaveValidator aave :: CurrencySymbol -> Aave aave protocol = Aave (assetClass protocol aaveProtocolName) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 9a2f21d1f..8fc1e33ce 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -19,6 +19,7 @@ module Plutus.Contracts.Endpoints where import Control.Monad hiding (fmap) +import qualified Data.ByteString as BS import qualified Data.Map as Map import Data.Monoid (Last (..)) import Data.Proxy (Proxy (..)) @@ -32,11 +33,10 @@ import qualified Ledger.Scripts as Scripts import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract import Plutus.Contract hiding (when) --- TODO remove that dep Plutus.Contracts.Currency (?) -import qualified Data.ByteString as BS import qualified Plutus.Contracts.AToken as AToken import Plutus.Contracts.Core (Aave, AaveDatum (..), - AaveRedeemer (..), Reserve (..), ReserveId, + AaveRedeemer (..), + Reserve (..), ReserveId, UserConfig (..)) import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs index bda06bf37..fa44b7ebd 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs @@ -1,5 +1,6 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE TemplateHaskell #-} module Plutus.Contracts.FungibleToken where @@ -9,6 +10,7 @@ import Plutus.V1.Ledger.Contexts (ScriptContext) import qualified Plutus.V1.Ledger.Scripts as Scripts import Plutus.V1.Ledger.Value (TokenName, Value) import qualified PlutusTx +import PlutusTx.Prelude {-# INLINABLE validator #-} validator :: TokenName -> ScriptContext -> Bool diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 99e2f53ea..fdf7700a1 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -1,21 +1,12 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveFunctor #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeFamilies #-} module Plutus.Contracts.State where @@ -37,8 +28,8 @@ import Playground.Contract import Plutus.Contract hiding (when) import Plutus.Contracts.Core (Aave (..), AaveDatum (..), AaveRedeemer (..), - AaveScript, Reserve (..), ReserveId, - UserConfig (..)) + AaveScript, Reserve (..), + ReserveId, UserConfig (..)) import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken diff --git a/MetaLamp/lending-pool/src/Plutus/State/Select.hs b/MetaLamp/lending-pool/src/Plutus/State/Select.hs index 6cd7f5cc0..332c9daba 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Select.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Select.hs @@ -1,16 +1,11 @@ {-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveFunctor #-} -{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} module Plutus.State.Select where diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index 5523bbb84..a6ae18ea5 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -5,6 +5,7 @@ {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -44,6 +45,7 @@ type RootToken = AssetClass -- State token can be only be forged either when input has a root token(first-time creation) -- or any of the state tokens(modification), assuming that state token was created with a root token at some point +{-# INLINABLE validateStateForging #-} validateStateForging :: RootToken -> TokenName -> ScriptContext -> Bool validateStateForging rootToken tn ctx = case [ i | i <- txInfoInputs $ scriptContextTxInfo ctx From a2e5cb863cab441fb810227ea163c27b0545eee8 Mon Sep 17 00:00:00 2001 From: megakaban Date: Wed, 19 May 2021 17:13:17 +0700 Subject: [PATCH 034/169] Naming, split state handles and only allow forge from the owner --- .../src/Plutus/Contracts/Endpoints.hs | 8 +- .../src/Plutus/Contracts/State.hs | 35 ++++----- .../lending-pool/src/Plutus/State/Select.hs | 12 +-- .../lending-pool/src/Plutus/State/Update.hs | 78 +++++++++---------- 4 files changed, 62 insertions(+), 71 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 8fc1e33ce..ec27f06b4 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -98,10 +98,10 @@ type AaveOwnerSchema = .\/ Endpoint "start" () reserves :: HasBlockchainActions s => Aave -> Contract w s Text [Reserve] -reserves aave = Prelude.fmap soDatum <$> State.findOutputsBy aave (State.reserveStateToken aave) State.pickReserve +reserves aave = Prelude.fmap soValue <$> State.findOutputsBy aave (State.reserveStateToken aave) State.pickReserve users :: HasBlockchainActions s => Aave -> Contract w s Text [UserConfig] -users aave = Prelude.fmap soDatum <$> State.findOutputsBy aave (State.userStateToken aave) State.pickUserConfig +users aave = Prelude.fmap soValue <$> State.findOutputsBy aave (State.userStateToken aave) State.pickUserConfig valueAt :: HasBlockchainActions s => Address -> Contract w s Text Value valueAt address = do @@ -132,7 +132,7 @@ PlutusTx.makeLift ''DepositParams deposit :: (HasBlockchainActions s) => Aave -> DepositParams -> Contract w s Text () deposit aave DepositParams {..} = do reserveOutput <- State.findAaveReserve aave dpAsset - let reserve = soDatum reserveOutput + let reserve = soValue reserveOutput lookups = Constraints.ownPubKeyHash dpOnBehalfOf <> Constraints.scriptInstanceLookups (Core.aaveInstance aave) outValue = assetClassValue (rCurrency reserve) dpAmount @@ -169,7 +169,7 @@ PlutusTx.makeLift ''WithdrawParams withdraw :: (HasBlockchainActions s) => Aave -> WithdrawParams -> Contract w s Text () withdraw aave WithdrawParams {..} = do reserveOutput <- State.findAaveReserve aave wpAsset - let reserve = soDatum reserveOutput + let reserve = soValue reserveOutput balance <- balanceAt wpFrom (rAToken reserve) when (wpAmount == balance) $ do diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index fdf7700a1..1d4ba5437 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -4,9 +4,9 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE RecordWildCards #-} module Plutus.Contracts.State where @@ -35,7 +35,7 @@ import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken import Plutus.State.Select (StateOutput (..)) import qualified Plutus.State.Select as Select -import Plutus.State.Update (RootStateHandle (..), +import Plutus.State.Update (PutStateHandle (..), StateHandle (..)) import qualified Plutus.State.Update as Update import Plutus.V1.Ledger.Ada (adaValueOf, lovelaceValueOf) @@ -52,12 +52,12 @@ findOutputsBy aave = Select.findOutputsBy (Core.aaveAddress aave) findOutputBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text (StateOutput a) findOutputBy aave = Select.findOutputBy (Core.aaveAddress aave) -findAaveRoot :: HasBlockchainActions s => Aave -> Contract w s Text (StateOutput ()) -findAaveRoot aave@Aave{..} = findOutputBy aave aaveProtocolInst pickLendingPool +findAaveOwnerToken :: HasBlockchainActions s => Aave -> Contract w s Text (StateOutput ()) +findAaveOwnerToken aave@Aave{..} = findOutputBy aave aaveProtocolInst pickOwnerDatum -pickLendingPool :: AaveDatum -> Maybe () -pickLendingPool LendingPoolDatum = Just () -pickLendingPool _ = Nothing +pickOwnerDatum :: AaveDatum -> Maybe () +pickOwnerDatum LendingPoolDatum = Just () +pickOwnerDatum _ = Nothing reserveStateToken, userStateToken :: Aave -> AssetClass reserveStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveReserve" @@ -81,23 +81,22 @@ findAaveUser aave userAddress reserveId = findOutputBy aave (userStateToken aave else Nothing mapState _ = Nothing -stateRootHandle :: (HasBlockchainActions s) => Aave -> Contract w s Text (RootStateHandle AaveScript AaveDatum) +stateRootHandle :: (HasBlockchainActions s) => Aave -> Contract w s Text (PutStateHandle AaveScript) stateRootHandle aave = do - output <- fmap (const Core.LendingPoolDatum) <$> findAaveRoot aave + ownerTokenOutput <- fmap (const Core.LendingPoolDatum) <$> findAaveOwnerToken aave pure $ - RootStateHandle { script = Core.aaveInstance aave, rootToken = aaveProtocolInst aave, output = output } + PutStateHandle { script = Core.aaveInstance aave, ownerToken = aaveProtocolInst aave, ownerTokenOutput = ownerTokenOutput } -putState :: (HasBlockchainActions s) => Aave -> StateHandle AaveRedeemer AaveDatum a -> a -> Contract w s Text a +putState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> a -> Contract w s Text a putState aave stateHandle newState = do - rootHandle <- stateRootHandle aave + ownerTokenOutput <- fmap (const Core.LendingPoolDatum) <$> findAaveOwnerToken aave + let rootHandle = PutStateHandle { script = Core.aaveInstance aave, ownerToken = aaveProtocolInst aave, ownerTokenOutput = ownerTokenOutput } Update.putState rootHandle stateHandle newState -updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveRedeemer AaveDatum a -> StateOutput a -> Contract w s Text a -updateState aave stateHandle newOutput = do - rootHandle <- stateRootHandle aave - Update.updateState rootHandle stateHandle newOutput +updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> StateOutput a -> Contract w s Text a +updateState aave = Update.updateState (Core.aaveInstance aave) -makeReserveHandle :: Aave -> (Reserve -> AaveRedeemer) -> StateHandle AaveRedeemer AaveDatum Reserve +makeReserveHandle :: Aave -> (Reserve -> AaveRedeemer) -> StateHandle AaveScript Reserve makeReserveHandle aave toRedeemer = StateHandle { stateToken = reserveStateToken aave, @@ -115,7 +114,7 @@ putReserve aave = putState aave $ makeReserveHandle aave Core.CreateReserveRedee updateReserve :: (HasBlockchainActions s) => Aave -> StateOutput Reserve -> Contract w s Text Reserve updateReserve aave = updateState aave $ makeReserveHandle aave (const Core.UpdateReserveRedeemer) -makeUserHandle :: Aave -> (UserConfig -> AaveRedeemer) -> StateHandle AaveRedeemer AaveDatum UserConfig +makeUserHandle :: Aave -> (UserConfig -> AaveRedeemer) -> StateHandle AaveScript UserConfig makeUserHandle aave toRedeemer = StateHandle { stateToken = userStateToken aave, diff --git a/MetaLamp/lending-pool/src/Plutus/State/Select.hs b/MetaLamp/lending-pool/src/Plutus/State/Select.hs index 332c9daba..3d0aba289 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Select.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Select.hs @@ -35,7 +35,7 @@ data StateOutput a = StateOutput { soOutRef :: TxOutRef, soOutTx :: TxOutTx, - soDatum :: a + soValue :: a } deriving (Prelude.Show, Prelude.Functor) getDatum :: PlutusTx.IsData a => TxOutTx -> Contract w s Text a @@ -47,7 +47,7 @@ getDatum o = case txOutDatumHash $ txOutTxOut o of Nothing -> throwError "datum has wrong type" Just d -> return d -getState :: (HasBlockchainActions s, PlutusTx.IsData o) => Address -> Contract w s Text [StateOutput o] +getState :: (HasBlockchainActions s, PlutusTx.IsData datum) => Address -> Contract w s Text [StateOutput datum] getState address = do utxos <- utxoAt address traverse getDatum' . Map.toList $ utxos @@ -56,10 +56,10 @@ getState address = do d <- getDatum o pure $ StateOutput oref o d -findOutputsBy :: (HasBlockchainActions s, PlutusTx.IsData o) => +findOutputsBy :: (HasBlockchainActions s, PlutusTx.IsData datum) => Address -> AssetClass -> - (o -> Maybe a) -> + (datum -> Maybe a) -> Contract w s Text [StateOutput a] findOutputsBy address stateToken mapDatum = mapMaybe checkStateToken <$> getState address where @@ -68,10 +68,10 @@ findOutputsBy address stateToken mapDatum = mapMaybe checkStateToken <$> getStat then fmap (StateOutput oref outTx) (mapDatum datum) else Nothing -findOutputBy :: (HasBlockchainActions s, PlutusTx.IsData o) => +findOutputBy :: (HasBlockchainActions s, PlutusTx.IsData datum) => Address -> AssetClass -> - (o -> Maybe a) -> + (datum -> Maybe a) -> Contract w s Text (StateOutput a) findOutputBy address stateToken mapDatum = do outputs <- findOutputsBy address stateToken mapDatum diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index a6ae18ea5..1cd557951 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -41,77 +41,69 @@ import PlutusTx.Prelude hiding (Semigroup (..), import Prelude (Semigroup (..)) import qualified Prelude -type RootToken = AssetClass +type OwnerToken = AssetClass --- State token can be only be forged either when input has a root token(first-time creation) --- or any of the state tokens(modification), assuming that state token was created with a root token at some point +-- State token can be only be forged when there is an input containing an owner token {-# INLINABLE validateStateForging #-} -validateStateForging :: RootToken -> TokenName -> ScriptContext -> Bool -validateStateForging rootToken tn ctx = case [ i - | i <- txInfoInputs $ scriptContextTxInfo ctx - , let v = valueWithin i - , (assetClassValueOf v rootToken == 1) || - (assetClassValueOf v stateToken == 1) - ] of - [_] -> True - [_, _] -> True - _ -> traceError "State forging without RootToken input" +validateStateForging :: OwnerToken -> ScriptContext -> Bool +validateStateForging ownerToken ctx = + any hasOwnerToken inputValues || traceError "State forging without OwnerToken input" where - stateToken = assetClass (ownCurrencySymbol ctx) tn - valueWithin = txOutValue . txInInfoResolved + inputs = txInfoInputs (scriptContextTxInfo ctx) + inputValues = txOutValue . txInInfoResolved <$> inputs + hasOwnerToken value = assetClassValueOf value ownerToken == 1 -makeStatePolicy :: RootToken -> TokenName -> MonetaryPolicy -makeStatePolicy rootToken tokenName = mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| \r t -> Scripts.wrapMonetaryPolicy (validateStateForging r t) ||]) - `PlutusTx.applyCode` PlutusTx.liftCode rootToken - `PlutusTx.applyCode` PlutusTx.liftCode tokenName +makeStatePolicy :: OwnerToken -> MonetaryPolicy +makeStatePolicy ownerToken = mkMonetaryPolicyScript $ + $$(PlutusTx.compile [|| Scripts.wrapMonetaryPolicy . validateStateForging ||]) + `PlutusTx.applyCode` PlutusTx.liftCode ownerToken -makeStateCurrency :: RootToken -> TokenName -> CurrencySymbol -makeStateCurrency rootToken = scriptCurrencySymbol . makeStatePolicy rootToken +makeStateCurrency :: OwnerToken -> CurrencySymbol +makeStateCurrency = scriptCurrencySymbol . makeStatePolicy -makeStateToken :: RootToken -> TokenName -> AssetClass -makeStateToken rootToken tokenName = assetClass (makeStateCurrency rootToken tokenName) tokenName +makeStateToken :: OwnerToken -> TokenName -> AssetClass +makeStateToken ownerToken = assetClass (makeStateCurrency ownerToken) -data RootStateHandle a b = RootStateHandle { - script :: Scripts.ScriptInstance a, - rootToken :: AssetClass, - output :: StateOutput b +data PutStateHandle scriptType = PutStateHandle { + script :: Scripts.ScriptInstance scriptType, + ownerToken :: AssetClass, + ownerTokenOutput :: StateOutput (DatumType scriptType) } -data StateHandle i o a = StateHandle { +data StateHandle scriptType a = StateHandle { stateToken :: AssetClass, - toDatum :: a -> o, - toRedeemer :: a -> i + toDatum :: a -> DatumType scriptType, + toRedeemer :: a -> RedeemerType scriptType } putState :: - (HasBlockchainActions s, IsData (DatumType o), IsData (RedeemerType o)) => - RootStateHandle o (DatumType o) -> - StateHandle (RedeemerType o) (DatumType o) a -> + (HasBlockchainActions s, IsData (DatumType scriptType), IsData (RedeemerType scriptType)) => + PutStateHandle scriptType -> + StateHandle scriptType a -> a -> Contract w s Text a -putState RootStateHandle {..} StateHandle{..} newState = do - let oref = soOutRef output - otx = soOutTx output +putState PutStateHandle {..} StateHandle{..} newState = do + let oref = soOutRef ownerTokenOutput + otx = soOutTx ownerTokenOutput lookups = Constraints.scriptInstanceLookups script - <> Constraints.monetaryPolicy (makeStatePolicy rootToken (Prelude.snd . unAssetClass $ stateToken)) + <> Constraints.monetaryPolicy (makeStatePolicy ownerToken) <> Constraints.otherScript (Scripts.validatorScript script) <> Constraints.unspentOutputs (Map.singleton oref otx) tx = mustForgeValue (assetClassValue stateToken 1) <> Constraints.mustPayToTheScript (toDatum newState) (assetClassValue stateToken 1) - <> Constraints.mustPayToTheScript (soDatum output) (assetClassValue rootToken 1) + <> Constraints.mustPayToTheScript (soValue ownerTokenOutput) (assetClassValue ownerToken 1) <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ toRedeemer newState) ledgerTx <- submitTxConstraintsWith lookups tx _ <- awaitTxConfirmed $ txId ledgerTx pure newState updateState :: - (HasBlockchainActions s, IsData (DatumType o), IsData (RedeemerType o)) => - RootStateHandle o (DatumType o) -> - StateHandle (RedeemerType o) (DatumType o) a -> + (HasBlockchainActions s, IsData (DatumType scriptType), IsData (RedeemerType scriptType)) => + Scripts.ScriptInstance scriptType -> + StateHandle scriptType a -> StateOutput a -> Contract w s Text a -updateState RootStateHandle{..} StateHandle{..} (StateOutput oref o datum) = do +updateState script StateHandle{..} (StateOutput oref o datum) = do let lookups = Constraints.scriptInstanceLookups script <> Constraints.otherScript (Scripts.validatorScript script) <> Constraints.unspentOutputs (Map.singleton oref o) From ad97f324e62475e6330b449bc6e17e2b84b86f0f Mon Sep 17 00:00:00 2001 From: megakaban Date: Thu, 20 May 2021 00:32:56 +0700 Subject: [PATCH 035/169] Use maps for reserves and user configs --- .../lending-pool/src/Plutus/Contracts/Core.hs | 32 +++-- .../src/Plutus/Contracts/Endpoints.hs | 59 +++++---- .../src/Plutus/Contracts/State.hs | 114 ++++++++++-------- .../lending-pool/src/Plutus/State/Update.hs | 8 +- 4 files changed, 121 insertions(+), 92 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 8962520d8..bca5c3efc 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -29,6 +29,7 @@ import Playground.Contract import Plutus.Contract hiding (when) import Plutus.V1.Ledger.Value import qualified PlutusTx +import qualified PlutusTx.AssocMap as AssocMap import PlutusTx.Prelude hiding (Semigroup (..), unless) import Prelude (Semigroup (..)) @@ -64,9 +65,10 @@ data Reserve = Reserve PlutusTx.unstableMakeIsData ''Reserve PlutusTx.makeLift ''Reserve +type UserConfigId = (ReserveId, PubKeyHash) + data UserConfig = UserConfig - { ucAddress :: PubKeyHash, - ucReserveId :: ReserveId, + { ucUsingAsCollateral :: Bool } deriving stock (Show, Generic) @@ -76,17 +78,21 @@ PlutusTx.unstableMakeIsData ''UserConfig PlutusTx.makeLift ''UserConfig data AaveRedeemer = - CreateReserveRedeemer Reserve - | UpdateReserveRedeemer - | CreateUserRedeemer UserConfig - | UpdateUserRedeemer + CreateReservesRedeemer (AssocMap.Map ReserveId Reserve) + | UpdateReservesRedeemer + | CreateUserConfigsRedeemer (AssocMap.Map UserConfigId UserConfig) + | UpdateUserConfigsRedeemer | WithdrawRedeemer deriving Show PlutusTx.unstableMakeIsData ''AaveRedeemer PlutusTx.makeLift ''AaveRedeemer -data AaveDatum = LendingPoolDatum | ReserveDatum Reserve | UserConfigDatum UserConfig | DepositDatum deriving stock (Show) +data AaveDatum = + LendingPoolDatum + | ReservesDatum (AssocMap.Map ReserveId Reserve) + | UserConfigsDatum (AssocMap.Map UserConfigId UserConfig) + | DepositDatum deriving stock (Show) PlutusTx.unstableMakeIsData ''AaveDatum PlutusTx.makeLift ''AaveDatum @@ -106,12 +112,12 @@ makeAaveValidator :: Aave -> AaveRedeemer -> ScriptContext -> Bool -makeAaveValidator _ _ (CreateReserveRedeemer _) _ = True -makeAaveValidator _ _ UpdateReserveRedeemer _ = True -makeAaveValidator _ _ (CreateUserRedeemer _) _ = True -makeAaveValidator _ _ UpdateUserRedeemer _ = True -makeAaveValidator _ _ WithdrawRedeemer _ = True -makeAaveValidator _ _ _ _ = False +makeAaveValidator _ _ (CreateReservesRedeemer _) _ = True +makeAaveValidator _ _ UpdateReservesRedeemer _ = True +makeAaveValidator _ _ (CreateUserConfigsRedeemer _) _ = True +makeAaveValidator _ _ UpdateUserConfigsRedeemer _ = True +makeAaveValidator _ _ WithdrawRedeemer _ = True +makeAaveValidator _ _ _ _ = False aaveProtocolName :: TokenName aaveProtocolName = "Aave" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index ec27f06b4..58e57d7f0 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -37,7 +37,7 @@ import qualified Plutus.Contracts.AToken as AToken import Plutus.Contracts.Core (Aave, AaveDatum (..), AaveRedeemer (..), Reserve (..), ReserveId, - UserConfig (..)) + UserConfig (..), UserConfigId) import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken @@ -47,6 +47,7 @@ import Plutus.V1.Ledger.Ada (adaValueOf, lovelaceValueOf) import qualified Plutus.V1.Ledger.Address as Addr import Plutus.V1.Ledger.Value as Value import qualified PlutusTx +import qualified PlutusTx.AssocMap as AssocMap import PlutusTx.Prelude hiding (Semigroup (..), unless) import Prelude (Semigroup (..)) @@ -82,7 +83,11 @@ start params = do tx = mustPayToTheScript Core.LendingPoolDatum $ assetClassValue rootToken 1 ledgerTx <- submitTxConstraints inst tx void $ awaitTxConfirmed $ txId ledgerTx - traverse_ (State.putReserve aave) $ fmap createReserve params + + let reserveMap = AssocMap.fromList $ fmap (\params -> (cpAsset params, createReserve params)) params + State.putReserves aave reserveMap + State.putUserConfigs aave AssocMap.empty + logInfo @String $ printf "started Aave %s at address %s" (show aave) (show $ Core.aaveAddress aave) pure aave @@ -97,11 +102,11 @@ type AaveOwnerSchema = BlockchainActions .\/ Endpoint "start" () -reserves :: HasBlockchainActions s => Aave -> Contract w s Text [Reserve] -reserves aave = Prelude.fmap soValue <$> State.findOutputsBy aave (State.reserveStateToken aave) State.pickReserve +reserves :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map ReserveId Reserve) +reserves aave = soValue <$> State.findAaveReserves aave -users :: HasBlockchainActions s => Aave -> Contract w s Text [UserConfig] -users aave = Prelude.fmap soValue <$> State.findOutputsBy aave (State.userStateToken aave) State.pickUserConfig +users :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map UserConfigId UserConfig) +users aave = soValue <$> State.findAaveUserConfigs aave valueAt :: HasBlockchainActions s => Address -> Contract w s Text Value valueAt address = do @@ -131,9 +136,9 @@ PlutusTx.makeLift ''DepositParams deposit :: (HasBlockchainActions s) => Aave -> DepositParams -> Contract w s Text () deposit aave DepositParams {..} = do - reserveOutput <- State.findAaveReserve aave dpAsset - let reserve = soValue reserveOutput - lookups = Constraints.ownPubKeyHash dpOnBehalfOf + reserve <- State.findAaveReserve aave dpAsset + + let lookups = Constraints.ownPubKeyHash dpOnBehalfOf <> Constraints.scriptInstanceLookups (Core.aaveInstance aave) outValue = assetClassValue (rCurrency reserve) dpAmount tx = mustPayToTheScript Core.DepositDatum outValue @@ -143,15 +148,18 @@ deposit aave DepositParams {..} = do wasZeroBalance <- (== 0) <$> balanceAt dpOnBehalfOf (rAToken reserve) _ <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount when wasZeroBalance $ do - userOutputs <- State.findOutputsBy aave (State.userStateToken aave) State.pickUserConfig - case userOutputs of - [] -> void $ - State.putUser aave $ UserConfig { ucAddress = dpOnBehalfOf, ucReserveId = rCurrency reserve, ucUsingAsCollateral = True } - [userOutput] -> void $ - State.updateUser aave $ Prelude.fmap (\u -> u { ucUsingAsCollateral = True }) userOutput - _ -> throwError "Invalid state: multiple users" - - void $ State.updateReserve aave $ Prelude.fmap (\r -> r { rAmount = rAmount r + dpAmount }) reserveOutput + userConfigs <- soValue <$> State.findAaveUserConfigs aave + let userConfigId = (rCurrency reserve, dpOnBehalfOf) + case AssocMap.lookup userConfigId userConfigs of + Nothing -> + State.addUserConfig + aave + userConfigId + UserConfig { ucUsingAsCollateral = True } + Just userConfig -> + State.updateUserConfig aave userConfigId $ userConfig { ucUsingAsCollateral = True } + + State.updateReserve aave dpAsset (reserve { rAmount = rAmount reserve + dpAmount }) data WithdrawParams = WithdrawParams { @@ -168,18 +176,17 @@ PlutusTx.makeLift ''WithdrawParams withdraw :: (HasBlockchainActions s) => Aave -> WithdrawParams -> Contract w s Text () withdraw aave WithdrawParams {..} = do - reserveOutput <- State.findAaveReserve aave wpAsset - let reserve = soValue reserveOutput + reserve <- State.findAaveReserve aave wpAsset balance <- balanceAt wpFrom (rAToken reserve) when (wpAmount == balance) $ do - userOutput <- State.findAaveUser aave wpFrom wpAsset - void $ - State.updateUser aave $ Prelude.fmap (\u -> u { ucUsingAsCollateral = False }) userOutput + let userConfigId = (wpAsset, wpFrom) + userConfig <- State.findAaveUserConfig aave userConfigId + State.updateUserConfig aave userConfigId $ userConfig { ucUsingAsCollateral = False } _ <- AToken.burnATokensFrom aave reserve wpTo wpAmount - void $ State.updateReserve aave $ Prelude.fmap (\r -> r { rAmount = rAmount r - wpAmount }) reserveOutput + State.updateReserve aave wpAsset (reserve { rAmount = rAmount reserve - wpAmount }) type AaveUserSchema = BlockchainActions @@ -197,8 +204,8 @@ data UserContractState = Created | Withdrawn | FundsAt Value | PoolFunds Value - | Reserves [Reserve] - | Users [UserConfig] + | Reserves (AssocMap.Map ReserveId Reserve) + | Users (AssocMap.Map UserConfigId UserConfig) deriving (Show, Generic, FromJSON, ToJSON) userEndpoints :: Aave -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 1d4ba5437..68ade95a0 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -4,9 +4,9 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE RecordWildCards #-} module Plutus.Contracts.State where @@ -29,7 +29,7 @@ import Plutus.Contract hiding (when) import Plutus.Contracts.Core (Aave (..), AaveDatum (..), AaveRedeemer (..), AaveScript, Reserve (..), - ReserveId, UserConfig (..)) + ReserveId, UserConfig (..), UserConfigId) import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken @@ -41,6 +41,7 @@ import qualified Plutus.State.Update as Update import Plutus.V1.Ledger.Ada (adaValueOf, lovelaceValueOf) import Plutus.V1.Ledger.Value as Value import qualified PlutusTx +import qualified PlutusTx.AssocMap as AssocMap import PlutusTx.Prelude hiding (Functor (..), Semigroup (..), unless) import Prelude (Semigroup (..), fmap) @@ -63,71 +64,86 @@ reserveStateToken, userStateToken :: Aave -> AssetClass reserveStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveReserve" userStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveUser" -findAaveReserve :: HasBlockchainActions s => Aave -> ReserveId -> Contract w s Text (StateOutput Reserve) -findAaveReserve aave reserveId = findOutputBy aave (reserveStateToken aave) mapState - where - mapState (Core.ReserveDatum r) = - if rCurrency r == reserveId - then Just r - else Nothing - mapState _ = Nothing - -findAaveUser :: HasBlockchainActions s => Aave -> PubKeyHash -> ReserveId -> Contract w s Text (StateOutput UserConfig) -findAaveUser aave userAddress reserveId = findOutputBy aave (userStateToken aave) mapState - where - mapState (UserConfigDatum user) = - if ucAddress user == userAddress && ucReserveId user == reserveId - then Just user - else Nothing - mapState _ = Nothing - -stateRootHandle :: (HasBlockchainActions s) => Aave -> Contract w s Text (PutStateHandle AaveScript) -stateRootHandle aave = do - ownerTokenOutput <- fmap (const Core.LendingPoolDatum) <$> findAaveOwnerToken aave - pure $ - PutStateHandle { script = Core.aaveInstance aave, ownerToken = aaveProtocolInst aave, ownerTokenOutput = ownerTokenOutput } +findAaveReserves :: HasBlockchainActions s => Aave -> Contract w s Text (StateOutput (AssocMap.Map ReserveId Reserve)) +findAaveReserves aave = findOutputBy aave (reserveStateToken aave) pickReserves + +pickReserves :: AaveDatum -> Maybe (AssocMap.Map ReserveId Reserve) +pickReserves (Core.ReservesDatum r) = Just r +pickReserves _ = Nothing + +findAaveReserve :: HasBlockchainActions s => Aave -> ReserveId -> Contract w s Text Reserve +findAaveReserve aave reserveId = do + reserves <- soValue <$> findAaveReserves aave + maybe (throwError "Reserve not found") pure $ AssocMap.lookup reserveId reserves + +findAaveUserConfigs :: HasBlockchainActions s => Aave -> Contract w s Text (StateOutput (AssocMap.Map UserConfigId UserConfig)) +findAaveUserConfigs aave = findOutputBy aave (userStateToken aave) pickUserConfig + +pickUserConfig :: AaveDatum -> Maybe (AssocMap.Map UserConfigId UserConfig) +pickUserConfig (Core.UserConfigsDatum userConfig) = Just userConfig +pickUserConfig _ = Nothing + +findAaveUserConfig :: HasBlockchainActions s => Aave -> UserConfigId -> Contract w s Text UserConfig +findAaveUserConfig aave userConfigId = do + configs <- soValue <$> findAaveUserConfigs aave + maybe (throwError "UserConfig not found") pure $ AssocMap.lookup userConfigId configs -putState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> a -> Contract w s Text a +putState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> a -> Contract w s Text () putState aave stateHandle newState = do ownerTokenOutput <- fmap (const Core.LendingPoolDatum) <$> findAaveOwnerToken aave - let rootHandle = PutStateHandle { script = Core.aaveInstance aave, ownerToken = aaveProtocolInst aave, ownerTokenOutput = ownerTokenOutput } - Update.putState rootHandle stateHandle newState + Update.putState + PutStateHandle { script = Core.aaveInstance aave, ownerToken = aaveProtocolInst aave, ownerTokenOutput = ownerTokenOutput } + stateHandle + newState -updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> StateOutput a -> Contract w s Text a +updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> StateOutput a -> Contract w s Text () updateState aave = Update.updateState (Core.aaveInstance aave) -makeReserveHandle :: Aave -> (Reserve -> AaveRedeemer) -> StateHandle AaveScript Reserve +makeReserveHandle :: Aave -> (AssocMap.Map ReserveId Reserve -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map ReserveId Reserve) makeReserveHandle aave toRedeemer = StateHandle { stateToken = reserveStateToken aave, - toDatum = Core.ReserveDatum, + toDatum = Core.ReservesDatum, toRedeemer = toRedeemer } -pickReserve :: AaveDatum -> Maybe Reserve -pickReserve (Core.ReserveDatum r) = Just r -pickReserve _ = Nothing +putReserves :: (HasBlockchainActions s) => Aave -> AssocMap.Map ReserveId Reserve -> Contract w s Text () +putReserves aave = putState aave $ makeReserveHandle aave Core.CreateReservesRedeemer -putReserve :: (HasBlockchainActions s) => Aave -> Reserve -> Contract w s Text Reserve -putReserve aave = putState aave $ makeReserveHandle aave Core.CreateReserveRedeemer +updateReserves :: (HasBlockchainActions s) => Aave -> StateOutput (AssocMap.Map ReserveId Reserve) -> Contract w s Text () +updateReserves aave = updateState aave $ makeReserveHandle aave (const Core.UpdateReservesRedeemer) -updateReserve :: (HasBlockchainActions s) => Aave -> StateOutput Reserve -> Contract w s Text Reserve -updateReserve aave = updateState aave $ makeReserveHandle aave (const Core.UpdateReserveRedeemer) +updateReserve :: (HasBlockchainActions s) => Aave -> ReserveId -> Reserve -> Contract w s Text () +updateReserve aave reserveId reserve = do + reservesOutput <- findAaveReserves aave + _ <- maybe (throwError "Update failed: reserve not found") pure $ + AssocMap.lookup reserveId (soValue reservesOutput) + updateReserves aave $ Prelude.fmap (AssocMap.insert reserveId reserve) reservesOutput -makeUserHandle :: Aave -> (UserConfig -> AaveRedeemer) -> StateHandle AaveScript UserConfig +makeUserHandle :: Aave -> (AssocMap.Map UserConfigId UserConfig -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map UserConfigId UserConfig) makeUserHandle aave toRedeemer = StateHandle { stateToken = userStateToken aave, - toDatum = Core.UserConfigDatum, + toDatum = Core.UserConfigsDatum, toRedeemer = toRedeemer } -pickUserConfig :: AaveDatum -> Maybe UserConfig -pickUserConfig (Core.UserConfigDatum user) = Just user -pickUserConfig _ = Nothing - -putUser :: (HasBlockchainActions s) => Aave -> UserConfig -> Contract w s Text UserConfig -putUser aave = putState aave $ makeUserHandle aave Core.CreateUserRedeemer - -updateUser :: (HasBlockchainActions s) => Aave -> StateOutput UserConfig -> Contract w s Text UserConfig -updateUser aave = updateState aave $ makeUserHandle aave (const Core.UpdateUserRedeemer) +putUserConfigs :: (HasBlockchainActions s) => Aave -> AssocMap.Map UserConfigId UserConfig -> Contract w s Text () +putUserConfigs aave = putState aave $ makeUserHandle aave Core.CreateUserConfigsRedeemer + +updateUserConfigs :: (HasBlockchainActions s) => Aave -> StateOutput (AssocMap.Map UserConfigId UserConfig) -> Contract w s Text () +updateUserConfigs aave = updateState aave $ makeUserHandle aave (const Core.UpdateUserConfigsRedeemer) + +addUserConfig :: (HasBlockchainActions s) => Aave -> UserConfigId -> UserConfig -> Contract w s Text () +addUserConfig aave userConfigId userConfig = do + configsOutput <- findAaveUserConfigs aave + _ <- maybe (pure ()) (const $ throwError "Add user config failed: config exists") $ + AssocMap.lookup userConfigId (soValue configsOutput) + updateUserConfigs aave $ Prelude.fmap (AssocMap.insert userConfigId userConfig) configsOutput + +updateUserConfig :: (HasBlockchainActions s) => Aave -> UserConfigId -> UserConfig -> Contract w s Text () +updateUserConfig aave userConfigId userConfig = do + configsOutput <- findAaveUserConfigs aave + _ <- maybe (throwError "Update failed: user config not found") pure $ + AssocMap.lookup userConfigId (soValue configsOutput) + updateUserConfigs aave $ Prelude.fmap (AssocMap.insert userConfigId userConfig) configsOutput diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index 1cd557951..155178802 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -81,7 +81,7 @@ putState :: PutStateHandle scriptType -> StateHandle scriptType a -> a -> - Contract w s Text a + Contract w s Text () putState PutStateHandle {..} StateHandle{..} newState = do let oref = soOutRef ownerTokenOutput otx = soOutTx ownerTokenOutput @@ -95,14 +95,14 @@ putState PutStateHandle {..} StateHandle{..} newState = do <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ toRedeemer newState) ledgerTx <- submitTxConstraintsWith lookups tx _ <- awaitTxConfirmed $ txId ledgerTx - pure newState + pure () updateState :: (HasBlockchainActions s, IsData (DatumType scriptType), IsData (RedeemerType scriptType)) => Scripts.ScriptInstance scriptType -> StateHandle scriptType a -> StateOutput a -> - Contract w s Text a + Contract w s Text () updateState script StateHandle{..} (StateOutput oref o datum) = do let lookups = Constraints.scriptInstanceLookups script <> Constraints.otherScript (Scripts.validatorScript script) @@ -111,4 +111,4 @@ updateState script StateHandle{..} (StateOutput oref o datum) = do <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData (toRedeemer datum)) ledgerTx <- submitTxConstraintsWith lookups tx _ <- awaitTxConfirmed $ txId ledgerTx - pure datum + pure () From c2cb42e50735f7fa9fd0a866cb6784dfe59f44a1 Mon Sep 17 00:00:00 2001 From: megakaban Date: Thu, 20 May 2021 15:35:05 +0700 Subject: [PATCH 036/169] Add error logging --- MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 58e57d7f0..7ba274f82 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -226,7 +226,10 @@ userEndpoints aa = forever $ f _ g c = do e <- runError $ do p <- endpoint @l - c aa p + errorHandler `handleError` (c aa p) tell $ Last $ Just $ case e of Left err -> Left err Right a -> Right $ g a + errorHandler e = do + logInfo @Text ("Error submiting the transaction: " <> e) + throwError e From fe18d48651a5886ac1171fb0c4717ce0d529666f Mon Sep 17 00:00:00 2001 From: megakaban Date: Thu, 20 May 2021 15:39:16 +0700 Subject: [PATCH 037/169] Remove aave function duplicate --- MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 7ba274f82..d7959ec0b 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -78,9 +78,9 @@ start params = do mapError (pack . show @Currency.CurrencyError) $ Currency.forgeContract pkh [(Core.aaveProtocolName, 1)] let aave = Core.aave aaveToken - let rootToken = assetClass aaveToken Core.aaveProtocolName + ownerToken = Core.aaveProtocolInst aave inst = Core.aaveInstance aave - tx = mustPayToTheScript Core.LendingPoolDatum $ assetClassValue rootToken 1 + tx = mustPayToTheScript Core.LendingPoolDatum $ assetClassValue ownerToken 1 ledgerTx <- submitTxConstraints inst tx void $ awaitTxConfirmed $ txId ledgerTx From 8d7e163968a36a408b9e6d733dbcd2c634bdd543 Mon Sep 17 00:00:00 2001 From: megakaban Date: Fri, 21 May 2021 14:47:37 +0700 Subject: [PATCH 038/169] Add TxUtils --- MetaLamp/lending-pool/plutus-starter.cabal | 2 +- .../src/Plutus/Contracts/AToken.hs | 48 +++------ .../lending-pool/src/Plutus/Contracts/Core.hs | 12 +-- .../src/Plutus/Contracts/Endpoints.hs | 22 ++-- .../src/Plutus/Contracts/State.hs | 5 +- .../src/Plutus/Contracts/TxUtils.hs | 102 ++++++++++++++++++ .../lending-pool/src/Plutus/State/Update.hs | 36 ++++--- 7 files changed, 157 insertions(+), 70 deletions(-) create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 7ad0b89a2..1af53c4b8 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -23,7 +23,7 @@ maintainer: Your email library exposed-modules: - Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.State Plutus.State.Select Plutus.State.Update + Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.State Plutus.State.Select Plutus.State.Update Plutus.Contracts.TxUtils build-depends: base >= 4.9 && < 5, aeson, diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 3de2a83ec..679bc6d73 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -30,10 +30,12 @@ import Ledger.Constraints.TxConstraints as Constraints import Ledger.Typed.Scripts (MonetaryPolicy) import qualified Ledger.Typed.Scripts as Scripts import Plutus.Contract -import Plutus.Contracts.Core (Aave, Reserve (..)) +import Plutus.Contracts.Core (Aave, AaveScript, + Reserve (..)) import qualified Plutus.Contracts.Core as Core import qualified Plutus.Contracts.FungibleToken as FungibleToken import qualified Plutus.Contracts.State as State +import qualified Plutus.Contracts.TxUtils as TxUtils import Plutus.V1.Ledger.Contexts (ScriptContext, scriptCurrencySymbol) import qualified Plutus.V1.Ledger.Scripts as Scripts @@ -65,48 +67,30 @@ makeAToken asset = assetClass (scriptCurrencySymbol . makeLiquidityPolicy $ asse forgeATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text () forgeATokensFrom aave reserve pkh amount = do - let script = Core.aaveInstance aave - policy = makeLiquidityPolicy (rCurrency reserve) - lookups = Constraints.scriptInstanceLookups script - <> Constraints.monetaryPolicy policy - <> Constraints.ownPubKeyHash pkh + let policy = makeLiquidityPolicy (rCurrency reserve) aTokenAmount = amount -- / rLiquidityIndex reserve -- TODO: how should we divide? - outValue = assetClassValue (rAToken reserve) aTokenAmount - tx = mustForgeValue outValue <> mustPayToPubKey pkh outValue - ledgerTx <- submitTxConstraintsWith lookups tx + forgeValue = assetClassValue (rAToken reserve) aTokenAmount + ledgerTx <- TxUtils.submitTxPair $ + TxUtils.mustForgeValue @Scripts.Any policy forgeValue + <> (Prelude.mempty, mustPayToPubKey pkh forgeValue) _ <- awaitTxConfirmed $ txId ledgerTx pure () burnATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text () burnATokensFrom aave reserve pkh amount = do let asset = rCurrency reserve - aTokenAmount = amount - script = Core.aaveInstance aave - policy = makeLiquidityPolicy asset - burnLookups = Constraints.scriptInstanceLookups script - <> Constraints.otherScript (Core.aaveValidator aave) - <> Constraints.ownPubKeyHash pkh - <> Constraints.monetaryPolicy policy - outValue = negate $ assetClassValue (rAToken reserve) aTokenAmount - burnTx = mustForgeValue outValue - ledgerTx <- submitTxConstraintsWith burnLookups burnTx - _ <- awaitTxConfirmed $ txId ledgerTx - utxos <- Map.filter ((> 0) . flip assetClassValueOf asset . txOutValue . txOutTxOut) <$> utxoAt (Core.aaveAddress aave) let balance = mconcat . fmap (txOutValue . txOutTxOut) . map snd . Map.toList $ utxos + aTokenAmount = amount remainder = assetClassValueOf balance asset - aTokenAmount - withdrawLookups = Constraints.scriptInstanceLookups script - <> Constraints.otherScript (Core.aaveValidator aave) - <> Constraints.unspentOutputs utxos - <> Constraints.ownPubKeyHash pkh - orefs = fst <$> Map.toList utxos - spendTx = mconcat $ fmap (\ref -> mustSpendScriptOutput ref $ Redeemer $ PlutusTx.toData Core.WithdrawRedeemer) orefs - withdrawTx = mustPayToPubKey pkh (assetClassValue asset aTokenAmount) - <> spendTx - <> mustPayToTheScript Core.DepositDatum (assetClassValue asset remainder) - ledgerTx <- submitTxConstraintsWith withdrawLookups withdrawTx + policy = makeLiquidityPolicy asset + burnValue = negate $ assetClassValue (rAToken reserve) aTokenAmount + spendStateInput = (\(ref, tx) -> TxUtils.StateInput ref tx Core.WithdrawRedeemer) <$> Map.toList utxos + ledgerTx <- TxUtils.submitTxPair $ + TxUtils.mustForgeValue policy burnValue + <> TxUtils.mustSpendFromScript (Core.aaveInstance aave) spendStateInput pkh (assetClassValue asset aTokenAmount) + <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.DepositDatum (assetClassValue asset remainder) _ <- awaitTxConfirmed $ txId ledgerTx - pure () diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index bca5c3efc..539827325 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -112,12 +112,12 @@ makeAaveValidator :: Aave -> AaveRedeemer -> ScriptContext -> Bool -makeAaveValidator _ _ (CreateReservesRedeemer _) _ = True -makeAaveValidator _ _ UpdateReservesRedeemer _ = True -makeAaveValidator _ _ (CreateUserConfigsRedeemer _) _ = True -makeAaveValidator _ _ UpdateUserConfigsRedeemer _ = True -makeAaveValidator _ _ WithdrawRedeemer _ = True -makeAaveValidator _ _ _ _ = False +makeAaveValidator _ _ (CreateReservesRedeemer _) _ = True +makeAaveValidator _ _ UpdateReservesRedeemer _ = True +makeAaveValidator _ _ (CreateUserConfigsRedeemer _) _ = True +makeAaveValidator _ _ UpdateUserConfigsRedeemer _ = True +makeAaveValidator _ _ WithdrawRedeemer _ = True +makeAaveValidator _ _ _ _ = False aaveProtocolName :: TokenName aaveProtocolName = "Aave" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index d7959ec0b..2d27b6382 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -37,11 +37,13 @@ import qualified Plutus.Contracts.AToken as AToken import Plutus.Contracts.Core (Aave, AaveDatum (..), AaveRedeemer (..), Reserve (..), ReserveId, - UserConfig (..), UserConfigId) + UserConfig (..), + UserConfigId) import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken import qualified Plutus.Contracts.State as State +import qualified Plutus.Contracts.TxUtils as TxUtils import Plutus.State.Select (StateOutput (..)) import Plutus.V1.Ledger.Ada (adaValueOf, lovelaceValueOf) import qualified Plutus.V1.Ledger.Address as Addr @@ -78,10 +80,9 @@ start params = do mapError (pack . show @Currency.CurrencyError) $ Currency.forgeContract pkh [(Core.aaveProtocolName, 1)] let aave = Core.aave aaveToken - ownerToken = Core.aaveProtocolInst aave - inst = Core.aaveInstance aave - tx = mustPayToTheScript Core.LendingPoolDatum $ assetClassValue ownerToken 1 - ledgerTx <- submitTxConstraints inst tx + payment = assetClassValue (Core.aaveProtocolInst aave) 1 + ledgerTx <- TxUtils.submitTxPair $ + TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.LendingPoolDatum payment void $ awaitTxConfirmed $ txId ledgerTx let reserveMap = AssocMap.fromList $ fmap (\params -> (cpAsset params, createReserve params)) params @@ -137,12 +138,9 @@ PlutusTx.makeLift ''DepositParams deposit :: (HasBlockchainActions s) => Aave -> DepositParams -> Contract w s Text () deposit aave DepositParams {..} = do reserve <- State.findAaveReserve aave dpAsset - - let lookups = Constraints.ownPubKeyHash dpOnBehalfOf - <> Constraints.scriptInstanceLookups (Core.aaveInstance aave) - outValue = assetClassValue (rCurrency reserve) dpAmount - tx = mustPayToTheScript Core.DepositDatum outValue - ledgerTx <- submitTxConstraintsWith lookups tx + let payment = assetClassValue (rCurrency reserve) dpAmount + ledgerTx <- TxUtils.submitTxPair $ + TxUtils.mustPayToScript (Core.aaveInstance aave) dpOnBehalfOf Core.DepositDatum payment _ <- awaitTxConfirmed $ txId ledgerTx wasZeroBalance <- (== 0) <$> balanceAt dpOnBehalfOf (rAToken reserve) @@ -226,7 +224,7 @@ userEndpoints aa = forever $ f _ g c = do e <- runError $ do p <- endpoint @l - errorHandler `handleError` (c aa p) + errorHandler `handleError` c aa p tell $ Last $ Just $ case e of Left err -> Left err Right a -> Right $ g a diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 68ade95a0..4835414d3 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -29,7 +29,8 @@ import Plutus.Contract hiding (when) import Plutus.Contracts.Core (Aave (..), AaveDatum (..), AaveRedeemer (..), AaveScript, Reserve (..), - ReserveId, UserConfig (..), UserConfigId) + ReserveId, UserConfig (..), + UserConfigId) import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken @@ -81,7 +82,7 @@ findAaveUserConfigs aave = findOutputBy aave (userStateToken aave) pickUserConfi pickUserConfig :: AaveDatum -> Maybe (AssocMap.Map UserConfigId UserConfig) pickUserConfig (Core.UserConfigsDatum userConfig) = Just userConfig -pickUserConfig _ = Nothing +pickUserConfig _ = Nothing findAaveUserConfig :: HasBlockchainActions s => Aave -> UserConfigId -> Contract w s Text UserConfig findAaveUserConfig aave userConfigId = do diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs new file mode 100644 index 000000000..b269bd052 --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs @@ -0,0 +1,102 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeFamilies #-} + +module Plutus.Contracts.TxUtils where + +import Control.Monad (void) +import Data.ByteString (ByteString) +import qualified Data.Map as Map +import Data.Text (Text) +import Data.Void (Void) +import Ledger hiding (singleton) +import qualified Ledger.Constraints as Constraints +import qualified Ledger.Constraints.OnChain as Constraints +import qualified Ledger.Constraints.TxConstraints as Constraints +import Ledger.Typed.Scripts (MonetaryPolicy, + ScriptInstance, + ScriptType (..)) +import qualified Ledger.Typed.Scripts as Scripts +import Plutus.Contract +import Plutus.Contracts.Core (Aave, Reserve (..)) +import qualified Plutus.Contracts.Core as Core +import qualified Plutus.Contracts.FungibleToken as FungibleToken +import Plutus.V1.Ledger.Contexts (ScriptContext, + scriptCurrencySymbol) +import qualified Plutus.V1.Ledger.Scripts as Scripts +import Plutus.V1.Ledger.Value (AssetClass (unAssetClass), + TokenName (..), assetClass, + assetClassValue, + assetClassValueOf) +import qualified PlutusTx +import PlutusTx.Prelude hiding (Semigroup (..)) +import Prelude (Semigroup (..)) +import qualified Prelude + +type TxPair a = (Constraints.ScriptLookups a, Constraints.TxConstraints (RedeemerType a) (DatumType a)) + +submitTxPair :: (AsContractError e, HasWriteTx s, PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => + TxPair a + -> Contract w s e Tx +submitTxPair (lookups, tx) = submitTxConstraintsWith lookups tx + +mustForgeValue :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => + MonetaryPolicy + -> Value + -> TxPair a +mustForgeValue policy value = (lookups, tx) + where + lookups = Constraints.monetaryPolicy policy + tx = Constraints.mustForgeValue value + +mustPayToScript :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => + ScriptInstance a + -> PubKeyHash + -> DatumType a + -> Value + -> TxPair a +mustPayToScript script pkh datum value = (lookups, tx) + where + lookups = Constraints.ownPubKeyHash pkh <> Constraints.scriptInstanceLookups script + tx = Constraints.mustPayToTheScript datum value + +data StateInput a = StateInput { + txOutRef :: TxOutRef, + txOutTx :: TxOutTx, + redeemer :: a +} + +mustSpendScriptOutputs :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => + ScriptInstance a + -> [StateInput (RedeemerType a)] + -> TxPair a +mustSpendScriptOutputs script hmm = (lookups, tx) + where + unspent = Map.fromList $ fmap (\(StateInput ref tx _) -> (ref, tx)) hmm + lookups = Constraints.otherScript (Scripts.validatorScript script) <> Constraints.unspentOutputs unspent + tx = Prelude.mconcat $ + fmap (\(StateInput ref _ redeemer) -> Constraints.mustSpendScriptOutput ref (Redeemer $ PlutusTx.toData redeemer)) hmm + +mustSpendFromScript :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => + ScriptInstance a + -> [StateInput (RedeemerType a)] + -> PubKeyHash + -> Value + -> TxPair a +mustSpendFromScript script hmm pkh value = (lookups, tx) <> mustSpendScriptOutputs script hmm + where + lookups = Constraints.ownPubKeyHash pkh + tx = Constraints.mustPayToPubKey pkh value + +mustRoundTripToScript :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => + ScriptInstance a + -> [StateInput (RedeemerType a)] + -> DatumType a + -> PubKeyHash + -> Value + -> TxPair a +mustRoundTripToScript script hmm datum pkh value = mustSpendScriptOutputs script hmm <> mustPayToScript script pkh datum value diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index 155178802..e615cef07 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -32,6 +32,7 @@ import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract import Plutus.Contract hiding (when) +import qualified Plutus.Contracts.TxUtils as TxUtils import Plutus.State.Select (StateOutput (..)) import Plutus.V1.Ledger.Value import PlutusTx (IsData) @@ -83,17 +84,16 @@ putState :: a -> Contract w s Text () putState PutStateHandle {..} StateHandle{..} newState = do - let oref = soOutRef ownerTokenOutput - otx = soOutTx ownerTokenOutput - lookups = Constraints.scriptInstanceLookups script - <> Constraints.monetaryPolicy (makeStatePolicy ownerToken) - <> Constraints.otherScript (Scripts.validatorScript script) - <> Constraints.unspentOutputs (Map.singleton oref otx) - tx = mustForgeValue (assetClassValue stateToken 1) - <> Constraints.mustPayToTheScript (toDatum newState) (assetClassValue stateToken 1) - <> Constraints.mustPayToTheScript (soValue ownerTokenOutput) (assetClassValue ownerToken 1) - <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData $ toRedeemer newState) - ledgerTx <- submitTxConstraintsWith lookups tx + pkh <- pubKeyHash <$> ownPubKey + ledgerTx <- TxUtils.submitTxPair $ + TxUtils.mustForgeValue (makeStatePolicy ownerToken) (assetClassValue stateToken 1) + <> TxUtils.mustPayToScript script pkh (toDatum newState) (assetClassValue stateToken 1) + <> TxUtils.mustRoundTripToScript + script + [TxUtils.StateInput (soOutRef ownerTokenOutput) (soOutTx ownerTokenOutput) (toRedeemer newState)] + (soValue ownerTokenOutput) + pkh + (assetClassValue ownerToken 1) _ <- awaitTxConfirmed $ txId ledgerTx pure () @@ -104,11 +104,13 @@ updateState :: StateOutput a -> Contract w s Text () updateState script StateHandle{..} (StateOutput oref o datum) = do - let lookups = Constraints.scriptInstanceLookups script - <> Constraints.otherScript (Scripts.validatorScript script) - <> Constraints.unspentOutputs (Map.singleton oref o) - tx = Constraints.mustPayToTheScript (toDatum datum) (assetClassValue stateToken 1) - <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData (toRedeemer datum)) - ledgerTx <- submitTxConstraintsWith lookups tx + pkh <- pubKeyHash <$> ownPubKey + ledgerTx <- TxUtils.submitTxPair $ + TxUtils.mustRoundTripToScript + script + [TxUtils.StateInput oref o (toRedeemer datum)] + (toDatum datum) + pkh + (assetClassValue stateToken 1) _ <- awaitTxConfirmed $ txId ledgerTx pure () From 3102eb607c08b89f5f9d35c095be3d8d0e8753b3 Mon Sep 17 00:00:00 2001 From: megakaban Date: Fri, 21 May 2021 16:12:59 +0700 Subject: [PATCH 039/169] Rename StateOutput -> OutputValue, move it to a separate module --- MetaLamp/lending-pool/plutus-starter.cabal | 2 +- .../src/Plutus/Contracts/AToken.hs | 5 ++-- .../src/Plutus/Contracts/Endpoints.hs | 8 +++--- .../src/Plutus/Contracts/State.hs | 28 +++++++++---------- .../src/Plutus/Contracts/TxUtils.hs | 23 ++++++--------- .../lending-pool/src/Plutus/OutputValue.hs | 14 ++++++++++ .../lending-pool/src/Plutus/State/Select.hs | 21 +++++--------- .../lending-pool/src/Plutus/State/Update.hs | 16 +++++------ 8 files changed, 60 insertions(+), 57 deletions(-) create mode 100644 MetaLamp/lending-pool/src/Plutus/OutputValue.hs diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 1af53c4b8..4d707892c 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -23,7 +23,7 @@ maintainer: Your email library exposed-modules: - Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.State Plutus.State.Select Plutus.State.Update Plutus.Contracts.TxUtils + Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.State Plutus.State.Select Plutus.State.Update Plutus.Contracts.TxUtils Plutus.OutputValue build-depends: base >= 4.9 && < 5, aeson, diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 679bc6d73..71e062ae4 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -36,6 +36,7 @@ import qualified Plutus.Contracts.Core as Core import qualified Plutus.Contracts.FungibleToken as FungibleToken import qualified Plutus.Contracts.State as State import qualified Plutus.Contracts.TxUtils as TxUtils +import Plutus.OutputValue (OutputValue (..)) import Plutus.V1.Ledger.Contexts (ScriptContext, scriptCurrencySymbol) import qualified Plutus.V1.Ledger.Scripts as Scripts @@ -87,10 +88,10 @@ burnATokensFrom aave reserve pkh amount = do remainder = assetClassValueOf balance asset - aTokenAmount policy = makeLiquidityPolicy asset burnValue = negate $ assetClassValue (rAToken reserve) aTokenAmount - spendStateInput = (\(ref, tx) -> TxUtils.StateInput ref tx Core.WithdrawRedeemer) <$> Map.toList utxos + spendInputs = (\(ref, tx) -> OutputValue ref tx Core.WithdrawRedeemer) <$> Map.toList utxos ledgerTx <- TxUtils.submitTxPair $ TxUtils.mustForgeValue policy burnValue - <> TxUtils.mustSpendFromScript (Core.aaveInstance aave) spendStateInput pkh (assetClassValue asset aTokenAmount) + <> TxUtils.mustSpendFromScript (Core.aaveInstance aave) spendInputs pkh (assetClassValue asset aTokenAmount) <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.DepositDatum (assetClassValue asset remainder) _ <- awaitTxConfirmed $ txId ledgerTx pure () diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 2d27b6382..52882b166 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -44,7 +44,7 @@ import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken import qualified Plutus.Contracts.State as State import qualified Plutus.Contracts.TxUtils as TxUtils -import Plutus.State.Select (StateOutput (..)) +import Plutus.OutputValue (OutputValue (..)) import Plutus.V1.Ledger.Ada (adaValueOf, lovelaceValueOf) import qualified Plutus.V1.Ledger.Address as Addr import Plutus.V1.Ledger.Value as Value @@ -104,10 +104,10 @@ type AaveOwnerSchema = .\/ Endpoint "start" () reserves :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map ReserveId Reserve) -reserves aave = soValue <$> State.findAaveReserves aave +reserves aave = ovValue <$> State.findAaveReserves aave users :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map UserConfigId UserConfig) -users aave = soValue <$> State.findAaveUserConfigs aave +users aave = ovValue <$> State.findAaveUserConfigs aave valueAt :: HasBlockchainActions s => Address -> Contract w s Text Value valueAt address = do @@ -146,7 +146,7 @@ deposit aave DepositParams {..} = do wasZeroBalance <- (== 0) <$> balanceAt dpOnBehalfOf (rAToken reserve) _ <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount when wasZeroBalance $ do - userConfigs <- soValue <$> State.findAaveUserConfigs aave + userConfigs <- ovValue <$> State.findAaveUserConfigs aave let userConfigId = (rCurrency reserve, dpOnBehalfOf) case AssocMap.lookup userConfigId userConfigs of Nothing -> diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 4835414d3..6d4542fc5 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -34,7 +34,7 @@ import Plutus.Contracts.Core (Aave (..), AaveDatum (..), import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken -import Plutus.State.Select (StateOutput (..)) +import Plutus.OutputValue (OutputValue (..)) import qualified Plutus.State.Select as Select import Plutus.State.Update (PutStateHandle (..), StateHandle (..)) @@ -48,13 +48,13 @@ import PlutusTx.Prelude hiding (Functor (..), import Prelude (Semigroup (..), fmap) import qualified Prelude -findOutputsBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text [StateOutput a] +findOutputsBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text [OutputValue a] findOutputsBy aave = Select.findOutputsBy (Core.aaveAddress aave) -findOutputBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text (StateOutput a) +findOutputBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text (OutputValue a) findOutputBy aave = Select.findOutputBy (Core.aaveAddress aave) -findAaveOwnerToken :: HasBlockchainActions s => Aave -> Contract w s Text (StateOutput ()) +findAaveOwnerToken :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue ()) findAaveOwnerToken aave@Aave{..} = findOutputBy aave aaveProtocolInst pickOwnerDatum pickOwnerDatum :: AaveDatum -> Maybe () @@ -65,7 +65,7 @@ reserveStateToken, userStateToken :: Aave -> AssetClass reserveStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveReserve" userStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveUser" -findAaveReserves :: HasBlockchainActions s => Aave -> Contract w s Text (StateOutput (AssocMap.Map ReserveId Reserve)) +findAaveReserves :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map ReserveId Reserve)) findAaveReserves aave = findOutputBy aave (reserveStateToken aave) pickReserves pickReserves :: AaveDatum -> Maybe (AssocMap.Map ReserveId Reserve) @@ -74,10 +74,10 @@ pickReserves _ = Nothing findAaveReserve :: HasBlockchainActions s => Aave -> ReserveId -> Contract w s Text Reserve findAaveReserve aave reserveId = do - reserves <- soValue <$> findAaveReserves aave + reserves <- ovValue <$> findAaveReserves aave maybe (throwError "Reserve not found") pure $ AssocMap.lookup reserveId reserves -findAaveUserConfigs :: HasBlockchainActions s => Aave -> Contract w s Text (StateOutput (AssocMap.Map UserConfigId UserConfig)) +findAaveUserConfigs :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map UserConfigId UserConfig)) findAaveUserConfigs aave = findOutputBy aave (userStateToken aave) pickUserConfig pickUserConfig :: AaveDatum -> Maybe (AssocMap.Map UserConfigId UserConfig) @@ -86,7 +86,7 @@ pickUserConfig _ = Nothing findAaveUserConfig :: HasBlockchainActions s => Aave -> UserConfigId -> Contract w s Text UserConfig findAaveUserConfig aave userConfigId = do - configs <- soValue <$> findAaveUserConfigs aave + configs <- ovValue <$> findAaveUserConfigs aave maybe (throwError "UserConfig not found") pure $ AssocMap.lookup userConfigId configs putState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> a -> Contract w s Text () @@ -97,7 +97,7 @@ putState aave stateHandle newState = do stateHandle newState -updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> StateOutput a -> Contract w s Text () +updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> OutputValue a -> Contract w s Text () updateState aave = Update.updateState (Core.aaveInstance aave) makeReserveHandle :: Aave -> (AssocMap.Map ReserveId Reserve -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map ReserveId Reserve) @@ -111,14 +111,14 @@ makeReserveHandle aave toRedeemer = putReserves :: (HasBlockchainActions s) => Aave -> AssocMap.Map ReserveId Reserve -> Contract w s Text () putReserves aave = putState aave $ makeReserveHandle aave Core.CreateReservesRedeemer -updateReserves :: (HasBlockchainActions s) => Aave -> StateOutput (AssocMap.Map ReserveId Reserve) -> Contract w s Text () +updateReserves :: (HasBlockchainActions s) => Aave -> OutputValue (AssocMap.Map ReserveId Reserve) -> Contract w s Text () updateReserves aave = updateState aave $ makeReserveHandle aave (const Core.UpdateReservesRedeemer) updateReserve :: (HasBlockchainActions s) => Aave -> ReserveId -> Reserve -> Contract w s Text () updateReserve aave reserveId reserve = do reservesOutput <- findAaveReserves aave _ <- maybe (throwError "Update failed: reserve not found") pure $ - AssocMap.lookup reserveId (soValue reservesOutput) + AssocMap.lookup reserveId (ovValue reservesOutput) updateReserves aave $ Prelude.fmap (AssocMap.insert reserveId reserve) reservesOutput makeUserHandle :: Aave -> (AssocMap.Map UserConfigId UserConfig -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map UserConfigId UserConfig) @@ -132,19 +132,19 @@ makeUserHandle aave toRedeemer = putUserConfigs :: (HasBlockchainActions s) => Aave -> AssocMap.Map UserConfigId UserConfig -> Contract w s Text () putUserConfigs aave = putState aave $ makeUserHandle aave Core.CreateUserConfigsRedeemer -updateUserConfigs :: (HasBlockchainActions s) => Aave -> StateOutput (AssocMap.Map UserConfigId UserConfig) -> Contract w s Text () +updateUserConfigs :: (HasBlockchainActions s) => Aave -> OutputValue (AssocMap.Map UserConfigId UserConfig) -> Contract w s Text () updateUserConfigs aave = updateState aave $ makeUserHandle aave (const Core.UpdateUserConfigsRedeemer) addUserConfig :: (HasBlockchainActions s) => Aave -> UserConfigId -> UserConfig -> Contract w s Text () addUserConfig aave userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (pure ()) (const $ throwError "Add user config failed: config exists") $ - AssocMap.lookup userConfigId (soValue configsOutput) + AssocMap.lookup userConfigId (ovValue configsOutput) updateUserConfigs aave $ Prelude.fmap (AssocMap.insert userConfigId userConfig) configsOutput updateUserConfig :: (HasBlockchainActions s) => Aave -> UserConfigId -> UserConfig -> Contract w s Text () updateUserConfig aave userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (throwError "Update failed: user config not found") pure $ - AssocMap.lookup userConfigId (soValue configsOutput) + AssocMap.lookup userConfigId (ovValue configsOutput) updateUserConfigs aave $ Prelude.fmap (AssocMap.insert userConfigId userConfig) configsOutput diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs index b269bd052..c857a6e17 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs @@ -25,6 +25,7 @@ import Plutus.Contract import Plutus.Contracts.Core (Aave, Reserve (..)) import qualified Plutus.Contracts.Core as Core import qualified Plutus.Contracts.FungibleToken as FungibleToken +import Plutus.OutputValue (OutputValue (..)) import Plutus.V1.Ledger.Contexts (ScriptContext, scriptCurrencySymbol) import qualified Plutus.V1.Ledger.Scripts as Scripts @@ -64,39 +65,33 @@ mustPayToScript script pkh datum value = (lookups, tx) lookups = Constraints.ownPubKeyHash pkh <> Constraints.scriptInstanceLookups script tx = Constraints.mustPayToTheScript datum value -data StateInput a = StateInput { - txOutRef :: TxOutRef, - txOutTx :: TxOutTx, - redeemer :: a -} - mustSpendScriptOutputs :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => ScriptInstance a - -> [StateInput (RedeemerType a)] + -> [OutputValue (RedeemerType a)] -> TxPair a -mustSpendScriptOutputs script hmm = (lookups, tx) +mustSpendScriptOutputs script inputs = (lookups, tx) where - unspent = Map.fromList $ fmap (\(StateInput ref tx _) -> (ref, tx)) hmm + unspent = Map.fromList $ fmap (\(OutputValue ref tx _) -> (ref, tx)) inputs lookups = Constraints.otherScript (Scripts.validatorScript script) <> Constraints.unspentOutputs unspent tx = Prelude.mconcat $ - fmap (\(StateInput ref _ redeemer) -> Constraints.mustSpendScriptOutput ref (Redeemer $ PlutusTx.toData redeemer)) hmm + fmap (\(OutputValue ref _ redeemer) -> Constraints.mustSpendScriptOutput ref (Redeemer $ PlutusTx.toData redeemer)) inputs mustSpendFromScript :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => ScriptInstance a - -> [StateInput (RedeemerType a)] + -> [OutputValue (RedeemerType a)] -> PubKeyHash -> Value -> TxPair a -mustSpendFromScript script hmm pkh value = (lookups, tx) <> mustSpendScriptOutputs script hmm +mustSpendFromScript script inputs pkh value = (lookups, tx) <> mustSpendScriptOutputs script inputs where lookups = Constraints.ownPubKeyHash pkh tx = Constraints.mustPayToPubKey pkh value mustRoundTripToScript :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => ScriptInstance a - -> [StateInput (RedeemerType a)] + -> [OutputValue (RedeemerType a)] -> DatumType a -> PubKeyHash -> Value -> TxPair a -mustRoundTripToScript script hmm datum pkh value = mustSpendScriptOutputs script hmm <> mustPayToScript script pkh datum value +mustRoundTripToScript script inputs datum pkh value = mustSpendScriptOutputs script inputs <> mustPayToScript script pkh datum value diff --git a/MetaLamp/lending-pool/src/Plutus/OutputValue.hs b/MetaLamp/lending-pool/src/Plutus/OutputValue.hs new file mode 100644 index 000000000..88b10d599 --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/OutputValue.hs @@ -0,0 +1,14 @@ +{-# LANGUAGE DeriveFunctor #-} + +module Plutus.OutputValue where + +import Ledger (TxOutRef, TxOutTx) + +import qualified PlutusTx.Prelude as PlutuxTx + +data OutputValue a = + OutputValue { + ovOutRef :: TxOutRef, + ovOutTx :: TxOutTx, + ovValue :: a + } deriving (Prelude.Show, Prelude.Functor) diff --git a/MetaLamp/lending-pool/src/Plutus/State/Select.hs b/MetaLamp/lending-pool/src/Plutus/State/Select.hs index 3d0aba289..784bbdf4d 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Select.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Select.hs @@ -1,5 +1,4 @@ {-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} @@ -24,6 +23,7 @@ import qualified Ledger.Scripts as Scripts import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract import Plutus.Contract hiding (when) +import Plutus.OutputValue (OutputValue (..)) import Plutus.V1.Ledger.Value import qualified PlutusTx import PlutusTx.Prelude hiding (Semigroup (..), @@ -31,13 +31,6 @@ import PlutusTx.Prelude hiding (Semigroup (..), import Prelude (Semigroup (..)) import qualified Prelude -data StateOutput a = - StateOutput { - soOutRef :: TxOutRef, - soOutTx :: TxOutTx, - soValue :: a - } deriving (Prelude.Show, Prelude.Functor) - getDatum :: PlutusTx.IsData a => TxOutTx -> Contract w s Text a getDatum o = case txOutDatumHash $ txOutTxOut o of Nothing -> throwError "datumHash not found" @@ -47,32 +40,32 @@ getDatum o = case txOutDatumHash $ txOutTxOut o of Nothing -> throwError "datum has wrong type" Just d -> return d -getState :: (HasBlockchainActions s, PlutusTx.IsData datum) => Address -> Contract w s Text [StateOutput datum] +getState :: (HasBlockchainActions s, PlutusTx.IsData datum) => Address -> Contract w s Text [OutputValue datum] getState address = do utxos <- utxoAt address traverse getDatum' . Map.toList $ utxos where getDatum' (oref, o) = do d <- getDatum o - pure $ StateOutput oref o d + pure $ OutputValue oref o d findOutputsBy :: (HasBlockchainActions s, PlutusTx.IsData datum) => Address -> AssetClass -> (datum -> Maybe a) -> - Contract w s Text [StateOutput a] + Contract w s Text [OutputValue a] findOutputsBy address stateToken mapDatum = mapMaybe checkStateToken <$> getState address where - checkStateToken (StateOutput oref outTx datum) = + checkStateToken (OutputValue oref outTx datum) = if assetClassValueOf (txOutValue $ txOutTxOut outTx) stateToken == 1 - then fmap (StateOutput oref outTx) (mapDatum datum) + then fmap (OutputValue oref outTx) (mapDatum datum) else Nothing findOutputBy :: (HasBlockchainActions s, PlutusTx.IsData datum) => Address -> AssetClass -> (datum -> Maybe a) -> - Contract w s Text (StateOutput a) + Contract w s Text (OutputValue a) findOutputBy address stateToken mapDatum = do outputs <- findOutputsBy address stateToken mapDatum let stateName = Text.pack . Prelude.show . Prelude.snd . unAssetClass $ stateToken diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index e615cef07..23aabaf92 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -33,7 +33,7 @@ import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract import Plutus.Contract hiding (when) import qualified Plutus.Contracts.TxUtils as TxUtils -import Plutus.State.Select (StateOutput (..)) +import Plutus.OutputValue (OutputValue (..)) import Plutus.V1.Ledger.Value import PlutusTx (IsData) import qualified PlutusTx @@ -68,7 +68,7 @@ makeStateToken ownerToken = assetClass (makeStateCurrency ownerToken) data PutStateHandle scriptType = PutStateHandle { script :: Scripts.ScriptInstance scriptType, ownerToken :: AssetClass, - ownerTokenOutput :: StateOutput (DatumType scriptType) + ownerTokenOutput :: OutputValue (DatumType scriptType) } data StateHandle scriptType a = StateHandle { @@ -90,8 +90,8 @@ putState PutStateHandle {..} StateHandle{..} newState = do <> TxUtils.mustPayToScript script pkh (toDatum newState) (assetClassValue stateToken 1) <> TxUtils.mustRoundTripToScript script - [TxUtils.StateInput (soOutRef ownerTokenOutput) (soOutTx ownerTokenOutput) (toRedeemer newState)] - (soValue ownerTokenOutput) + [toRedeemer newState Prelude.<$ ownerTokenOutput] + (ovValue ownerTokenOutput) pkh (assetClassValue ownerToken 1) _ <- awaitTxConfirmed $ txId ledgerTx @@ -101,15 +101,15 @@ updateState :: (HasBlockchainActions s, IsData (DatumType scriptType), IsData (RedeemerType scriptType)) => Scripts.ScriptInstance scriptType -> StateHandle scriptType a -> - StateOutput a -> + OutputValue a -> Contract w s Text () -updateState script StateHandle{..} (StateOutput oref o datum) = do +updateState script StateHandle{..} output = do pkh <- pubKeyHash <$> ownPubKey ledgerTx <- TxUtils.submitTxPair $ TxUtils.mustRoundTripToScript script - [TxUtils.StateInput oref o (toRedeemer datum)] - (toDatum datum) + [toRedeemer Prelude.<$> output] + (toDatum . ovValue $ output) pkh (assetClassValue stateToken 1) _ <- awaitTxConfirmed $ txId ledgerTx From 3cb34ea00be3567d66a28657b304cef1a6e5722d Mon Sep 17 00:00:00 2001 From: megakaban Date: Fri, 21 May 2021 16:16:17 +0700 Subject: [PATCH 040/169] Use uncurry --- MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs index c857a6e17..fa6ca3a98 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs @@ -43,7 +43,7 @@ type TxPair a = (Constraints.ScriptLookups a, Constraints.TxConstraints (Redeeme submitTxPair :: (AsContractError e, HasWriteTx s, PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => TxPair a -> Contract w s e Tx -submitTxPair (lookups, tx) = submitTxConstraintsWith lookups tx +submitTxPair = uncurry submitTxConstraintsWith mustForgeValue :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => MonetaryPolicy From 709ac31b052068b6888dc524a020356f844cff5b Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Sun, 23 May 2021 21:04:34 +0700 Subject: [PATCH 041/169] add borrow params --- .../src/Plutus/Contracts/Endpoints.hs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 52882b166..a88cb9be2 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -186,6 +186,24 @@ withdraw aave WithdrawParams {..} = do State.updateReserve aave wpAsset (reserve { rAmount = rAmount reserve - wpAmount }) +data BorrowParams = + BorrowParams { + bpAsset :: AssetClass, + bpAmount :: Integer, + bpOnBehalfOf :: PubKeyHash + } + deriving stock (Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''BorrowParams +PlutusTx.makeLift ''BorrowParams + +borrow :: (HasBlockchainActions s) => Aave -> BorrowParams -> Contract w s Text () +borrow aave BorrowParams {..} = do + reserve <- State.findAaveReserve aave bpAsset + + pure () + type AaveUserSchema = BlockchainActions .\/ Endpoint "deposit" DepositParams From 7c5f39546df9a9c6902c7873252d1d60e4b399eb Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 24 May 2021 20:20:16 +0700 Subject: [PATCH 042/169] add borrow logic --- .../lending-pool/src/Plutus/Contracts/Core.hs | 34 +++++++++++++++---- .../src/Plutus/Contracts/Endpoints.hs | 33 ++++++++++++++++-- 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 539827325..473e091e5 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -3,6 +3,7 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} @@ -52,12 +53,15 @@ instance Prelude.Ord Aave where type ReserveId = AssetClass +deriving anyclass instance ToSchema Rational + data Reserve = Reserve - { rCurrency :: ReserveId, - rAToken :: AssetClass, - rAmount :: Integer, - rDebtToken :: AssetClass, - rLiquidityIndex :: Integer + { rCurrency :: ReserveId, + rAToken :: AssetClass, + rAmount :: Integer, + rDebtToken :: AssetClass, + rLiquidityIndex :: Integer, + rCurrentStableBorrowRate :: Rational } deriving stock (Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) @@ -67,9 +71,22 @@ PlutusTx.makeLift ''Reserve type UserConfigId = (ReserveId, PubKeyHash) +-- TODO data Insentifized a = Insentifized { iDatum :: a, iSlotTimestamp :: Integer } +data Debt = Debt + { + dAmount :: Integer, + dStableBorrowRate :: Rational + } + deriving stock (Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''Debt +PlutusTx.makeLift ''Debt + data UserConfig = UserConfig { - ucUsingAsCollateral :: Bool + ucUsingAsCollateral :: Bool, + ucDebt :: [Debt] } deriving stock (Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) @@ -83,6 +100,7 @@ data AaveRedeemer = | CreateUserConfigsRedeemer (AssocMap.Map UserConfigId UserConfig) | UpdateUserConfigsRedeemer | WithdrawRedeemer + | BorrowRedeemer deriving Show PlutusTx.unstableMakeIsData ''AaveRedeemer @@ -92,7 +110,9 @@ data AaveDatum = LendingPoolDatum | ReservesDatum (AssocMap.Map ReserveId Reserve) | UserConfigsDatum (AssocMap.Map UserConfigId UserConfig) - | DepositDatum deriving stock (Show) + | DepositDatum + | BorrowDatum + deriving stock (Show) PlutusTx.unstableMakeIsData ''AaveDatum PlutusTx.makeLift ''AaveDatum diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index a88cb9be2..ad287967f 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -71,7 +71,9 @@ createReserve CreateParams {..} = rAmount = 0, rAToken = AToken.makeAToken cpAsset, rDebtToken = cpAsset, - rLiquidityIndex = 1 } + rLiquidityIndex = 1, + rCurrentStableBorrowRate = 11 % 10 -- TODO configure borrow rate when lending core will be ready + } start :: HasBlockchainActions s => [CreateParams] -> Contract w s Text Aave start params = do @@ -153,7 +155,7 @@ deposit aave DepositParams {..} = do State.addUserConfig aave userConfigId - UserConfig { ucUsingAsCollateral = True } + UserConfig { ucUsingAsCollateral = True, ucDebt = [] } Just userConfig -> State.updateUserConfig aave userConfigId $ userConfig { ucUsingAsCollateral = True } @@ -202,6 +204,33 @@ borrow :: (HasBlockchainActions s) => Aave -> BorrowParams -> Contract w s Text borrow aave BorrowParams {..} = do reserve <- State.findAaveReserve aave bpAsset + userConfigs <- ovValue <$> State.findAaveUserConfigs aave + let userConfigId = (rCurrency reserve, bpOnBehalfOf) + let debt = Core.Debt + { + dAmount = bpAmount, + dStableBorrowRate = rCurrentStableBorrowRate reserve + } + case AssocMap.lookup userConfigId userConfigs of + Nothing -> + State.addUserConfig + aave + userConfigId + UserConfig { ucUsingAsCollateral = False, ucDebt = [debt] } + Just userConfig -> + State.updateUserConfig aave userConfigId $ userConfig { ucDebt = debt : ucDebt userConfig } + + State.updateReserve aave bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) + + utxos <- + Map.filter ((> 0) . flip assetClassValueOf bpAsset . txOutValue . txOutTxOut) + <$> utxoAt (Core.aaveAddress aave) + let inputs = (\(ref, tx) -> OutputValue ref tx Core.BorrowRedeemer) <$> Map.toList utxos + let payment = assetClassValue (rCurrency reserve) bpAmount + ledgerTx <- TxUtils.submitTxPair $ + TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs bpOnBehalfOf payment + _ <- awaitTxConfirmed $ txId ledgerTx + pure () type AaveUserSchema = From f93e3fb7bef5ae5de656d51e93de470a5da6a550 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 26 May 2021 16:41:26 +0700 Subject: [PATCH 043/169] add repay endpoint logic --- .../lending-pool/src/Plutus/Contracts/Core.hs | 15 +---- .../src/Plutus/Contracts/Endpoints.hs | 56 ++++++++++++++----- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 473e091e5..acac64176 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -71,22 +71,10 @@ PlutusTx.makeLift ''Reserve type UserConfigId = (ReserveId, PubKeyHash) --- TODO data Insentifized a = Insentifized { iDatum :: a, iSlotTimestamp :: Integer } -data Debt = Debt - { - dAmount :: Integer, - dStableBorrowRate :: Rational - } - deriving stock (Show, Generic) - deriving anyclass (ToJSON, FromJSON, ToSchema) - -PlutusTx.unstableMakeIsData ''Debt -PlutusTx.makeLift ''Debt - data UserConfig = UserConfig { ucUsingAsCollateral :: Bool, - ucDebt :: [Debt] + ucDebt :: Maybe Integer } deriving stock (Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) @@ -112,6 +100,7 @@ data AaveDatum = | UserConfigsDatum (AssocMap.Map UserConfigId UserConfig) | DepositDatum | BorrowDatum + | RepayDatum deriving stock (Show) PlutusTx.unstableMakeIsData ''AaveDatum diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index ad287967f..243a47362 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -155,7 +155,7 @@ deposit aave DepositParams {..} = do State.addUserConfig aave userConfigId - UserConfig { ucUsingAsCollateral = True, ucDebt = [] } + UserConfig { ucUsingAsCollateral = True, ucDebt = Nothing } Just userConfig -> State.updateUserConfig aave userConfigId $ userConfig { ucUsingAsCollateral = True } @@ -204,33 +204,61 @@ borrow :: (HasBlockchainActions s) => Aave -> BorrowParams -> Contract w s Text borrow aave BorrowParams {..} = do reserve <- State.findAaveReserve aave bpAsset + utxos <- + Map.filter ((> 0) . flip assetClassValueOf bpAsset . txOutValue . txOutTxOut) + <$> utxoAt (Core.aaveAddress aave) + let inputs = (\(ref, tx) -> OutputValue ref tx Core.BorrowRedeemer) <$> Map.toList utxos + let payment = assetClassValue (rCurrency reserve) bpAmount + ledgerTx <- TxUtils.submitTxPair $ + TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs bpOnBehalfOf payment + _ <- awaitTxConfirmed $ txId ledgerTx + userConfigs <- ovValue <$> State.findAaveUserConfigs aave let userConfigId = (rCurrency reserve, bpOnBehalfOf) - let debt = Core.Debt - { - dAmount = bpAmount, - dStableBorrowRate = rCurrentStableBorrowRate reserve - } case AssocMap.lookup userConfigId userConfigs of Nothing -> State.addUserConfig aave userConfigId - UserConfig { ucUsingAsCollateral = False, ucDebt = [debt] } + UserConfig { ucUsingAsCollateral = False, ucDebt = Just bpAmount } Just userConfig -> - State.updateUserConfig aave userConfigId $ userConfig { ucDebt = debt : ucDebt userConfig } + State.updateUserConfig aave userConfigId $ userConfig { ucDebt = (+ bpAmount) <$> ucDebt userConfig } State.updateReserve aave bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) - utxos <- - Map.filter ((> 0) . flip assetClassValueOf bpAsset . txOutValue . txOutTxOut) - <$> utxoAt (Core.aaveAddress aave) - let inputs = (\(ref, tx) -> OutputValue ref tx Core.BorrowRedeemer) <$> Map.toList utxos - let payment = assetClassValue (rCurrency reserve) bpAmount + pure () + +data RepayParams = + RepayParams { + rpAsset :: AssetClass, + rpAmount :: Integer, + rpOnBehalfOf :: PubKeyHash + } + deriving stock (Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''RepayParams +PlutusTx.makeLift ''RepayParams + +repay :: (HasBlockchainActions s) => Aave -> RepayParams -> Contract w s Text () +repay aave RepayParams {..} = do + reserve <- State.findAaveReserve aave rpAsset + + let payment = assetClassValue (rCurrency reserve) rpAmount ledgerTx <- TxUtils.submitTxPair $ - TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs bpOnBehalfOf payment + TxUtils.mustPayToScript (Core.aaveInstance aave) rpOnBehalfOf Core.RepayDatum payment _ <- awaitTxConfirmed $ txId ledgerTx + userConfigs <- ovValue <$> State.findAaveUserConfigs aave + let userConfigId = (rCurrency reserve, rpOnBehalfOf) + case AssocMap.lookup userConfigId userConfigs of + Nothing -> + throwError "User does not have any debt." + Just userConfig -> + State.updateUserConfig aave userConfigId $ userConfig { ucDebt = (`subtract` rpAmount) <$> ucDebt userConfig } + + State.updateReserve aave rpAsset (reserve { rAmount = rAmount reserve + rpAmount }) + pure () type AaveUserSchema = From 6ba6df1cb9dd00794c669839dc1373a6c46885e5 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 26 May 2021 17:32:59 +0700 Subject: [PATCH 044/169] add endpoint calls --- MetaLamp/lending-pool/pab/Main.hs | 18 +++++++++++++++++- .../lending-pool/src/Plutus/Contracts/Core.hs | 3 +++ .../src/Plutus/Contracts/Endpoints.hs | 6 ++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index b60d8f8f6..b9342587d 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -59,7 +59,7 @@ wallets :: [Wallet] wallets = [Wallet i | i <- [1 .. 4]] testCurrencyNames :: [TokenName] -testCurrencyNames = ["MOGUS"] +testCurrencyNames = ["MOGUS", "USD"] toAsset :: TokenName -> AssetClass toAsset tokenName = @@ -126,6 +126,22 @@ main = void $ Simulator.runSimulationWith handlers $ do _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful withdraw" + _ <- + Simulator.callEndpointOnInstance userCid "borrow" $ + Aave.BorrowParams { Aave.bpAsset = testAssets !! 1, Aave.bpAmount = 35, Aave.bpOnBehalfOf = sender } + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right Aave.Borrowed))) -> Just () + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Successful borrow" + + _ <- + Simulator.callEndpointOnInstance userCid "repay" $ + Aave.RepayParams { Aave.rpAsset = testAssets !! 1, Aave.rpAmount = 25, Aave.rpOnBehalfOf = sender } + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right Aave.Repaid))) -> Just () + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Successful repay" + _ <- Simulator.callEndpointOnInstance userCid "fundsAt" sender v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of Success (Monoid.Last (Just (Right (Aave.FundsAt v)))) -> Just v diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index acac64176..9af6f33fa 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -89,6 +89,7 @@ data AaveRedeemer = | UpdateUserConfigsRedeemer | WithdrawRedeemer | BorrowRedeemer + | RepayRedeemer deriving Show PlutusTx.unstableMakeIsData ''AaveRedeemer @@ -126,6 +127,8 @@ makeAaveValidator _ _ UpdateReservesRedeemer _ = True makeAaveValidator _ _ (CreateUserConfigsRedeemer _) _ = True makeAaveValidator _ _ UpdateUserConfigsRedeemer _ = True makeAaveValidator _ _ WithdrawRedeemer _ = True +makeAaveValidator _ _ BorrowRedeemer _ = True +makeAaveValidator _ _ RepayRedeemer _ = True makeAaveValidator _ _ _ _ = False aaveProtocolName :: TokenName diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 243a47362..249296886 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -265,6 +265,8 @@ type AaveUserSchema = BlockchainActions .\/ Endpoint "deposit" DepositParams .\/ Endpoint "withdraw" WithdrawParams + .\/ Endpoint "borrow" BorrowParams + .\/ Endpoint "repay" RepayParams .\/ Endpoint "fundsAt" PubKeyHash .\/ Endpoint "poolFunds" () .\/ Endpoint "reserves" () @@ -275,6 +277,8 @@ data UserContractState = Created | Stopped | Deposited | Withdrawn + | Borrowed + | Repaid | FundsAt Value | PoolFunds Value | Reserves (AssocMap.Map ReserveId Reserve) @@ -285,6 +289,8 @@ userEndpoints :: Aave -> Contract (Last (Either Text UserContractState)) AaveUse userEndpoints aa = forever $ f (Proxy @"deposit") (const Deposited) deposit `select` f (Proxy @"withdraw") (const Withdrawn) withdraw + `select` f (Proxy @"borrow") (const Borrowed) borrow + `select` f (Proxy @"repay") (const Repaid) repay `select` f (Proxy @"fundsAt") FundsAt (\_ pkh -> fundsAt pkh) `select` f (Proxy @"poolFunds") PoolFunds (\aave () -> poolFunds aave) `select` f (Proxy @"reserves") Reserves (\aave () -> reserves aave) From e40134e7fd905f796eba5926a0031da0528dabbd Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 26 May 2021 20:53:57 +0700 Subject: [PATCH 045/169] fix borrow and repay logic --- MetaLamp/lending-pool/pab/Main.hs | 16 ++++++++++++++++ .../src/Plutus/Contracts/Endpoints.hs | 6 ++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index b9342587d..f0e2b4fb3 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -126,6 +126,16 @@ main = void $ Simulator.runSimulationWith handlers $ do _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful withdraw" + let lenderCid = cids Map.! Wallet 3 + let lender = pubKeyHash . walletPubKey $ Wallet 3 + _ <- + Simulator.callEndpointOnInstance lenderCid "deposit" $ + Aave.DepositParams { Aave.dpAsset = testAssets !! 1, Aave.dpOnBehalfOf = lender, Aave.dpAmount = 200 } + flip Simulator.waitForState lenderCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right Aave.Deposited))) -> Just () + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Successful deposit from lender" + _ <- Simulator.callEndpointOnInstance userCid "borrow" $ Aave.BorrowParams { Aave.bpAsset = testAssets !! 1, Aave.bpAmount = 35, Aave.bpOnBehalfOf = sender } @@ -148,6 +158,12 @@ main = void $ Simulator.runSimulationWith handlers $ do _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final user funds: " <> show v + _ <- Simulator.callEndpointOnInstance lenderCid "fundsAt" lender + v <- flip Simulator.waitForState lenderCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right (Aave.FundsAt v)))) -> Just v + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Final lender funds: " <> show v + _ <- Simulator.callEndpointOnInstance userCid "reserves" () reserves <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of Success (Monoid.Last (Just (Right (Aave.Reserves reserves)))) -> Just reserves diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 249296886..5560dd9cd 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -209,8 +209,10 @@ borrow aave BorrowParams {..} = do <$> utxoAt (Core.aaveAddress aave) let inputs = (\(ref, tx) -> OutputValue ref tx Core.BorrowRedeemer) <$> Map.toList utxos let payment = assetClassValue (rCurrency reserve) bpAmount + let remainder = assetClassValue (rCurrency reserve) (rAmount reserve - bpAmount) ledgerTx <- TxUtils.submitTxPair $ - TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs bpOnBehalfOf payment + TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs bpOnBehalfOf payment <> + TxUtils.mustPayToScript (Core.aaveInstance aave) bpOnBehalfOf Core.BorrowDatum remainder _ <- awaitTxConfirmed $ txId ledgerTx userConfigs <- ovValue <$> State.findAaveUserConfigs aave @@ -255,7 +257,7 @@ repay aave RepayParams {..} = do Nothing -> throwError "User does not have any debt." Just userConfig -> - State.updateUserConfig aave userConfigId $ userConfig { ucDebt = (`subtract` rpAmount) <$> ucDebt userConfig } + State.updateUserConfig aave userConfigId $ userConfig { ucDebt = subtract rpAmount <$> ucDebt userConfig } State.updateReserve aave rpAsset (reserve { rAmount = rAmount reserve + rpAmount }) From 03860ef5f32088102cf987b9d1f8a3c29b3763db Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 27 May 2021 14:04:30 +0700 Subject: [PATCH 046/169] rm redundant pure --- MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 5560dd9cd..74afab4ed 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -228,8 +228,6 @@ borrow aave BorrowParams {..} = do State.updateReserve aave bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) - pure () - data RepayParams = RepayParams { rpAsset :: AssetClass, @@ -261,8 +259,6 @@ repay aave RepayParams {..} = do State.updateReserve aave rpAsset (reserve { rAmount = rAmount reserve + rpAmount }) - pure () - type AaveUserSchema = BlockchainActions .\/ Endpoint "deposit" DepositParams From 7fe80feff89fef42c1096c9244a6744b8c0cc68b Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 27 May 2021 15:49:07 +0700 Subject: [PATCH 047/169] run fmt --- MetaLamp/lending-pool/pab/Main.hs | 4 ++-- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index f0e2b4fb3..dfc3f01e5 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -141,7 +141,7 @@ main = void $ Simulator.runSimulationWith handlers $ do Aave.BorrowParams { Aave.bpAsset = testAssets !! 1, Aave.bpAmount = 35, Aave.bpOnBehalfOf = sender } flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of Success (Monoid.Last (Just (Right Aave.Borrowed))) -> Just () - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful borrow" _ <- @@ -149,7 +149,7 @@ main = void $ Simulator.runSimulationWith handlers $ do Aave.RepayParams { Aave.rpAsset = testAssets !! 1, Aave.rpAmount = 25, Aave.rpOnBehalfOf = sender } flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of Success (Monoid.Last (Just (Right Aave.Repaid))) -> Just () - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful repay" _ <- Simulator.callEndpointOnInstance userCid "fundsAt" sender diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 9af6f33fa..5d01c92c4 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -127,8 +127,8 @@ makeAaveValidator _ _ UpdateReservesRedeemer _ = True makeAaveValidator _ _ (CreateUserConfigsRedeemer _) _ = True makeAaveValidator _ _ UpdateUserConfigsRedeemer _ = True makeAaveValidator _ _ WithdrawRedeemer _ = True -makeAaveValidator _ _ BorrowRedeemer _ = True -makeAaveValidator _ _ RepayRedeemer _ = True +makeAaveValidator _ _ BorrowRedeemer _ = True +makeAaveValidator _ _ RepayRedeemer _ = True makeAaveValidator _ _ _ _ = False aaveProtocolName :: TokenName From 86b2f5815383abcac6610923dcd4eed4de0432a4 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 28 May 2021 20:11:31 +0700 Subject: [PATCH 048/169] add aToken validator --- .../src/Plutus/Contracts/AToken.hs | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 71e062ae4..18085c575 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -40,31 +40,51 @@ import Plutus.OutputValue (OutputValue (..)) import Plutus.V1.Ledger.Contexts (ScriptContext, scriptCurrencySymbol) import qualified Plutus.V1.Ledger.Scripts as Scripts -import Plutus.V1.Ledger.Value (AssetClass (unAssetClass), +import Plutus.V1.Ledger.Value (AssetClass (..), TokenName (..), assetClass, assetClassValue, assetClassValueOf) import qualified PlutusTx import PlutusTx.Prelude hiding (Semigroup (..)) +import qualified PlutusTx.Semigroup as Semigroup import Prelude (Semigroup (..)) import qualified Prelude {-# INLINABLE validator #-} --- TODO: check that ScriptContext has enough liquidity -validator :: AssetClass -> ScriptContext -> Bool -validator _ _ = True +validator :: AssetClass -> TokenName -> ScriptContext -> Bool +validator underlyingAsset aTokenName ctx = hasEnoughUnderlyingAsset + where + txInfo :: TxInfo + txInfo = scriptContextTxInfo ctx + + aTokenCurrency :: AssetClass + aTokenCurrency = assetClass (ownCurrencySymbol ctx) aTokenName + + amountMinted :: Integer + amountMinted = assetClassValueOf (txInfoForge txInfo) aTokenCurrency + amountAsset :: Integer + amountAsset = assetClassValueOf (valueSpent txInfo) underlyingAsset + + hasEnoughUnderlyingAsset :: Bool + hasEnoughUnderlyingAsset = amountMinted <= amountAsset makeLiquidityPolicy :: AssetClass -> MonetaryPolicy makeLiquidityPolicy asset = Scripts.mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| Scripts.wrapMonetaryPolicy . validator ||]) + $$(PlutusTx.compile [|| \a t -> Scripts.wrapMonetaryPolicy $ validator a t||]) `PlutusTx.applyCode` PlutusTx.liftCode asset + `PlutusTx.applyCode` + PlutusTx.liftCode aToken + where + aToken = aTokenName asset makeAToken :: AssetClass -> AssetClass -makeAToken asset = assetClass (scriptCurrencySymbol . makeLiquidityPolicy $ asset) (TokenName aTokenName) - where - (_, tokenName) = unAssetClass asset - aTokenName = "a" <> unTokenName tokenName +makeAToken asset = assetClass (scriptCurrencySymbol . makeLiquidityPolicy $ asset) (aTokenName asset) + +{-# INLINABLE aTokenName #-} +aTokenName :: AssetClass -> TokenName +aTokenName asset = TokenName $ "a" Semigroup.<> case asset of + AssetClass (_,TokenName n) -> n forgeATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text () forgeATokensFrom aave reserve pkh amount = do From 570e0a710467bdfa9c28d5da402852d367d0cdb4 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Sun, 30 May 2021 17:44:47 +0700 Subject: [PATCH 049/169] merge forge and spend txs in deposit --- MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs | 10 ++++------ .../lending-pool/src/Plutus/Contracts/Endpoints.hs | 4 ++-- MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs | 3 +++ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 18085c575..dde92bcdf 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -63,7 +63,7 @@ validator underlyingAsset aTokenName ctx = hasEnoughUnderlyingAsset amountMinted :: Integer amountMinted = assetClassValueOf (txInfoForge txInfo) aTokenCurrency amountAsset :: Integer - amountAsset = assetClassValueOf (valueSpent txInfo) underlyingAsset + amountAsset = assetClassValueOf (valueSpent txInfo) underlyingAsset -- TODO how to check if value spent does not come from aave script? hasEnoughUnderlyingAsset :: Bool hasEnoughUnderlyingAsset = amountMinted <= amountAsset @@ -86,16 +86,14 @@ aTokenName :: AssetClass -> TokenName aTokenName asset = TokenName $ "a" Semigroup.<> case asset of AssetClass (_,TokenName n) -> n -forgeATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text () +forgeATokensFrom :: forall w s. (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text (TxUtils.TxPair AaveScript) forgeATokensFrom aave reserve pkh amount = do let policy = makeLiquidityPolicy (rCurrency reserve) aTokenAmount = amount -- / rLiquidityIndex reserve -- TODO: how should we divide? forgeValue = assetClassValue (rAToken reserve) aTokenAmount - ledgerTx <- TxUtils.submitTxPair $ - TxUtils.mustForgeValue @Scripts.Any policy forgeValue + pure $ + TxUtils.mustForgeValue @AaveScript policy forgeValue <> (Prelude.mempty, mustPayToPubKey pkh forgeValue) - _ <- awaitTxConfirmed $ txId ledgerTx - pure () burnATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text () burnATokensFrom aave reserve pkh amount = do diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 74afab4ed..de3bfe034 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -140,13 +140,13 @@ PlutusTx.makeLift ''DepositParams deposit :: (HasBlockchainActions s) => Aave -> DepositParams -> Contract w s Text () deposit aave DepositParams {..} = do reserve <- State.findAaveReserve aave dpAsset + forgeTxPair <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount let payment = assetClassValue (rCurrency reserve) dpAmount ledgerTx <- TxUtils.submitTxPair $ - TxUtils.mustPayToScript (Core.aaveInstance aave) dpOnBehalfOf Core.DepositDatum payment + TxUtils.mustPayToScript (Core.aaveInstance aave) dpOnBehalfOf Core.DepositDatum payment <> forgeTxPair _ <- awaitTxConfirmed $ txId ledgerTx wasZeroBalance <- (== 0) <$> balanceAt dpOnBehalfOf (rAToken reserve) - _ <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount when wasZeroBalance $ do userConfigs <- ovValue <$> State.findAaveUserConfigs aave let userConfigId = (rCurrency reserve, dpOnBehalfOf) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs index fa6ca3a98..96210ce78 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleContexts #-} @@ -40,6 +41,8 @@ import qualified Prelude type TxPair a = (Constraints.ScriptLookups a, Constraints.TxConstraints (RedeemerType a) (DatumType a)) +type HasTxData a = (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) + submitTxPair :: (AsContractError e, HasWriteTx s, PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => TxPair a -> Contract w s e Tx From 8ce6ca44010cafc1c7826bb825ab701ee28de7b4 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Sun, 30 May 2021 18:28:36 +0700 Subject: [PATCH 050/169] submit burn tx correctly --- MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs | 12 +++++++----- .../lending-pool/src/Plutus/Contracts/Endpoints.hs | 10 +++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index dde92bcdf..ed87322be 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -62,8 +62,10 @@ validator underlyingAsset aTokenName ctx = hasEnoughUnderlyingAsset amountMinted :: Integer amountMinted = assetClassValueOf (txInfoForge txInfo) aTokenCurrency + + -- TODO how to check if value spent comes from pub key when aTokens are minted and comes from aave script when aTokens are burned? amountAsset :: Integer - amountAsset = assetClassValueOf (valueSpent txInfo) underlyingAsset -- TODO how to check if value spent does not come from aave script? + amountAsset = assetClassValueOf (valueSpent txInfo) underlyingAsset hasEnoughUnderlyingAsset :: Bool hasEnoughUnderlyingAsset = amountMinted <= amountAsset @@ -91,11 +93,13 @@ forgeATokensFrom aave reserve pkh amount = do let policy = makeLiquidityPolicy (rCurrency reserve) aTokenAmount = amount -- / rLiquidityIndex reserve -- TODO: how should we divide? forgeValue = assetClassValue (rAToken reserve) aTokenAmount + let payment = assetClassValue (rCurrency reserve) amount pure $ TxUtils.mustForgeValue @AaveScript policy forgeValue <> (Prelude.mempty, mustPayToPubKey pkh forgeValue) + <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.DepositDatum payment -burnATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text () +burnATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text (TxUtils.TxPair AaveScript) burnATokensFrom aave reserve pkh amount = do let asset = rCurrency reserve utxos <- @@ -107,9 +111,7 @@ burnATokensFrom aave reserve pkh amount = do policy = makeLiquidityPolicy asset burnValue = negate $ assetClassValue (rAToken reserve) aTokenAmount spendInputs = (\(ref, tx) -> OutputValue ref tx Core.WithdrawRedeemer) <$> Map.toList utxos - ledgerTx <- TxUtils.submitTxPair $ + pure $ TxUtils.mustForgeValue policy burnValue <> TxUtils.mustSpendFromScript (Core.aaveInstance aave) spendInputs pkh (assetClassValue asset aTokenAmount) <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.DepositDatum (assetClassValue asset remainder) - _ <- awaitTxConfirmed $ txId ledgerTx - pure () diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index de3bfe034..89bc52c7e 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -140,10 +140,8 @@ PlutusTx.makeLift ''DepositParams deposit :: (HasBlockchainActions s) => Aave -> DepositParams -> Contract w s Text () deposit aave DepositParams {..} = do reserve <- State.findAaveReserve aave dpAsset - forgeTxPair <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount - let payment = assetClassValue (rCurrency reserve) dpAmount - ledgerTx <- TxUtils.submitTxPair $ - TxUtils.mustPayToScript (Core.aaveInstance aave) dpOnBehalfOf Core.DepositDatum payment <> forgeTxPair + forgeTx <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount + ledgerTx <- TxUtils.submitTxPair forgeTx _ <- awaitTxConfirmed $ txId ledgerTx wasZeroBalance <- (== 0) <$> balanceAt dpOnBehalfOf (rAToken reserve) @@ -184,7 +182,9 @@ withdraw aave WithdrawParams {..} = do userConfig <- State.findAaveUserConfig aave userConfigId State.updateUserConfig aave userConfigId $ userConfig { ucUsingAsCollateral = False } - _ <- AToken.burnATokensFrom aave reserve wpTo wpAmount + burnTx <- AToken.burnATokensFrom aave reserve wpTo wpAmount + ledgerTx <- TxUtils.submitTxPair burnTx + _ <- awaitTxConfirmed $ txId ledgerTx State.updateReserve aave wpAsset (reserve { rAmount = rAmount reserve - wpAmount }) From a352ebc6635701ef1d5e3edb27ad59ce0bb0d9dc Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 31 May 2021 17:20:42 +0700 Subject: [PATCH 051/169] add reserves and users wrappers --- .../lending-pool/src/Plutus/Contracts/Core.hs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 5d01c92c4..e052211f5 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -82,6 +82,24 @@ data UserConfig = UserConfig PlutusTx.unstableMakeIsData ''UserConfig PlutusTx.makeLift ''UserConfig +newtype InstanceReserves = InstanceReserves { + getInstanceReserves :: AssocMap.Map ReserveId Reserve +} + deriving stock (Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''InstanceReserves +PlutusTx.makeLift ''InstanceReserves + +newtype InstanceUsers = InstanceUsers { + getInstanceUsers :: AssocMap.Map UserConfigId UserConfig +} + deriving stock (Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''InstanceUsers +PlutusTx.makeLift ''InstanceUsers + data AaveRedeemer = CreateReservesRedeemer (AssocMap.Map ReserveId Reserve) | UpdateReservesRedeemer From aaaf5de9831367c146cce20a71c2e2356f653443 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 1 Jun 2021 17:44:08 +0700 Subject: [PATCH 052/169] refactor redeemer and datum types --- .../src/Plutus/Contracts/AToken.hs | 2 +- .../lending-pool/src/Plutus/Contracts/Core.hs | 39 +++++-------------- .../src/Plutus/Contracts/Endpoints.hs | 24 ++++++------ .../src/Plutus/Contracts/State.hs | 34 ++++++++-------- 4 files changed, 39 insertions(+), 60 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index ed87322be..4e9fb2c48 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -114,4 +114,4 @@ burnATokensFrom aave reserve pkh amount = do pure $ TxUtils.mustForgeValue policy burnValue <> TxUtils.mustSpendFromScript (Core.aaveInstance aave) spendInputs pkh (assetClassValue asset aTokenAmount) - <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.DepositDatum (assetClassValue asset remainder) + <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.WithdrawDatum (assetClassValue asset remainder) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index e052211f5..5cb238640 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -82,29 +82,9 @@ data UserConfig = UserConfig PlutusTx.unstableMakeIsData ''UserConfig PlutusTx.makeLift ''UserConfig -newtype InstanceReserves = InstanceReserves { - getInstanceReserves :: AssocMap.Map ReserveId Reserve -} - deriving stock (Show, Generic) - deriving anyclass (ToJSON, FromJSON, ToSchema) - -PlutusTx.unstableMakeIsData ''InstanceReserves -PlutusTx.makeLift ''InstanceReserves - -newtype InstanceUsers = InstanceUsers { - getInstanceUsers :: AssocMap.Map UserConfigId UserConfig -} - deriving stock (Show, Generic) - deriving anyclass (ToJSON, FromJSON, ToSchema) - -PlutusTx.unstableMakeIsData ''InstanceUsers -PlutusTx.makeLift ''InstanceUsers - data AaveRedeemer = - CreateReservesRedeemer (AssocMap.Map ReserveId Reserve) - | UpdateReservesRedeemer - | CreateUserConfigsRedeemer (AssocMap.Map UserConfigId UserConfig) - | UpdateUserConfigsRedeemer + StartRedeemer + | DepositRedeemer | WithdrawRedeemer | BorrowRedeemer | RepayRedeemer @@ -118,6 +98,7 @@ data AaveDatum = | ReservesDatum (AssocMap.Map ReserveId Reserve) | UserConfigsDatum (AssocMap.Map UserConfigId UserConfig) | DepositDatum + | WithdrawDatum | BorrowDatum | RepayDatum deriving stock (Show) @@ -140,14 +121,12 @@ makeAaveValidator :: Aave -> AaveRedeemer -> ScriptContext -> Bool -makeAaveValidator _ _ (CreateReservesRedeemer _) _ = True -makeAaveValidator _ _ UpdateReservesRedeemer _ = True -makeAaveValidator _ _ (CreateUserConfigsRedeemer _) _ = True -makeAaveValidator _ _ UpdateUserConfigsRedeemer _ = True -makeAaveValidator _ _ WithdrawRedeemer _ = True -makeAaveValidator _ _ BorrowRedeemer _ = True -makeAaveValidator _ _ RepayRedeemer _ = True -makeAaveValidator _ _ _ _ = False +makeAaveValidator _ _ StartRedeemer _ = True +makeAaveValidator _ _ DepositRedeemer _ = True +makeAaveValidator _ _ WithdrawRedeemer _ = True +makeAaveValidator _ _ BorrowRedeemer _ = True +makeAaveValidator _ _ RepayRedeemer _ = True +-- makeAaveValidator _ _ _ _ = False aaveProtocolName :: TokenName aaveProtocolName = "Aave" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 89bc52c7e..b2a99b895 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -88,8 +88,8 @@ start params = do void $ awaitTxConfirmed $ txId ledgerTx let reserveMap = AssocMap.fromList $ fmap (\params -> (cpAsset params, createReserve params)) params - State.putReserves aave reserveMap - State.putUserConfigs aave AssocMap.empty + State.putReserves aave Core.StartRedeemer reserveMap + State.putUserConfigs aave Core.StartRedeemer AssocMap.empty logInfo @String $ printf "started Aave %s at address %s" (show aave) (show $ Core.aaveAddress aave) pure aave @@ -151,13 +151,13 @@ deposit aave DepositParams {..} = do case AssocMap.lookup userConfigId userConfigs of Nothing -> State.addUserConfig - aave + aave Core.DepositRedeemer userConfigId UserConfig { ucUsingAsCollateral = True, ucDebt = Nothing } Just userConfig -> - State.updateUserConfig aave userConfigId $ userConfig { ucUsingAsCollateral = True } + State.updateUserConfig aave Core.DepositRedeemer userConfigId $ userConfig { ucUsingAsCollateral = True } - State.updateReserve aave dpAsset (reserve { rAmount = rAmount reserve + dpAmount }) + State.updateReserve aave Core.DepositRedeemer dpAsset (reserve { rAmount = rAmount reserve + dpAmount }) data WithdrawParams = WithdrawParams { @@ -180,13 +180,13 @@ withdraw aave WithdrawParams {..} = do when (wpAmount == balance) $ do let userConfigId = (wpAsset, wpFrom) userConfig <- State.findAaveUserConfig aave userConfigId - State.updateUserConfig aave userConfigId $ userConfig { ucUsingAsCollateral = False } + State.updateUserConfig aave Core.WithdrawRedeemer userConfigId $ userConfig { ucUsingAsCollateral = False } burnTx <- AToken.burnATokensFrom aave reserve wpTo wpAmount ledgerTx <- TxUtils.submitTxPair burnTx _ <- awaitTxConfirmed $ txId ledgerTx - State.updateReserve aave wpAsset (reserve { rAmount = rAmount reserve - wpAmount }) + State.updateReserve aave Core.WithdrawRedeemer wpAsset (reserve { rAmount = rAmount reserve - wpAmount }) data BorrowParams = BorrowParams { @@ -220,13 +220,13 @@ borrow aave BorrowParams {..} = do case AssocMap.lookup userConfigId userConfigs of Nothing -> State.addUserConfig - aave + aave Core.BorrowRedeemer userConfigId UserConfig { ucUsingAsCollateral = False, ucDebt = Just bpAmount } Just userConfig -> - State.updateUserConfig aave userConfigId $ userConfig { ucDebt = (+ bpAmount) <$> ucDebt userConfig } + State.updateUserConfig aave Core.BorrowRedeemer userConfigId $ userConfig { ucDebt = (+ bpAmount) <$> ucDebt userConfig } - State.updateReserve aave bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) + State.updateReserve aave Core.BorrowRedeemer bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) data RepayParams = RepayParams { @@ -255,9 +255,9 @@ repay aave RepayParams {..} = do Nothing -> throwError "User does not have any debt." Just userConfig -> - State.updateUserConfig aave userConfigId $ userConfig { ucDebt = subtract rpAmount <$> ucDebt userConfig } + State.updateUserConfig aave Core.RepayRedeemer userConfigId $ userConfig { ucDebt = subtract rpAmount <$> ucDebt userConfig } - State.updateReserve aave rpAsset (reserve { rAmount = rAmount reserve + rpAmount }) + State.updateReserve aave Core.RepayRedeemer rpAsset (reserve { rAmount = rAmount reserve + rpAmount }) type AaveUserSchema = BlockchainActions diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 6d4542fc5..05658d9b7 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -108,18 +108,18 @@ makeReserveHandle aave toRedeemer = toRedeemer = toRedeemer } -putReserves :: (HasBlockchainActions s) => Aave -> AssocMap.Map ReserveId Reserve -> Contract w s Text () -putReserves aave = putState aave $ makeReserveHandle aave Core.CreateReservesRedeemer +putReserves :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssocMap.Map ReserveId Reserve -> Contract w s Text () +putReserves aave redeemer = putState aave $ makeReserveHandle aave (const redeemer) -updateReserves :: (HasBlockchainActions s) => Aave -> OutputValue (AssocMap.Map ReserveId Reserve) -> Contract w s Text () -updateReserves aave = updateState aave $ makeReserveHandle aave (const Core.UpdateReservesRedeemer) +updateReserves :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map ReserveId Reserve) -> Contract w s Text () +updateReserves aave redeemer = updateState aave $ makeReserveHandle aave (const redeemer) -updateReserve :: (HasBlockchainActions s) => Aave -> ReserveId -> Reserve -> Contract w s Text () -updateReserve aave reserveId reserve = do +updateReserve :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> ReserveId -> Reserve -> Contract w s Text () +updateReserve aave redeemer reserveId reserve = do reservesOutput <- findAaveReserves aave _ <- maybe (throwError "Update failed: reserve not found") pure $ AssocMap.lookup reserveId (ovValue reservesOutput) - updateReserves aave $ Prelude.fmap (AssocMap.insert reserveId reserve) reservesOutput + updateReserves aave redeemer $ Prelude.fmap (AssocMap.insert reserveId reserve) reservesOutput makeUserHandle :: Aave -> (AssocMap.Map UserConfigId UserConfig -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map UserConfigId UserConfig) makeUserHandle aave toRedeemer = @@ -129,22 +129,22 @@ makeUserHandle aave toRedeemer = toRedeemer = toRedeemer } -putUserConfigs :: (HasBlockchainActions s) => Aave -> AssocMap.Map UserConfigId UserConfig -> Contract w s Text () -putUserConfigs aave = putState aave $ makeUserHandle aave Core.CreateUserConfigsRedeemer +putUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssocMap.Map UserConfigId UserConfig -> Contract w s Text () +putUserConfigs aave redeemer = putState aave $ makeUserHandle aave (const redeemer) -updateUserConfigs :: (HasBlockchainActions s) => Aave -> OutputValue (AssocMap.Map UserConfigId UserConfig) -> Contract w s Text () -updateUserConfigs aave = updateState aave $ makeUserHandle aave (const Core.UpdateUserConfigsRedeemer) +updateUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map UserConfigId UserConfig) -> Contract w s Text () +updateUserConfigs aave redeemer = updateState aave $ makeUserHandle aave (const redeemer) -addUserConfig :: (HasBlockchainActions s) => Aave -> UserConfigId -> UserConfig -> Contract w s Text () -addUserConfig aave userConfigId userConfig = do +addUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> UserConfigId -> UserConfig -> Contract w s Text () +addUserConfig aave redeemer userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (pure ()) (const $ throwError "Add user config failed: config exists") $ AssocMap.lookup userConfigId (ovValue configsOutput) - updateUserConfigs aave $ Prelude.fmap (AssocMap.insert userConfigId userConfig) configsOutput + updateUserConfigs aave redeemer $ Prelude.fmap (AssocMap.insert userConfigId userConfig) configsOutput -updateUserConfig :: (HasBlockchainActions s) => Aave -> UserConfigId -> UserConfig -> Contract w s Text () -updateUserConfig aave userConfigId userConfig = do +updateUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> UserConfigId -> UserConfig -> Contract w s Text () +updateUserConfig aave redeemer userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (throwError "Update failed: user config not found") pure $ AssocMap.lookup userConfigId (ovValue configsOutput) - updateUserConfigs aave $ Prelude.fmap (AssocMap.insert userConfigId userConfig) configsOutput + updateUserConfigs aave redeemer $ Prelude.fmap (AssocMap.insert userConfigId userConfig) configsOutput From b9d31c1a523883050bb95af78bb11b4af6eda0a0 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 2 Jun 2021 14:54:57 +0700 Subject: [PATCH 053/169] add prisms --- MetaLamp/lending-pool/plutus-starter.cabal | 1 + .../lending-pool/src/Plutus/Contracts/Core.hs | 2 ++ .../src/Plutus/Contracts/State.hs | 19 ++++--------------- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 4d707892c..d0cbe13d3 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -30,6 +30,7 @@ library bytestring, containers, text, + lens, -- Plutus: playground-common, plutus-contract, diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 5cb238640..fa61b78e5 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -15,6 +15,7 @@ module Plutus.Contracts.Core where +import qualified Control.Lens as Lens import Control.Monad hiding (fmap) import qualified Data.ByteString as BS import qualified Data.Map as Map @@ -105,6 +106,7 @@ data AaveDatum = PlutusTx.unstableMakeIsData ''AaveDatum PlutusTx.makeLift ''AaveDatum +Lens.makeClassyPrisms ''AaveDatum data AaveScript instance Scripts.ScriptType AaveScript where diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 05658d9b7..b7b62c693 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -10,6 +10,7 @@ module Plutus.Contracts.State where +import Control.Lens ((^?)) import Control.Monad hiding (fmap) import qualified Data.ByteString as BS import qualified Data.Map as Map @@ -55,22 +56,14 @@ findOutputBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Ma findOutputBy aave = Select.findOutputBy (Core.aaveAddress aave) findAaveOwnerToken :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue ()) -findAaveOwnerToken aave@Aave{..} = findOutputBy aave aaveProtocolInst pickOwnerDatum - -pickOwnerDatum :: AaveDatum -> Maybe () -pickOwnerDatum LendingPoolDatum = Just () -pickOwnerDatum _ = Nothing +findAaveOwnerToken aave@Aave{..} = findOutputBy aave aaveProtocolInst (^? Core._LendingPoolDatum) reserveStateToken, userStateToken :: Aave -> AssetClass reserveStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveReserve" userStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveUser" findAaveReserves :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map ReserveId Reserve)) -findAaveReserves aave = findOutputBy aave (reserveStateToken aave) pickReserves - -pickReserves :: AaveDatum -> Maybe (AssocMap.Map ReserveId Reserve) -pickReserves (Core.ReservesDatum r) = Just r -pickReserves _ = Nothing +findAaveReserves aave = findOutputBy aave (reserveStateToken aave) (^? Core._ReservesDatum) findAaveReserve :: HasBlockchainActions s => Aave -> ReserveId -> Contract w s Text Reserve findAaveReserve aave reserveId = do @@ -78,11 +71,7 @@ findAaveReserve aave reserveId = do maybe (throwError "Reserve not found") pure $ AssocMap.lookup reserveId reserves findAaveUserConfigs :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map UserConfigId UserConfig)) -findAaveUserConfigs aave = findOutputBy aave (userStateToken aave) pickUserConfig - -pickUserConfig :: AaveDatum -> Maybe (AssocMap.Map UserConfigId UserConfig) -pickUserConfig (Core.UserConfigsDatum userConfig) = Just userConfig -pickUserConfig _ = Nothing +findAaveUserConfigs aave = findOutputBy aave (userStateToken aave) (^? Core._UserConfigsDatum) findAaveUserConfig :: HasBlockchainActions s => Aave -> UserConfigId -> Contract w s Text UserConfig findAaveUserConfig aave userConfigId = do From 6a99101fd033b5a1ef4c46aaa0739ca456d6568c Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 2 Jun 2021 20:17:20 +0700 Subject: [PATCH 054/169] combine use cases transactions into one --- .../src/Plutus/Contracts/Endpoints.hs | 63 +++++++++++-------- .../src/Plutus/Contracts/State.hs | 19 +++--- .../lending-pool/src/Plutus/State/Update.hs | 12 ++-- 3 files changed, 51 insertions(+), 43 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index b2a99b895..c61a78350 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -50,9 +50,10 @@ import qualified Plutus.V1.Ledger.Address as Addr import Plutus.V1.Ledger.Value as Value import qualified PlutusTx import qualified PlutusTx.AssocMap as AssocMap -import PlutusTx.Prelude hiding (Semigroup (..), +import PlutusTx.Prelude hiding (Monoid (..), + Semigroup (..), mconcat, unless) -import Prelude (Semigroup (..)) +import Prelude (Monoid (..), Semigroup (..)) import qualified Prelude import Text.Printf (printf) @@ -83,14 +84,14 @@ start params = do Currency.forgeContract pkh [(Core.aaveProtocolName, 1)] let aave = Core.aave aaveToken payment = assetClassValue (Core.aaveProtocolInst aave) 1 - ledgerTx <- TxUtils.submitTxPair $ - TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.LendingPoolDatum payment - void $ awaitTxConfirmed $ txId ledgerTx + let aaveTokenTx = TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.LendingPoolDatum payment let reserveMap = AssocMap.fromList $ fmap (\params -> (cpAsset params, createReserve params)) params - State.putReserves aave Core.StartRedeemer reserveMap - State.putUserConfigs aave Core.StartRedeemer AssocMap.empty + reservesTx <- State.putReserves aave Core.StartRedeemer reserveMap + userConfigsTx <- State.putUserConfigs aave Core.StartRedeemer AssocMap.empty + ledgerTx <- TxUtils.submitTxPair $ aaveTokenTx <> reservesTx <> userConfigsTx + void $ awaitTxConfirmed $ txId ledgerTx logInfo @String $ printf "started Aave %s at address %s" (show aave) (show $ Core.aaveAddress aave) pure aave @@ -141,11 +142,9 @@ deposit :: (HasBlockchainActions s) => Aave -> DepositParams -> Contract w s Tex deposit aave DepositParams {..} = do reserve <- State.findAaveReserve aave dpAsset forgeTx <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount - ledgerTx <- TxUtils.submitTxPair forgeTx - _ <- awaitTxConfirmed $ txId ledgerTx wasZeroBalance <- (== 0) <$> balanceAt dpOnBehalfOf (rAToken reserve) - when wasZeroBalance $ do + userConfigsTx <- if wasZeroBalance then do userConfigs <- ovValue <$> State.findAaveUserConfigs aave let userConfigId = (rCurrency reserve, dpOnBehalfOf) case AssocMap.lookup userConfigId userConfigs of @@ -156,8 +155,13 @@ deposit aave DepositParams {..} = do UserConfig { ucUsingAsCollateral = True, ucDebt = Nothing } Just userConfig -> State.updateUserConfig aave Core.DepositRedeemer userConfigId $ userConfig { ucUsingAsCollateral = True } + else pure mempty - State.updateReserve aave Core.DepositRedeemer dpAsset (reserve { rAmount = rAmount reserve + dpAmount }) + reservesTx <- State.updateReserve aave Core.DepositRedeemer dpAsset (reserve { rAmount = rAmount reserve + dpAmount }) + + ledgerTx <- TxUtils.submitTxPair $ forgeTx <> reservesTx <> userConfigsTx + _ <- awaitTxConfirmed $ txId ledgerTx + pure () data WithdrawParams = WithdrawParams { @@ -177,16 +181,19 @@ withdraw aave WithdrawParams {..} = do reserve <- State.findAaveReserve aave wpAsset balance <- balanceAt wpFrom (rAToken reserve) - when (wpAmount == balance) $ do + userConfigsTx <- if (wpAmount == balance) then do let userConfigId = (wpAsset, wpFrom) userConfig <- State.findAaveUserConfig aave userConfigId State.updateUserConfig aave Core.WithdrawRedeemer userConfigId $ userConfig { ucUsingAsCollateral = False } + else pure mempty burnTx <- AToken.burnATokensFrom aave reserve wpTo wpAmount - ledgerTx <- TxUtils.submitTxPair burnTx - _ <- awaitTxConfirmed $ txId ledgerTx - State.updateReserve aave Core.WithdrawRedeemer wpAsset (reserve { rAmount = rAmount reserve - wpAmount }) + reservesTx <- State.updateReserve aave Core.WithdrawRedeemer wpAsset (reserve { rAmount = rAmount reserve - wpAmount }) + + ledgerTx <- TxUtils.submitTxPair $ burnTx <> reservesTx <> userConfigsTx + _ <- awaitTxConfirmed $ txId ledgerTx + pure () data BorrowParams = BorrowParams { @@ -210,14 +217,12 @@ borrow aave BorrowParams {..} = do let inputs = (\(ref, tx) -> OutputValue ref tx Core.BorrowRedeemer) <$> Map.toList utxos let payment = assetClassValue (rCurrency reserve) bpAmount let remainder = assetClassValue (rCurrency reserve) (rAmount reserve - bpAmount) - ledgerTx <- TxUtils.submitTxPair $ - TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs bpOnBehalfOf payment <> - TxUtils.mustPayToScript (Core.aaveInstance aave) bpOnBehalfOf Core.BorrowDatum remainder - _ <- awaitTxConfirmed $ txId ledgerTx + let disbursementTx = TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs bpOnBehalfOf payment <> + TxUtils.mustPayToScript (Core.aaveInstance aave) bpOnBehalfOf Core.BorrowDatum remainder userConfigs <- ovValue <$> State.findAaveUserConfigs aave let userConfigId = (rCurrency reserve, bpOnBehalfOf) - case AssocMap.lookup userConfigId userConfigs of + userConfigsTx <- case AssocMap.lookup userConfigId userConfigs of Nothing -> State.addUserConfig aave Core.BorrowRedeemer @@ -226,7 +231,11 @@ borrow aave BorrowParams {..} = do Just userConfig -> State.updateUserConfig aave Core.BorrowRedeemer userConfigId $ userConfig { ucDebt = (+ bpAmount) <$> ucDebt userConfig } - State.updateReserve aave Core.BorrowRedeemer bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) + reservesTx <- State.updateReserve aave Core.BorrowRedeemer bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) + + ledgerTx <- TxUtils.submitTxPair $ disbursementTx <> reservesTx <> userConfigsTx + _ <- awaitTxConfirmed $ txId ledgerTx + pure () data RepayParams = RepayParams { @@ -245,19 +254,21 @@ repay aave RepayParams {..} = do reserve <- State.findAaveReserve aave rpAsset let payment = assetClassValue (rCurrency reserve) rpAmount - ledgerTx <- TxUtils.submitTxPair $ - TxUtils.mustPayToScript (Core.aaveInstance aave) rpOnBehalfOf Core.RepayDatum payment - _ <- awaitTxConfirmed $ txId ledgerTx + let reimbursementTx = TxUtils.mustPayToScript (Core.aaveInstance aave) rpOnBehalfOf Core.RepayDatum payment userConfigs <- ovValue <$> State.findAaveUserConfigs aave let userConfigId = (rCurrency reserve, rpOnBehalfOf) - case AssocMap.lookup userConfigId userConfigs of + userConfigsTx <- case AssocMap.lookup userConfigId userConfigs of Nothing -> throwError "User does not have any debt." Just userConfig -> State.updateUserConfig aave Core.RepayRedeemer userConfigId $ userConfig { ucDebt = subtract rpAmount <$> ucDebt userConfig } - State.updateReserve aave Core.RepayRedeemer rpAsset (reserve { rAmount = rAmount reserve + rpAmount }) + reservesTx <- State.updateReserve aave Core.RepayRedeemer rpAsset (reserve { rAmount = rAmount reserve + rpAmount }) + + ledgerTx <- TxUtils.submitTxPair $ reimbursementTx <> reservesTx <> userConfigsTx + _ <- awaitTxConfirmed $ txId ledgerTx + pure () type AaveUserSchema = BlockchainActions diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index b7b62c693..4f84e2487 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -35,6 +35,7 @@ import Plutus.Contracts.Core (Aave (..), AaveDatum (..), import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken +import qualified Plutus.Contracts.TxUtils as TxUtils import Plutus.OutputValue (OutputValue (..)) import qualified Plutus.State.Select as Select import Plutus.State.Update (PutStateHandle (..), @@ -78,7 +79,7 @@ findAaveUserConfig aave userConfigId = do configs <- ovValue <$> findAaveUserConfigs aave maybe (throwError "UserConfig not found") pure $ AssocMap.lookup userConfigId configs -putState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> a -> Contract w s Text () +putState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> a -> Contract w s Text (TxUtils.TxPair AaveScript) putState aave stateHandle newState = do ownerTokenOutput <- fmap (const Core.LendingPoolDatum) <$> findAaveOwnerToken aave Update.putState @@ -86,7 +87,7 @@ putState aave stateHandle newState = do stateHandle newState -updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> OutputValue a -> Contract w s Text () +updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> OutputValue a -> Contract w s Text (TxUtils.TxPair AaveScript) updateState aave = Update.updateState (Core.aaveInstance aave) makeReserveHandle :: Aave -> (AssocMap.Map ReserveId Reserve -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map ReserveId Reserve) @@ -97,13 +98,13 @@ makeReserveHandle aave toRedeemer = toRedeemer = toRedeemer } -putReserves :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssocMap.Map ReserveId Reserve -> Contract w s Text () +putReserves :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssocMap.Map ReserveId Reserve -> Contract w s Text (TxUtils.TxPair AaveScript) putReserves aave redeemer = putState aave $ makeReserveHandle aave (const redeemer) -updateReserves :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map ReserveId Reserve) -> Contract w s Text () +updateReserves :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map ReserveId Reserve) -> Contract w s Text (TxUtils.TxPair AaveScript) updateReserves aave redeemer = updateState aave $ makeReserveHandle aave (const redeemer) -updateReserve :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> ReserveId -> Reserve -> Contract w s Text () +updateReserve :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> ReserveId -> Reserve -> Contract w s Text (TxUtils.TxPair AaveScript) updateReserve aave redeemer reserveId reserve = do reservesOutput <- findAaveReserves aave _ <- maybe (throwError "Update failed: reserve not found") pure $ @@ -118,20 +119,20 @@ makeUserHandle aave toRedeemer = toRedeemer = toRedeemer } -putUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssocMap.Map UserConfigId UserConfig -> Contract w s Text () +putUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssocMap.Map UserConfigId UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript) putUserConfigs aave redeemer = putState aave $ makeUserHandle aave (const redeemer) -updateUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map UserConfigId UserConfig) -> Contract w s Text () +updateUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map UserConfigId UserConfig) -> Contract w s Text (TxUtils.TxPair AaveScript) updateUserConfigs aave redeemer = updateState aave $ makeUserHandle aave (const redeemer) -addUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> UserConfigId -> UserConfig -> Contract w s Text () +addUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> UserConfigId -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript) addUserConfig aave redeemer userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (pure ()) (const $ throwError "Add user config failed: config exists") $ AssocMap.lookup userConfigId (ovValue configsOutput) updateUserConfigs aave redeemer $ Prelude.fmap (AssocMap.insert userConfigId userConfig) configsOutput -updateUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> UserConfigId -> UserConfig -> Contract w s Text () +updateUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> UserConfigId -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript) updateUserConfig aave redeemer userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (throwError "Update failed: user config not found") pure $ diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index 23aabaf92..505c091df 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -82,10 +82,10 @@ putState :: PutStateHandle scriptType -> StateHandle scriptType a -> a -> - Contract w s Text () + Contract w s Text (TxUtils.TxPair scriptType) putState PutStateHandle {..} StateHandle{..} newState = do pkh <- pubKeyHash <$> ownPubKey - ledgerTx <- TxUtils.submitTxPair $ + pure $ TxUtils.mustForgeValue (makeStatePolicy ownerToken) (assetClassValue stateToken 1) <> TxUtils.mustPayToScript script pkh (toDatum newState) (assetClassValue stateToken 1) <> TxUtils.mustRoundTripToScript @@ -94,23 +94,19 @@ putState PutStateHandle {..} StateHandle{..} newState = do (ovValue ownerTokenOutput) pkh (assetClassValue ownerToken 1) - _ <- awaitTxConfirmed $ txId ledgerTx - pure () updateState :: (HasBlockchainActions s, IsData (DatumType scriptType), IsData (RedeemerType scriptType)) => Scripts.ScriptInstance scriptType -> StateHandle scriptType a -> OutputValue a -> - Contract w s Text () + Contract w s Text (TxUtils.TxPair scriptType) updateState script StateHandle{..} output = do pkh <- pubKeyHash <$> ownPubKey - ledgerTx <- TxUtils.submitTxPair $ + pure $ TxUtils.mustRoundTripToScript script [toRedeemer Prelude.<$> output] (toDatum . ovValue $ output) pkh (assetClassValue stateToken 1) - _ <- awaitTxConfirmed $ txId ledgerTx - pure () From ac131fd332b315209b3f26ec03c44c2a8bff4c41 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 2 Jun 2021 20:33:08 +0700 Subject: [PATCH 055/169] submit state minting transactions one by one --- MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index c61a78350..5840d180e 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -85,13 +85,17 @@ start params = do let aave = Core.aave aaveToken payment = assetClassValue (Core.aaveProtocolInst aave) 1 let aaveTokenTx = TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.LendingPoolDatum payment + ledgerTx <- TxUtils.submitTxPair aaveTokenTx + void $ awaitTxConfirmed $ txId ledgerTx let reserveMap = AssocMap.fromList $ fmap (\params -> (cpAsset params, createReserve params)) params reservesTx <- State.putReserves aave Core.StartRedeemer reserveMap + ledgerTx <- TxUtils.submitTxPair reservesTx + void $ awaitTxConfirmed $ txId ledgerTx userConfigsTx <- State.putUserConfigs aave Core.StartRedeemer AssocMap.empty - - ledgerTx <- TxUtils.submitTxPair $ aaveTokenTx <> reservesTx <> userConfigsTx + ledgerTx <- TxUtils.submitTxPair userConfigsTx void $ awaitTxConfirmed $ txId ledgerTx + logInfo @String $ printf "started Aave %s at address %s" (show aave) (show $ Core.aaveAddress aave) pure aave From 4855cbc1f03202e0d0d472f4883fa719c0f14373 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 3 Jun 2021 20:31:32 +0700 Subject: [PATCH 056/169] validate putting state is authorized by pool operator --- .../lending-pool/src/Plutus/Contracts/Core.hs | 21 +++++++++++++++++-- .../src/Plutus/Contracts/Endpoints.hs | 3 ++- .../src/Plutus/Contracts/State.hs | 4 ++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index fa61b78e5..2925ddc0c 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -5,6 +5,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} @@ -15,6 +16,7 @@ module Plutus.Contracts.Core where +import Control.Lens ((^?)) import qualified Control.Lens as Lens import Control.Monad hiding (fmap) import qualified Data.ByteString as BS @@ -94,8 +96,10 @@ data AaveRedeemer = PlutusTx.unstableMakeIsData ''AaveRedeemer PlutusTx.makeLift ''AaveRedeemer +type LendingPoolOperator = PubKeyHash + data AaveDatum = - LendingPoolDatum + LendingPoolDatum LendingPoolOperator | ReservesDatum (AssocMap.Map ReserveId Reserve) | UserConfigsDatum (AssocMap.Map UserConfigId UserConfig) | DepositDatum @@ -123,13 +127,26 @@ makeAaveValidator :: Aave -> AaveRedeemer -> ScriptContext -> Bool -makeAaveValidator _ _ StartRedeemer _ = True +makeAaveValidator aave datum StartRedeemer ctx = trace "StartRedeemer" $ validateStart aave datum ctx makeAaveValidator _ _ DepositRedeemer _ = True makeAaveValidator _ _ WithdrawRedeemer _ = True makeAaveValidator _ _ BorrowRedeemer _ = True makeAaveValidator _ _ RepayRedeemer _ = True -- makeAaveValidator _ _ _ _ = False +validateStart :: Aave -> AaveDatum -> ScriptContext -> Bool +validateStart aave (LendingPoolDatum operator) ctx = traceIfFalse "Lending Pool Datum management is not authorized by operator" (isSignedByOperator && hasOutputWithSameOperator) + where + txInfo = scriptContextTxInfo ctx + isSignedByOperator = txSignedBy txInfo operator + + (scriptsHash, scriptsDatumHash) = ownHashes ctx + hasOutputWithSameOperator = case scriptOutputsAt scriptsHash txInfo of + outs -> isJust $ AssocMap.lookup scriptsDatumHash $ AssocMap.fromList outs +validateStart aave (ReservesDatum reserves) ctx = trace "ReservesDatum" False +validateStart aave (UserConfigsDatum configs) ctx = trace "UserConfigsDatum" False +validateStart aave _ ctx = trace "OtherDatum" False + aaveProtocolName :: TokenName aaveProtocolName = "Aave" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 5840d180e..8b3ea07e5 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -84,7 +84,8 @@ start params = do Currency.forgeContract pkh [(Core.aaveProtocolName, 1)] let aave = Core.aave aaveToken payment = assetClassValue (Core.aaveProtocolInst aave) 1 - let aaveTokenTx = TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.LendingPoolDatum payment + let aaveTokenTx = TxUtils.mustPayToScript (Core.aaveInstance aave) pkh (Core.LendingPoolDatum pkh) payment + -- TODO how to ensure that newly minted owner token is paid to the script before someone else spends it? ledgerTx <- TxUtils.submitTxPair aaveTokenTx void $ awaitTxConfirmed $ txId ledgerTx diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 4f84e2487..2a77e1c69 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -56,7 +56,7 @@ findOutputsBy aave = Select.findOutputsBy (Core.aaveAddress aave) findOutputBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text (OutputValue a) findOutputBy aave = Select.findOutputBy (Core.aaveAddress aave) -findAaveOwnerToken :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue ()) +findAaveOwnerToken :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue Core.LendingPoolOperator) findAaveOwnerToken aave@Aave{..} = findOutputBy aave aaveProtocolInst (^? Core._LendingPoolDatum) reserveStateToken, userStateToken :: Aave -> AssetClass @@ -81,7 +81,7 @@ findAaveUserConfig aave userConfigId = do putState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> a -> Contract w s Text (TxUtils.TxPair AaveScript) putState aave stateHandle newState = do - ownerTokenOutput <- fmap (const Core.LendingPoolDatum) <$> findAaveOwnerToken aave + ownerTokenOutput <- fmap Core.LendingPoolDatum <$> findAaveOwnerToken aave Update.putState PutStateHandle { script = Core.aaveInstance aave, ownerToken = aaveProtocolInst aave, ownerTokenOutput = ownerTokenOutput } stateHandle From b309512d165a2e7aa6cda066acb84b37f1ff1f00 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 4 Jun 2021 13:45:47 +0700 Subject: [PATCH 057/169] refactor error msgs --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 2925ddc0c..bde2b9255 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -135,7 +135,9 @@ makeAaveValidator _ _ RepayRedeemer _ = True -- makeAaveValidator _ _ _ _ = False validateStart :: Aave -> AaveDatum -> ScriptContext -> Bool -validateStart aave (LendingPoolDatum operator) ctx = traceIfFalse "Lending Pool Datum management is not authorized by operator" (isSignedByOperator && hasOutputWithSameOperator) +validateStart aave (LendingPoolDatum operator) ctx = + traceIfFalse "validateStart: Lending Pool Datum management is not authorized by operator" + (isSignedByOperator && hasOutputWithSameOperator) where txInfo = scriptContextTxInfo ctx isSignedByOperator = txSignedBy txInfo operator @@ -143,9 +145,7 @@ validateStart aave (LendingPoolDatum operator) ctx = traceIfFalse "Lending Pool (scriptsHash, scriptsDatumHash) = ownHashes ctx hasOutputWithSameOperator = case scriptOutputsAt scriptsHash txInfo of outs -> isJust $ AssocMap.lookup scriptsDatumHash $ AssocMap.fromList outs -validateStart aave (ReservesDatum reserves) ctx = trace "ReservesDatum" False -validateStart aave (UserConfigsDatum configs) ctx = trace "UserConfigsDatum" False -validateStart aave _ ctx = trace "OtherDatum" False +validateStart aave _ ctx = trace "validateStart: Lending Pool Datum management is not allowed" False aaveProtocolName :: TokenName aaveProtocolName = "Aave" From ba9df72cb4abdbf882e30a24bac82a8b616a7fe7 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 4 Jun 2021 17:28:46 +0700 Subject: [PATCH 058/169] wip user configs validation --- MetaLamp/lending-pool/plutus-starter.cabal | 2 +- .../src/Ext/Plutus/Ledger/Contexts.hs | 15 +++++++++++ .../lending-pool/src/Plutus/Contracts/Core.hs | 25 +++++++++++++++++-- .../src/Plutus/Contracts/State.hs | 11 ++++---- .../lending-pool/src/Plutus/OutputValue.hs | 9 +++++-- .../lending-pool/src/Plutus/State/Update.hs | 3 +++ 6 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index d0cbe13d3..561025cc8 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -23,7 +23,7 @@ maintainer: Your email library exposed-modules: - Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.State Plutus.State.Select Plutus.State.Update Plutus.Contracts.TxUtils Plutus.OutputValue + Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.State Plutus.State.Select Plutus.State.Update Plutus.Contracts.TxUtils Plutus.OutputValue Ext.Plutus.Ledger.Contexts build-depends: base >= 4.9 && < 5, aeson, diff --git a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs new file mode 100644 index 000000000..97c543f4f --- /dev/null +++ b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs @@ -0,0 +1,15 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{-# OPTIONS_GHC -fno-specialise #-} + +module Ext.Plutus.Ledger.Contexts where + +import Ledger (DatumHash, Value) +import PlutusTx.Prelude (Eq ((==)), Maybe, find, fst, (<$>)) + +{-# INLINABLE findDatumHashByValue #-} +-- | Find the hash of a datum, if it is part of the pending transaction's +-- outputs +findDatumHashByValue :: Value -> [(DatumHash, Value)] -> Maybe DatumHash +findDatumHashByValue val outs = fst <$> find f outs + where + f (_, val') = val' == val diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index bde2b9255..9fae99209 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -23,6 +23,7 @@ import qualified Data.ByteString as BS import qualified Data.Map as Map import Data.Text (Text, pack) import Data.Void (Void) +import Ext.Plutus.Ledger.Contexts (findDatumHashByValue) import Ledger hiding (singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints @@ -101,7 +102,7 @@ type LendingPoolOperator = PubKeyHash data AaveDatum = LendingPoolDatum LendingPoolOperator | ReservesDatum (AssocMap.Map ReserveId Reserve) - | UserConfigsDatum (AssocMap.Map UserConfigId UserConfig) + | UserConfigsDatum AssetClass (AssocMap.Map UserConfigId UserConfig) | DepositDatum | WithdrawDatum | BorrowDatum @@ -112,6 +113,11 @@ PlutusTx.unstableMakeIsData ''AaveDatum PlutusTx.makeLift ''AaveDatum Lens.makeClassyPrisms ''AaveDatum +{-# INLINABLE pickUserConfigs #-} +pickUserConfigs :: AaveDatum -> Maybe (AssocMap.Map UserConfigId UserConfig) +pickUserConfigs (UserConfigsDatum _ configs) = Just configs +pickUserConfigs _ = Nothing + data AaveScript instance Scripts.ScriptType AaveScript where type instance RedeemerType AaveScript = AaveRedeemer @@ -128,7 +134,7 @@ makeAaveValidator :: Aave -> ScriptContext -> Bool makeAaveValidator aave datum StartRedeemer ctx = trace "StartRedeemer" $ validateStart aave datum ctx -makeAaveValidator _ _ DepositRedeemer _ = True +makeAaveValidator aave datum DepositRedeemer ctx = trace "DepositRedeemer" $ validateDeposit aave datum ctx makeAaveValidator _ _ WithdrawRedeemer _ = True makeAaveValidator _ _ BorrowRedeemer _ = True makeAaveValidator _ _ RepayRedeemer _ = True @@ -147,6 +153,21 @@ validateStart aave (LendingPoolDatum operator) ctx = outs -> isJust $ AssocMap.lookup scriptsDatumHash $ AssocMap.fromList outs validateStart aave _ ctx = trace "validateStart: Lending Pool Datum management is not allowed" False +validateDeposit :: Aave -> AaveDatum -> ScriptContext -> Bool +validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx = trace "UserConfigsDatum" $ isNothing userConfigsOutputDatum + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + userConfigsOutputDatumHash = findDatumHashByValue (assetClassValue stateToken 1) $ scriptOutputsAt scriptsHash txInfo + userConfigsOutputDatum :: Maybe (AssocMap.Map UserConfigId UserConfig) + userConfigsOutputDatum = userConfigsOutputDatumHash >>= (`findDatum` txInfo) >>= (PlutusTx.fromData . getDatum) >>= pickUserConfigs +validateDeposit aave (LendingPoolDatum _) ctx = trace "LendingPoolDatum" False +validateDeposit aave (ReservesDatum _) ctx = trace "ReservesDatum" False +validateDeposit aave DepositDatum ctx = trace "DepositDatum" False +validateDeposit aave WithdrawDatum ctx = trace "WithdrawDatum" False +validateDeposit aave BorrowDatum ctx = trace "BorrowDatum" False +validateDeposit aave RepayDatum ctx = trace "RepayDatum" False + aaveProtocolName :: TokenName aaveProtocolName = "Aave" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 2a77e1c69..eedb2b388 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -10,7 +10,7 @@ module Plutus.Contracts.State where -import Control.Lens ((^?)) +import Control.Lens import Control.Monad hiding (fmap) import qualified Data.ByteString as BS import qualified Data.Map as Map @@ -36,7 +36,7 @@ import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken import qualified Plutus.Contracts.TxUtils as TxUtils -import Plutus.OutputValue (OutputValue (..)) +import Plutus.OutputValue (OutputValue (..),_ovValue) import qualified Plutus.State.Select as Select import Plutus.State.Update (PutStateHandle (..), StateHandle (..)) @@ -72,7 +72,7 @@ findAaveReserve aave reserveId = do maybe (throwError "Reserve not found") pure $ AssocMap.lookup reserveId reserves findAaveUserConfigs :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map UserConfigId UserConfig)) -findAaveUserConfigs aave = findOutputBy aave (userStateToken aave) (^? Core._UserConfigsDatum) +findAaveUserConfigs aave = findOutputBy aave (userStateToken aave) (^? Core._UserConfigsDatum . _2) findAaveUserConfig :: HasBlockchainActions s => Aave -> UserConfigId -> Contract w s Text UserConfig findAaveUserConfig aave userConfigId = do @@ -113,9 +113,10 @@ updateReserve aave redeemer reserveId reserve = do makeUserHandle :: Aave -> (AssocMap.Map UserConfigId UserConfig -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map UserConfigId UserConfig) makeUserHandle aave toRedeemer = + let stateToken = userStateToken aave in StateHandle { - stateToken = userStateToken aave, - toDatum = Core.UserConfigsDatum, + stateToken = stateToken, + toDatum = Core.UserConfigsDatum stateToken, toRedeemer = toRedeemer } diff --git a/MetaLamp/lending-pool/src/Plutus/OutputValue.hs b/MetaLamp/lending-pool/src/Plutus/OutputValue.hs index 88b10d599..c95a9ffa8 100644 --- a/MetaLamp/lending-pool/src/Plutus/OutputValue.hs +++ b/MetaLamp/lending-pool/src/Plutus/OutputValue.hs @@ -1,9 +1,12 @@ -{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FunctionalDependencies #-} +{-# LANGUAGE TemplateHaskell #-} module Plutus.OutputValue where +import Control.Lens (makeClassy_) import Ledger (TxOutRef, TxOutTx) - import qualified PlutusTx.Prelude as PlutuxTx data OutputValue a = @@ -12,3 +15,5 @@ data OutputValue a = ovOutTx :: TxOutTx, ovValue :: a } deriving (Prelude.Show, Prelude.Functor) + +makeClassy_ ''OutputValue diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index 505c091df..b2ff84d4e 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -45,6 +45,9 @@ import qualified Prelude type OwnerToken = AssetClass -- State token can be only be forged when there is an input containing an owner token +-- TODO: add rules: +-- 1. output contains same owner token with same owner (aave script) +-- 2. output contains the forged state token with same owner (aave script) {-# INLINABLE validateStateForging #-} validateStateForging :: OwnerToken -> ScriptContext -> Bool validateStateForging ownerToken ctx = From a8ad71cd2972b405aa2a6be0efe894aec3623b3e Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 4 Jun 2021 20:09:12 +0700 Subject: [PATCH 059/169] add user configs validator for deposit --- .../lending-pool/src/Plutus/Contracts/Core.hs | 47 +++++++++++++------ .../src/Plutus/Contracts/Endpoints.hs | 9 ++-- .../lending-pool/src/Plutus/State/Update.hs | 20 ++++---- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 9fae99209..d699248d9 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -88,7 +88,7 @@ PlutusTx.makeLift ''UserConfig data AaveRedeemer = StartRedeemer - | DepositRedeemer + | DepositRedeemer UserConfigId | WithdrawRedeemer | BorrowRedeemer | RepayRedeemer @@ -114,8 +114,8 @@ PlutusTx.makeLift ''AaveDatum Lens.makeClassyPrisms ''AaveDatum {-# INLINABLE pickUserConfigs #-} -pickUserConfigs :: AaveDatum -> Maybe (AssocMap.Map UserConfigId UserConfig) -pickUserConfigs (UserConfigsDatum _ configs) = Just configs +pickUserConfigs :: AaveDatum -> Maybe (AssetClass, AssocMap.Map UserConfigId UserConfig) +pickUserConfigs (UserConfigsDatum stateToken configs) = Just (stateToken, configs) pickUserConfigs _ = Nothing data AaveScript @@ -134,7 +134,7 @@ makeAaveValidator :: Aave -> ScriptContext -> Bool makeAaveValidator aave datum StartRedeemer ctx = trace "StartRedeemer" $ validateStart aave datum ctx -makeAaveValidator aave datum DepositRedeemer ctx = trace "DepositRedeemer" $ validateDeposit aave datum ctx +makeAaveValidator aave datum (DepositRedeemer userConfigId) ctx = trace "DepositRedeemer" $ validateDeposit aave datum ctx userConfigId makeAaveValidator _ _ WithdrawRedeemer _ = True makeAaveValidator _ _ BorrowRedeemer _ = True makeAaveValidator _ _ RepayRedeemer _ = True @@ -153,20 +153,37 @@ validateStart aave (LendingPoolDatum operator) ctx = outs -> isJust $ AssocMap.lookup scriptsDatumHash $ AssocMap.fromList outs validateStart aave _ ctx = trace "validateStart: Lending Pool Datum management is not allowed" False -validateDeposit :: Aave -> AaveDatum -> ScriptContext -> Bool -validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx = trace "UserConfigsDatum" $ isNothing userConfigsOutputDatum +validateDeposit :: Aave -> AaveDatum -> ScriptContext -> UserConfigId -> Bool +validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId = + traceIfFalse "validateDeposit: User Configs Datum change is not valid" isValidUserConfigsTransformation where txInfo = scriptContextTxInfo ctx (scriptsHash, scriptsDatumHash) = ownHashes ctx - userConfigsOutputDatumHash = findDatumHashByValue (assetClassValue stateToken 1) $ scriptOutputsAt scriptsHash txInfo - userConfigsOutputDatum :: Maybe (AssocMap.Map UserConfigId UserConfig) - userConfigsOutputDatum = userConfigsOutputDatumHash >>= (`findDatum` txInfo) >>= (PlutusTx.fromData . getDatum) >>= pickUserConfigs -validateDeposit aave (LendingPoolDatum _) ctx = trace "LendingPoolDatum" False -validateDeposit aave (ReservesDatum _) ctx = trace "ReservesDatum" False -validateDeposit aave DepositDatum ctx = trace "DepositDatum" False -validateDeposit aave WithdrawDatum ctx = trace "WithdrawDatum" False -validateDeposit aave BorrowDatum ctx = trace "BorrowDatum" False -validateDeposit aave RepayDatum ctx = trace "RepayDatum" False + userConfigsOutputDatumHash = + findDatumHashByValue (assetClassValue stateToken 1) $ scriptOutputsAt scriptsHash txInfo + userConfigsOutputDatum :: + Maybe (AssetClass, AssocMap.Map UserConfigId UserConfig) + userConfigsOutputDatum = + userConfigsOutputDatumHash >>= (`findDatum` txInfo) >>= (PlutusTx.fromData . getDatum) >>= pickUserConfigs + + isValidUserConfigsTransformation :: Bool + isValidUserConfigsTransformation = + maybe False checkUserConfigs userConfigsOutputDatum + checkUserConfigs :: + (AssetClass, AssocMap.Map UserConfigId UserConfig) -> Bool + checkUserConfigs (newStateToken, newUserConfigs) = + newStateToken == stateToken && + maybe False checkRedeemerConfig (AssocMap.lookup userConfigId newUserConfigs) + checkRedeemerConfig :: UserConfig -> Bool + checkRedeemerConfig UserConfig{..} = ucUsingAsCollateral + +validateDeposit aave (LendingPoolDatum _) ctx userConfigId = trace "LendingPoolDatum" False +validateDeposit aave (ReservesDatum _) ctx userConfigId = trace "ReservesDatum" False +validateDeposit aave DepositDatum ctx userConfigId = trace "DepositDatum" False +validateDeposit aave WithdrawDatum ctx userConfigId = trace "WithdrawDatum" False +validateDeposit aave BorrowDatum ctx userConfigId = trace "BorrowDatum" False +validateDeposit aave RepayDatum ctx userConfigId = trace "RepayDatum" False + aaveProtocolName :: TokenName aaveProtocolName = "Aave" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 8b3ea07e5..4f21b2e44 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -148,21 +148,22 @@ deposit aave DepositParams {..} = do reserve <- State.findAaveReserve aave dpAsset forgeTx <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount + let userConfigId = (rCurrency reserve, dpOnBehalfOf) wasZeroBalance <- (== 0) <$> balanceAt dpOnBehalfOf (rAToken reserve) userConfigsTx <- if wasZeroBalance then do userConfigs <- ovValue <$> State.findAaveUserConfigs aave - let userConfigId = (rCurrency reserve, dpOnBehalfOf) case AssocMap.lookup userConfigId userConfigs of Nothing -> State.addUserConfig - aave Core.DepositRedeemer + aave + (Core.DepositRedeemer userConfigId) userConfigId UserConfig { ucUsingAsCollateral = True, ucDebt = Nothing } Just userConfig -> - State.updateUserConfig aave Core.DepositRedeemer userConfigId $ userConfig { ucUsingAsCollateral = True } + State.updateUserConfig aave (Core.DepositRedeemer userConfigId) userConfigId $ userConfig { ucUsingAsCollateral = True } else pure mempty - reservesTx <- State.updateReserve aave Core.DepositRedeemer dpAsset (reserve { rAmount = rAmount reserve + dpAmount }) + reservesTx <- State.updateReserve aave (Core.DepositRedeemer userConfigId) dpAsset (reserve { rAmount = rAmount reserve + dpAmount }) ledgerTx <- TxUtils.submitTxPair $ forgeTx <> reservesTx <> userConfigsTx _ <- awaitTxConfirmed $ txId ledgerTx diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index b2ff84d4e..9d0082434 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -49,24 +49,25 @@ type OwnerToken = AssetClass -- 1. output contains same owner token with same owner (aave script) -- 2. output contains the forged state token with same owner (aave script) {-# INLINABLE validateStateForging #-} -validateStateForging :: OwnerToken -> ScriptContext -> Bool -validateStateForging ownerToken ctx = +validateStateForging :: OwnerToken -> TokenName -> ScriptContext -> Bool +validateStateForging ownerToken tokenName ctx = any hasOwnerToken inputValues || traceError "State forging without OwnerToken input" where inputs = txInfoInputs (scriptContextTxInfo ctx) inputValues = txOutValue . txInInfoResolved <$> inputs hasOwnerToken value = assetClassValueOf value ownerToken == 1 -makeStatePolicy :: OwnerToken -> MonetaryPolicy -makeStatePolicy ownerToken = mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| Scripts.wrapMonetaryPolicy . validateStateForging ||]) +makeStatePolicy :: OwnerToken -> TokenName -> MonetaryPolicy +makeStatePolicy ownerToken tokenName = mkMonetaryPolicyScript $ + $$(PlutusTx.compile [|| \ot tn -> Scripts.wrapMonetaryPolicy $ validateStateForging ot tn||]) `PlutusTx.applyCode` PlutusTx.liftCode ownerToken + `PlutusTx.applyCode` PlutusTx.liftCode tokenName -makeStateCurrency :: OwnerToken -> CurrencySymbol -makeStateCurrency = scriptCurrencySymbol . makeStatePolicy +makeStateCurrency :: OwnerToken -> TokenName -> CurrencySymbol +makeStateCurrency ownerToken tokenName = scriptCurrencySymbol $ makeStatePolicy ownerToken tokenName makeStateToken :: OwnerToken -> TokenName -> AssetClass -makeStateToken ownerToken = assetClass (makeStateCurrency ownerToken) +makeStateToken ownerToken tokenName = assetClass (makeStateCurrency ownerToken tokenName) tokenName data PutStateHandle scriptType = PutStateHandle { script :: Scripts.ScriptInstance scriptType, @@ -88,8 +89,9 @@ putState :: Contract w s Text (TxUtils.TxPair scriptType) putState PutStateHandle {..} StateHandle{..} newState = do pkh <- pubKeyHash <$> ownPubKey + let (_, stateTokenName) = unAssetClass stateToken pure $ - TxUtils.mustForgeValue (makeStatePolicy ownerToken) (assetClassValue stateToken 1) + TxUtils.mustForgeValue (makeStatePolicy ownerToken stateTokenName) (assetClassValue stateToken 1) <> TxUtils.mustPayToScript script pkh (toDatum newState) (assetClassValue stateToken 1) <> TxUtils.mustRoundTripToScript script From ad72f796ab61e6e330466aba60991599642641f9 Mon Sep 17 00:00:00 2001 From: stanislav-az Date: Sat, 5 Jun 2021 19:14:54 +0700 Subject: [PATCH 060/169] wip add reserves validator for deposit --- .../src/Ext/Plutus/Ledger/Contexts.hs | 10 +++++- .../lending-pool/src/Plutus/Contracts/Core.hs | 34 +++++++++++++++++-- .../src/Plutus/Contracts/State.hs | 5 +-- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs index 97c543f4f..44c1149cd 100644 --- a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs +++ b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs @@ -4,7 +4,7 @@ module Ext.Plutus.Ledger.Contexts where import Ledger (DatumHash, Value) -import PlutusTx.Prelude (Eq ((==)), Maybe, find, fst, (<$>)) +import PlutusTx.Prelude (Eq ((==)), Maybe, find, fst, snd, (<$>)) {-# INLINABLE findDatumHashByValue #-} -- | Find the hash of a datum, if it is part of the pending transaction's @@ -13,3 +13,11 @@ findDatumHashByValue :: Value -> [(DatumHash, Value)] -> Maybe DatumHash findDatumHashByValue val outs = fst <$> find f outs where f (_, val') = val' == val + +{-# INLINABLE findValueByDatumHash #-} +-- | Find the hash of a datum, if it is part of the pending transaction's +-- outputs +findValueByDatumHash :: DatumHash -> [(DatumHash, Value)] -> Maybe Value +findValueByDatumHash dh outs = snd <$> find f outs + where + f (dh', _) = dh' == dh diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index d699248d9..e49c5eeba 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -23,7 +23,7 @@ import qualified Data.ByteString as BS import qualified Data.Map as Map import Data.Text (Text, pack) import Data.Void (Void) -import Ext.Plutus.Ledger.Contexts (findDatumHashByValue) +import Ext.Plutus.Ledger.Contexts (findDatumHashByValue, findValueByDatumHash) import Ledger hiding (singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints @@ -101,7 +101,7 @@ type LendingPoolOperator = PubKeyHash data AaveDatum = LendingPoolDatum LendingPoolOperator - | ReservesDatum (AssocMap.Map ReserveId Reserve) + | ReservesDatum AssetClass (AssocMap.Map ReserveId Reserve) | UserConfigsDatum AssetClass (AssocMap.Map UserConfigId UserConfig) | DepositDatum | WithdrawDatum @@ -118,6 +118,11 @@ pickUserConfigs :: AaveDatum -> Maybe (AssetClass, AssocMap.Map UserConfigId Use pickUserConfigs (UserConfigsDatum stateToken configs) = Just (stateToken, configs) pickUserConfigs _ = Nothing +{-# INLINABLE pickReserves #-} +pickReserves :: AaveDatum -> Maybe (AssetClass, AssocMap.Map ReserveId Reserve) +pickReserves (ReservesDatum stateToken configs) = Just (stateToken, configs) +pickReserves _ = Nothing + data AaveScript instance Scripts.ScriptType AaveScript where type instance RedeemerType AaveScript = AaveRedeemer @@ -177,8 +182,31 @@ validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId checkRedeemerConfig :: UserConfig -> Bool checkRedeemerConfig UserConfig{..} = ucUsingAsCollateral +validateDeposit aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) = trace "ReservesDatum" $ isNothing investmentValue + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + reservesOutputDatumHash = + findDatumHashByValue (assetClassValue stateToken 1) $ scriptOutputsAt scriptsHash txInfo + reservesOutputDatum :: + Maybe (AssetClass, AssocMap.Map ReserveId Reserve) + reservesOutputDatum = + reservesOutputDatumHash >>= (`findDatum` txInfo) >>= (PlutusTx.fromData . getDatum) >>= pickReserves + + investmentDatumHash = findDatumHash (Datum $ PlutusTx.toData DepositDatum) txInfo + investmentValue = investmentDatumHash >>= (`findValueByDatumHash` scriptOutputsAt scriptsHash txInfo) + + isValidReservesTransformation :: Bool + isValidReservesTransformation = + maybe False checkreserves reservesOutputDatum + checkreserves :: + (AssetClass, AssocMap.Map ReserveId Reserve) -> Bool + checkreserves (newStateToken, newReserves) = + newStateToken == stateToken && + maybe False checkRedeemerConfig (AssocMap.lookup reserveId newReserves) + checkRedeemerConfig :: Reserve -> Bool + checkRedeemerConfig Reserve{..} = False validateDeposit aave (LendingPoolDatum _) ctx userConfigId = trace "LendingPoolDatum" False -validateDeposit aave (ReservesDatum _) ctx userConfigId = trace "ReservesDatum" False validateDeposit aave DepositDatum ctx userConfigId = trace "DepositDatum" False validateDeposit aave WithdrawDatum ctx userConfigId = trace "WithdrawDatum" False validateDeposit aave BorrowDatum ctx userConfigId = trace "BorrowDatum" False diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index eedb2b388..7302b0072 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -64,7 +64,7 @@ reserveStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveRese userStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveUser" findAaveReserves :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map ReserveId Reserve)) -findAaveReserves aave = findOutputBy aave (reserveStateToken aave) (^? Core._ReservesDatum) +findAaveReserves aave = findOutputBy aave (reserveStateToken aave) (^? Core._ReservesDatum . _2) findAaveReserve :: HasBlockchainActions s => Aave -> ReserveId -> Contract w s Text Reserve findAaveReserve aave reserveId = do @@ -92,9 +92,10 @@ updateState aave = Update.updateState (Core.aaveInstance aave) makeReserveHandle :: Aave -> (AssocMap.Map ReserveId Reserve -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map ReserveId Reserve) makeReserveHandle aave toRedeemer = + let stateToken = reserveStateToken aave in StateHandle { stateToken = reserveStateToken aave, - toDatum = Core.ReservesDatum, + toDatum = Core.ReservesDatum stateToken, toRedeemer = toRedeemer } From bcadd1a761cc4f51dd3c6d28687d13af8c6c947f Mon Sep 17 00:00:00 2001 From: stanislav-az Date: Mon, 7 Jun 2021 10:58:18 +0700 Subject: [PATCH 061/169] validate reserves in deposit --- .../lending-pool/src/Plutus/Contracts/Core.hs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index e49c5eeba..231d0c641 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -182,37 +182,42 @@ validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId checkRedeemerConfig :: UserConfig -> Bool checkRedeemerConfig UserConfig{..} = ucUsingAsCollateral -validateDeposit aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) = trace "ReservesDatum" $ isNothing investmentValue +validateDeposit aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) = + traceIfFalse "validateDeposit: Reserves Datum change is not valid" isValidReservesTransformation where txInfo = scriptContextTxInfo ctx (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + reservesOutputDatumHash = - findDatumHashByValue (assetClassValue stateToken 1) $ scriptOutputsAt scriptsHash txInfo + findDatumHashByValue (assetClassValue stateToken 1) scriptOutputs reservesOutputDatum :: Maybe (AssetClass, AssocMap.Map ReserveId Reserve) reservesOutputDatum = reservesOutputDatumHash >>= (`findDatum` txInfo) >>= (PlutusTx.fromData . getDatum) >>= pickReserves investmentDatumHash = findDatumHash (Datum $ PlutusTx.toData DepositDatum) txInfo - investmentValue = investmentDatumHash >>= (`findValueByDatumHash` scriptOutputsAt scriptsHash txInfo) + investmentValue = investmentDatumHash >>= (`findValueByDatumHash` scriptOutputs) isValidReservesTransformation :: Bool isValidReservesTransformation = maybe False checkreserves reservesOutputDatum - checkreserves :: - (AssetClass, AssocMap.Map ReserveId Reserve) -> Bool + checkreserves :: (AssetClass, AssocMap.Map ReserveId Reserve) -> Bool checkreserves (newStateToken, newReserves) = newStateToken == stateToken && - maybe False checkRedeemerConfig (AssocMap.lookup reserveId newReserves) - checkRedeemerConfig :: Reserve -> Bool - checkRedeemerConfig Reserve{..} = False + maybe + False + checkReserveState + ((,,) <$> investmentValue <*> AssocMap.lookup reserveId reserves <*> AssocMap.lookup reserveId newReserves) + checkReserveState :: (Value, Reserve, Reserve) -> Bool + checkReserveState (value, oldState, newState) = + assetClassValueOf value reserveId == (rAmount newState - rAmount oldState) validateDeposit aave (LendingPoolDatum _) ctx userConfigId = trace "LendingPoolDatum" False validateDeposit aave DepositDatum ctx userConfigId = trace "DepositDatum" False validateDeposit aave WithdrawDatum ctx userConfigId = trace "WithdrawDatum" False validateDeposit aave BorrowDatum ctx userConfigId = trace "BorrowDatum" False validateDeposit aave RepayDatum ctx userConfigId = trace "RepayDatum" False - aaveProtocolName :: TokenName aaveProtocolName = "Aave" From 648c16dec12386a1f1d8ded07cfdbfb379a26a1f Mon Sep 17 00:00:00 2001 From: megakaban Date: Mon, 7 Jun 2021 12:14:19 +0700 Subject: [PATCH 062/169] Initial commit --- MetaLamp/lending-pool/client/.gitignore | 15 + MetaLamp/lending-pool/client/README.md | 1 + MetaLamp/lending-pool/client/entry.js | 1 + .../lending-pool/client/package-lock.json | 7019 +++++++++++++++++ MetaLamp/lending-pool/client/package.json | 42 + MetaLamp/lending-pool/client/packages.dhall | 178 + .../client/scripts/fetch-plutus-purs.sh | 9 + .../client/scripts/generate-purs.sh | 2 + .../client/scripts/start-chrome.sh | 1 + MetaLamp/lending-pool/client/spago.dhall | 38 + MetaLamp/lending-pool/client/src/Aave.purs | 92 + .../lending-pool/client/src/AmountForm.purs | 57 + MetaLamp/lending-pool/client/src/AppAff.purs | 77 + .../lending-pool/client/src/AppComponent.purs | 232 + .../lending-pool/client/src/Capability.purs | 51 + MetaLamp/lending-pool/client/src/Main.purs | 21 + .../lending-pool/client/static/favicon.ico | Bin 0 -> 1406 bytes .../lending-pool/client/static/index.html | 9 + .../lending-pool/client/webpack.config.js | 118 + .../lending-pool/generate-purs/AaveTypes.hs | 38 + MetaLamp/lending-pool/generate-purs/Main.hs | 208 + MetaLamp/lending-pool/pab/Main.hs | 217 +- MetaLamp/lending-pool/plutus-starter.cabal | 42 +- .../lending-pool/src/Plutus/Contracts/Core.hs | 12 +- .../src/Plutus/Contracts/Endpoints.hs | 29 +- .../lending-pool/src/Plutus/PAB/Simulation.hs | 143 + 26 files changed, 8408 insertions(+), 244 deletions(-) create mode 100644 MetaLamp/lending-pool/client/.gitignore create mode 100644 MetaLamp/lending-pool/client/README.md create mode 100644 MetaLamp/lending-pool/client/entry.js create mode 100644 MetaLamp/lending-pool/client/package-lock.json create mode 100644 MetaLamp/lending-pool/client/package.json create mode 100644 MetaLamp/lending-pool/client/packages.dhall create mode 100755 MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh create mode 100755 MetaLamp/lending-pool/client/scripts/generate-purs.sh create mode 100755 MetaLamp/lending-pool/client/scripts/start-chrome.sh create mode 100644 MetaLamp/lending-pool/client/spago.dhall create mode 100644 MetaLamp/lending-pool/client/src/Aave.purs create mode 100644 MetaLamp/lending-pool/client/src/AmountForm.purs create mode 100644 MetaLamp/lending-pool/client/src/AppAff.purs create mode 100644 MetaLamp/lending-pool/client/src/AppComponent.purs create mode 100644 MetaLamp/lending-pool/client/src/Capability.purs create mode 100644 MetaLamp/lending-pool/client/src/Main.purs create mode 100644 MetaLamp/lending-pool/client/static/favicon.ico create mode 100644 MetaLamp/lending-pool/client/static/index.html create mode 100644 MetaLamp/lending-pool/client/webpack.config.js create mode 100644 MetaLamp/lending-pool/generate-purs/AaveTypes.hs create mode 100644 MetaLamp/lending-pool/generate-purs/Main.hs create mode 100644 MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs diff --git a/MetaLamp/lending-pool/client/.gitignore b/MetaLamp/lending-pool/client/.gitignore new file mode 100644 index 000000000..b9ced14b5 --- /dev/null +++ b/MetaLamp/lending-pool/client/.gitignore @@ -0,0 +1,15 @@ +generated +generated/ +generated-docs/ +node_modules/ +output/ +yarn-error.log +yarn.lock +.psci_modules/ +.psc-package/ +.psc-package2nix/ +.spago/ +.spago2nix/ +plutus-pab.yaml +.psc-ide-port +plutus-purs/ \ No newline at end of file diff --git a/MetaLamp/lending-pool/client/README.md b/MetaLamp/lending-pool/client/README.md new file mode 100644 index 000000000..c4f2eea83 --- /dev/null +++ b/MetaLamp/lending-pool/client/README.md @@ -0,0 +1 @@ +# lending pool client \ No newline at end of file diff --git a/MetaLamp/lending-pool/client/entry.js b/MetaLamp/lending-pool/client/entry.js new file mode 100644 index 000000000..ce62e7165 --- /dev/null +++ b/MetaLamp/lending-pool/client/entry.js @@ -0,0 +1 @@ +import './src/Main.purs'; diff --git a/MetaLamp/lending-pool/client/package-lock.json b/MetaLamp/lending-pool/client/package-lock.json new file mode 100644 index 000000000..77b310829 --- /dev/null +++ b/MetaLamp/lending-pool/client/package-lock.json @@ -0,0 +1,7019 @@ +{ + "name": "plutus-pab-client", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@fortawesome/fontawesome-free": { + "version": "5.15.3", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.3.tgz", + "integrity": "sha512-rFnSUN/QOtnOAgqFRooTA3H57JLDm0QEG/jPdk+tLQNL/eWd+Aok8g3qCI+Q1xuDPWpGW/i9JySpJVsq8Q0s9w==" + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==" + }, + "@types/node": { + "version": "15.12.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.1.tgz", + "integrity": "sha512-zyxJM8I1c9q5sRMtVF+zdd13Jt6RU4r4qfhTd7lQubyThvLfx6yYekWSQjGCGV2Tkecgxnlpl/DNlb6Hg+dmEw==" + }, + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "requires": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==" + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "requires": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==" + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "requires": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=" + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "optional": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "requires": { + "lodash": "^4.17.14" + } + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=" + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "bignumber": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bignumber/-/bignumber-1.1.0.tgz", + "integrity": "sha1-5qsKdD2l8+oBjlwXWX0SH3howVk=" + }, + "bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "optional": true + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "requires": { + "inherits": "~2.0.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + }, + "bootstrap": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.0.tgz", + "integrity": "sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "~1.0.5" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "optional": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "optional": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "optional": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "optional": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "optional": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "requires": { + "source-map": "~0.6.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "css-loader": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-1.0.1.tgz", + "integrity": "sha512-+ZHAZm/yqvJ2kDtPne3uX0C+Vr3Zn5jFn2N4HywtS5ujwvsVkyg0VArEXpl3BgczDA8anieki1FIzhchX4yrDw==", + "requires": { + "babel-code-frame": "^6.26.0", + "css-selector-tokenizer": "^0.7.0", + "icss-utils": "^2.1.0", + "loader-utils": "^1.0.2", + "lodash": "^4.17.11", + "postcss": "^6.0.23", + "postcss-modules-extract-imports": "^1.2.0", + "postcss-modules-local-by-default": "^1.2.0", + "postcss-modules-scope": "^1.1.0", + "postcss-modules-values": "^1.3.0", + "postcss-value-parser": "^3.3.0", + "source-list-map": "^2.0.0" + } + }, + "css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "css-selector-tokenizer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", + "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", + "requires": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, + "css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==" + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "requires": { + "array-find-index": "^1.0.1" + } + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=" + }, + "dargs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-5.1.0.tgz", + "integrity": "sha1-7H6lDHhWTNNsnV7Bj2Yyn63ieCk=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" + }, + "dns-packet": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", + "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + } + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + }, + "err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=" + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", + "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "eventsource": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", + "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", + "requires": { + "original": "^1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extract-text-webpack-plugin": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz", + "integrity": "sha512-bt/LZ4m5Rqt/Crl2HiKuAl/oqg0psx1tsTLkvWbJen1CtD+fftkZhMaQ9HOtY2gWsl2Wq+sABmMVi9z3DhKWQQ==", + "requires": { + "async": "^2.4.1", + "loader-utils": "^1.1.0", + "schema-utils": "^0.3.0", + "webpack-sources": "^1.0.1" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==" + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" + }, + "file-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-2.0.0.tgz", + "integrity": "sha512-YCsBfd1ZGCyonOKLxPiKPdu+8ld9HAaMEvJewzz+b2eTF7uL5Zm/HdBF6FjCrpCMRq25Mi0U1gl4pwn2TlH7hQ==", + "requires": { + "loader-utils": "^1.0.2", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "follow-redirects": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.1.tgz", + "integrity": "sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "requires": { + "globule": "^1.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "optional": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "requires": { + "global-prefix": "^3.0.0" + }, + "dependencies": { + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + } + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globby": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-4.1.0.tgz", + "integrity": "sha1-CA9UVJ7BuCpsYOYx/ILhIR2+lfg=", + "requires": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^6.0.1", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "globule": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz", + "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==", + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-entities": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", + "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==" + }, + "html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + } + }, + "html-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", + "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", + "requires": { + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "tapable": "^1.0.0", + "toposort": "^1.0.0", + "util.promisify": "1.0.0" + }, + "dependencies": { + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "http-parser-js": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", + "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==" + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=" + }, + "icss-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", + "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", + "requires": { + "postcss": "^6.0.1" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "in-publish": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz", + "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==" + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "requires": { + "repeating": "^2.0.0" + } + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==" + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arguments": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", + "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "optional": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" + }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==" + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-number-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==" + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==" + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "requires": { + "path-is-inside": "^1.0.2" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-string": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==" + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" + }, + "js-base64": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==" + }, + "js-string-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", + "integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==" + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" + }, + "loglevel": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", + "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==" + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + } + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==" + }, + "mime-db": { + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" + }, + "mime-types": { + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", + "requires": { + "mime-db": "1.48.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" + }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==" + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + } + } + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "node-sass": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz", + "integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==", + "requires": { + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash": "^4.17.15", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.13.2", + "node-gyp": "^3.8.0", + "npmlog": "^4.0.0", + "request": "^2.88.0", + "sass-graph": "2.2.5", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "requires": { + "path-key": "^2.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "requires": { + "boolbase": "~1.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" + }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", + "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "requires": { + "is-wsl": "^1.1.0" + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "requires": { + "url-parse": "^1.4.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "requires": { + "retry": "^0.12.0" + }, + "dependencies": { + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" + } + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "requires": { + "no-case": "^2.2.0" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "optional": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + } + } + }, + "portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz", + "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==", + "requires": { + "postcss": "^6.0.1" + } + }, + "postcss-modules-local-by-default": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", + "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", + "requires": { + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" + } + }, + "postcss-modules-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", + "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", + "requires": { + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" + } + }, + "postcss-modules-values": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", + "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", + "requires": { + "icss-replace-symbols": "^1.1.0", + "postcss": "^6.0.1" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" + }, + "pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "requires": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + }, + "promise-retry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", + "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "purs-loader": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/purs-loader/-/purs-loader-3.7.2.tgz", + "integrity": "sha512-Sidqk2RE1R2DTPt30I6G3p//c9pMaV9jd36NI3HXXSyf4Kf5X01FiP/2wMTJ8a5XKAXKdKCJ3WPqA8Whlxi0tg==", + "requires": { + "bluebird": "^3.3.5", + "chalk": "^1.1.3", + "cross-spawn": "^3.0.1", + "dargs": "^5.1.0", + "debug": "^2.6.0", + "globby": "^4.0.0", + "js-string-escape": "^1.0.1", + "loader-utils": "^1.0.2", + "lodash.difference": "^4.5.0", + "promise-retry": "^1.1.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + } + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "optional": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "renderkid": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.5.tgz", + "integrity": "sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ==", + "requires": { + "css-select": "^2.0.2", + "dom-converter": "^0.2", + "htmlparser2": "^3.10.1", + "lodash": "^4.17.20", + "strip-ansi": "^3.0.0" + } + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + } + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "requires": { + "aproba": "^1.1.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sass-graph": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", + "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", + "requires": { + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^13.3.2" + } + }, + "sass-loader": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.3.1.tgz", + "integrity": "sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA==", + "requires": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.0.1", + "neo-async": "^2.5.0", + "pify": "^4.0.1", + "semver": "^6.3.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "requires": { + "ajv": "^5.0.0" + } + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "requires": { + "js-base64": "^2.1.8", + "source-map": "^0.4.2" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" + }, + "selfsigned": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz", + "integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==", + "requires": { + "node-forge": "^0.10.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "sockjs": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", + "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^3.4.0", + "websocket-driver": "^0.7.4" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "sockjs-client": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.1.tgz", + "integrity": "sha512-VnVAb663fosipI/m6pqRXakEOw7nvd7TUgdr3PlR/8V2I95QIdwT8L4nMxhyU8SmDBHYXU1TOElaKOmKLfYzeQ==", + "requires": { + "debug": "^3.2.6", + "eventsource": "^1.0.7", + "faye-websocket": "^0.11.3", + "inherits": "^2.0.4", + "json3": "^3.3.3", + "url-parse": "^1.5.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==" + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "requires": { + "readable-stream": "^2.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "requires": { + "get-stdin": "^4.0.1" + } + }, + "style-loader": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", + "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + }, + "tar": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "requires": { + "block-stream": "*", + "fstream": "^1.0.12", + "inherits": "2" + } + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + } + } + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "requires": { + "setimmediate": "^1.0.4" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "toposort": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" + }, + "true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "requires": { + "glob": "^7.1.2" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "uglify-js": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", + "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", + "requires": { + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" + } + } + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "url-loader": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", + "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", + "requires": { + "loader-utils": "^1.1.0", + "mime": "^2.0.3", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "url-parse": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", + "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==" + }, + "uuid-validate": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/uuid-validate/-/uuid-validate-0.0.3.tgz", + "integrity": "sha512-Fykw5U4eZESbq739BeLvEBFRuJODfrlmjx5eJux7W817LjRaq4b7/i4t2zxQmhcX+fAj4nMfRdTzO4tmwLKn0w==" + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" + } + }, + "watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "optional": true, + "requires": { + "chokidar": "^2.1.8" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "optional": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true, + "requires": { + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webpack": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", + "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "webpack-cli": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz", + "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==", + "requires": { + "chalk": "^2.4.2", + "cross-spawn": "^6.0.5", + "enhanced-resolve": "^4.1.1", + "findup-sync": "^3.0.0", + "global-modules": "^2.0.0", + "import-local": "^2.0.0", + "interpret": "^1.4.0", + "loader-utils": "^1.4.0", + "supports-color": "^6.1.0", + "v8-compile-cache": "^2.1.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "webpack-dev-middleware": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", + "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + } + }, + "webpack-dev-server": { + "version": "3.11.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz", + "integrity": "sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ==", + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.8", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.21", + "sockjs-client": "^1.5.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true, + "requires": { + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xhr2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.1.4.tgz", + "integrity": "sha1-f4dliEdxbbUCYyOBL4GMras4el8=" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + } + } + } + } +} diff --git a/MetaLamp/lending-pool/client/package.json b/MetaLamp/lending-pool/client/package.json new file mode 100644 index 000000000..b1e4ec580 --- /dev/null +++ b/MetaLamp/lending-pool/client/package.json @@ -0,0 +1,42 @@ +{ + "name": "plutus-pab-client", + "version": "1.0.0", + "scripts": { + "webpack": "DEBUG=purs-loader* DEBUG_DEPTH=100 webpack --progress --bail --mode=production -p", + "webpack:watch": "PATH=$PATH:../releases/psc-package DEBUG=purs-loader* DEBUG_DEPTH=100 webpack --progress --display-error-details --display verbose --watch", + "webpack:server": "webpack-dev-server --progress --inline --hot --mode=development", + "webpack:server:debug": "DEBUG=purs-loader* DEBUG_DEPTH=100 webpack-dev-server --progress --inline --hot", + "purs:compile": "spago build", + "docs": "spago docs", + "repl": "spago repl", + "generate-purs": "sh ./scripts/generate-purs.sh", + "fetch-plutus-purs": "sh ./scripts/fetch-plutus-purs.sh", + "start-chrome": "sh ./scripts/start-chrome.sh", + "preinstall": "npm run fetch-plutus-purs && npm run generate-purs", + "start": "npm run purs:compile && npm run webpack:server" + }, + "dependencies": { + "@fortawesome/fontawesome-free": "^5.10.2", + "bignumber": "^1.1.0", + "bootstrap": "^4.3.1", + "css-loader": "^1.0.0", + "extract-text-webpack-plugin": "^3.0.2", + "file-loader": "^2.0.0", + "html-webpack-plugin": "^3.2.0", + "jquery": "^3.3.1", + "json-bigint": "^1.0.0", + "node-sass": "^4.12.0", + "purs-loader": "^3.6.0", + "sass-loader": "^7.1.0", + "style-loader": "^0.23.1", + "url-loader": "^1.1.2", + "uuid": "^7.0.2", + "uuid-validate": "^0.0.3", + "webpack": "^4.41.0", + "webpack-cli": "^3.1.2", + "webpack-dev-server": "^3.1.10", + "xhr2": "^0.1.4" + }, + "resolutions": {}, + "license": "Apache-2.0" +} diff --git a/MetaLamp/lending-pool/client/packages.dhall b/MetaLamp/lending-pool/client/packages.dhall new file mode 100644 index 000000000..6a35493a5 --- /dev/null +++ b/MetaLamp/lending-pool/client/packages.dhall @@ -0,0 +1,178 @@ +{- +Welcome to your new Dhall package-set! + +Below are instructions for how to edit this file for most use +cases, so that you don't need to know Dhall to use it. + +## Warning: Don't Move This Top-Level Comment! + +Due to how `dhall format` currently works, this comment's +instructions cannot appear near corresponding sections below +because `dhall format` will delete the comment. However, +it will not delete a top-level comment like this one. + +## Use Cases + +Most will want to do one or both of these options: +1. Override/Patch a package's dependency +2. Add a package not already in the default package set + +This file will continue to work whether you use one or both options. +Instructions for each option are explained below. + +### Overriding/Patching a package + +Purpose: +- Change a package's dependency to a newer/older release than the + default package set's release +- Use your own modified version of some dependency that may + include new API, changed API, removed API by + using your custom git repo of the library rather than + the package set's repo + +Syntax: +Replace the overrides' "{=}" (an empty record) with the following idea +The "//" or "⫽" means "merge these two records and + when they have the same value, use the one on the right:" +------------------------------- +let override = + { packageName = + upstream.packageName // { updateEntity1 = "new value", updateEntity2 = "new value" } + , packageName = + upstream.packageName // { version = "v4.0.0" } + , packageName = + upstream.packageName // { repo = "https://www.example.com/path/to/new/repo.git" } + } +------------------------------- + +Example: +------------------------------- +let overrides = + { halogen = + upstream.halogen // { version = "master" } + , halogen-vdom = + upstream.halogen-vdom // { version = "v4.0.0" } + } +------------------------------- + +### Additions + +Purpose: +- Add packages that aren't already included in the default package set + +Syntax: +Replace the additions' "{=}" (an empty record) with the following idea: +------------------------------- +let additions = + { package-name = + { dependencies = + [ "dependency1" + , "dependency2" + ] + , repo = + "https://example.com/path/to/git/repo.git" + , version = + "tag ('v4.0.0') or branch ('master')" + } + , package-name = + { dependencies = + [ "dependency1" + , "dependency2" + ] + , repo = + "https://example.com/path/to/git/repo.git" + , version = + "tag ('v4.0.0') or branch ('master')" + } + , etc. + } +------------------------------- + +Example: +------------------------------- +let additions = + { benchotron = + { dependencies = + [ "arrays" + , "exists" + , "profunctor" + , "strings" + , "quickcheck" + , "lcg" + , "transformers" + , "foldable-traversable" + , "exceptions" + , "node-fs" + , "node-buffer" + , "node-readline" + , "datetime" + , "now" + ] + , repo = + "https://github.com/hdgarrood/purescript-benchotron.git" + , version = + "v7.0.0" + } + } +------------------------------- +-} + + +let upstream = + https://github.com/purescript/package-sets/releases/download/psc-0.13.6-20200502/packages.dhall sha256:1e1ecbf222c709b76cc7e24cf63af3c2089ffd22bbb1e3379dfd3c07a1787694 + +let overrides = {=} + +let additions = + { servant-support = + { dependencies = + [ "console" + , "prelude" + , "either" + , "foldable-traversable" + , "generics-rep" + , "effect" + , "aff" + , "affjax" + , "exceptions" + , "web-xhr" + , "foreign-generic" + ] + , repo = + "https://github.com/shmish111/purescript-servant-support" + , version = + "1805f896560751c48a04d3e29f9c109df850d8d3" + } + , concurrent-queues = + { dependencies = + [ "aff" + , "avar" + ] + , repo = + "https://github.com/purescript-contrib/purescript-concurrent-queues.git" + , version = + "v1.1.0" + } + , foreign-generic = + upstream.foreign-generic + ⫽ { repo = + "https://github.com/shmish111/purescript-foreign-generic" + , version = + "57692ed7b1bc512bcfddd2c00c27e865e9c21b84" + } + , matryoshka = + { dependencies = + [ "prelude" + , "fixed-points" + , "free" + , "transformers" + , "profunctor" + ] + , repo = + "https://github.com/slamdata/purescript-matryoshka.git" + , version = + "v0.4.0" + } + } + +in upstream ⫽ overrides ⫽ additions diff --git a/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh b/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh new file mode 100755 index 000000000..69ac31ab9 --- /dev/null +++ b/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh @@ -0,0 +1,9 @@ +rm -rf plutus-purs +mkdir plutus-purs +cd plutus-purs +git init +git remote add origin -f https://github.com/input-output-hk/plutus +git config core.sparseCheckout true +echo 'web-common-plutus/*' >> .git/info/sparse-checkout +echo 'web-common/*' >> .git/info/sparse-checkout +git pull origin 58bf9ed626d498c140c69a859a508da03843d097 diff --git a/MetaLamp/lending-pool/client/scripts/generate-purs.sh b/MetaLamp/lending-pool/client/scripts/generate-purs.sh new file mode 100755 index 000000000..0947c5a43 --- /dev/null +++ b/MetaLamp/lending-pool/client/scripts/generate-purs.sh @@ -0,0 +1,2 @@ +cd .. +cabal run generate-purs \ No newline at end of file diff --git a/MetaLamp/lending-pool/client/scripts/start-chrome.sh b/MetaLamp/lending-pool/client/scripts/start-chrome.sh new file mode 100755 index 000000000..15694ecd5 --- /dev/null +++ b/MetaLamp/lending-pool/client/scripts/start-chrome.sh @@ -0,0 +1 @@ +google-chrome --disable-web-security --user-data-dir=/chrome-temp \ No newline at end of file diff --git a/MetaLamp/lending-pool/client/spago.dhall b/MetaLamp/lending-pool/client/spago.dhall new file mode 100644 index 000000000..e7b989c66 --- /dev/null +++ b/MetaLamp/lending-pool/client/spago.dhall @@ -0,0 +1,38 @@ +{- +Welcome to a Spago project! +You can edit this file as you like. +-} +{ name = "plutus-pab-client" +, dependencies = + [ "aff" + , "affjax" + , "argonaut-codecs" + , "avar" + , "bigints" + , "concurrent-queues" + , "console" + , "debug" + , "effect" + , "foreign-generic" + , "halogen" + , "matryoshka" + , "newtype" + , "node-fs" + , "prelude" + , "psci-support" + , "remotedata" + , "servant-support" + , "test-unit" + , "transformers" + , "undefinable" + , "uuid" + , "web-socket" + ] +, packages = ./packages.dhall +, sources = + [ "src/**/*.purs" + , "generated/**/*.purs" + , "plutus-purs/web-common/**/*.purs" + , "plutus-purs/web-common-plutus/**/*.purs" + ] +} diff --git a/MetaLamp/lending-pool/client/src/Aave.purs b/MetaLamp/lending-pool/client/src/Aave.purs new file mode 100644 index 000000000..5e30fdad3 --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Aave.purs @@ -0,0 +1,92 @@ +module Aave where + +import Prelude + +import Capability (class Contract, APIError(..), ContractId, ContractUnit(..), Endpoint(..), callEndpoint, delay, getContractStatus, getContracts) +import Control.Monad.Except (lift, runExcept, runExceptT, throwError) +import Data.Bifunctor (lmap) +import Data.Either (Either(..), either) +import Data.Json.JsonTuple (JsonTuple) +import Data.Lens (Prism', preview) +import Data.Maybe (Maybe(..)) +import Data.RawJson (RawJson(..)) +import Data.Time.Duration (Milliseconds(..)) +import Foreign.Generic (class Encode, decodeJSON) +import Plutus.Contracts.Core (Reserve, UserConfig) +import Plutus.Contracts.Endpoints (BorrowParams, DepositParams, RepayParams, UserContractState, WithdrawParams, _Borrowed, _Deposited, _FundsAt, _GetPubKey, _Pending, _PoolFunds, _Repaid, _Reserves, _Users, _Withdrawn) +import Plutus.PAB.Events.ContractInstanceState (PartiallyDecodedResponse(..)) +import Plutus.PAB.Simulation (AaveContracts) +import Plutus.PAB.Webserver.Types (ContractInstanceClientState(..)) +import Plutus.V1.Ledger.Crypto (PubKeyHash) +import Plutus.V1.Ledger.Value (AssetClass, Value) +import PlutusTx.AssocMap (Map) +getAaveContracts :: forall m. Contract m => m (Either APIError (Array (ContractInstanceClientState AaveContracts))) +getAaveContracts = getContracts + +getAaveContractStatus :: forall m. Contract m => ContractId -> m (Either APIError (ContractInstanceClientState AaveContracts)) +getAaveContractStatus = getContractStatus + +getAaveContractResponse :: forall m. Contract m => ContractId -> m (Either APIError UserContractState) +getAaveContractResponse = map (_ >>= getAaveResponse) <<< getAaveContractStatus + +getAaveResponse :: ContractInstanceClientState AaveContracts -> Either APIError UserContractState +getAaveResponse (ContractInstanceClientState { cicCurrentState: PartiallyDecodedResponse { observableState: RawJson s } }) = do + (res:: Either String UserContractState) <- lmap (AjaxCallError <<< show) <<< runExcept <<< decodeJSON $ s + case res of + Left e -> Left <<< AjaxCallError $ e + Right r -> Right r + +getAaveResponseWith :: forall m a p. + Contract m => + Encode p => + Endpoint -> + Prism' UserContractState a -> + ContractId -> + p -> + m (Either APIError a) +getAaveResponseWith endpoint pick cid param = runExceptT $ do + _ <- lift (callEndpoint endpoint cid param) >>= either throwError pure + lift (pollStatus endpoint pick cid) >>= either throwError pure + +pollStatus :: forall m a. + Contract m => + Endpoint -> + Prism' UserContractState a -> + ContractId -> + m (Either APIError a) +pollStatus endpoint pick cid = runExceptT $ do + _ <- lift <<< delay <<< Milliseconds $ 300.0 + res <- lift (getAaveContractResponse cid) >>= either throwError pure + case (preview _Pending res) of + Just _ -> lift (pollStatus endpoint pick cid) >>= either throwError pure + Nothing -> + case (preview pick res) of + Just v -> pure v + Nothing -> throwError $ AjaxCallError $ "Invalid state: " <> (show res) + +deposit :: forall m. Contract m => ContractId -> DepositParams -> m (Either APIError Unit) +deposit = getAaveResponseWith (Endpoint "deposit") _Deposited + +withdraw :: forall m. Contract m => ContractId -> WithdrawParams -> m (Either APIError Unit) +withdraw = getAaveResponseWith (Endpoint "withdraw") _Withdrawn + +borrow :: forall m. Contract m => ContractId -> BorrowParams -> m (Either APIError Unit) +borrow = getAaveResponseWith (Endpoint "borrow") _Borrowed + +repay :: forall m. Contract m => ContractId -> RepayParams -> m (Either APIError Unit) +repay = getAaveResponseWith (Endpoint "repay") _Repaid + +fundsAt :: forall m. Contract m => ContractId -> PubKeyHash -> m (Either APIError Value) +fundsAt = getAaveResponseWith (Endpoint "fundsAt") _FundsAt + +poolFunds :: forall m. Contract m => ContractId -> m (Either APIError Value) +poolFunds cid = getAaveResponseWith (Endpoint "poolFunds") _PoolFunds cid ContractUnit + +reserves :: forall m. Contract m => ContractId -> m (Either APIError (Map AssetClass Reserve)) +reserves cid = getAaveResponseWith (Endpoint "reserves") _Reserves cid ContractUnit + +users :: forall m. Contract m => ContractId -> m (Either APIError (Map (JsonTuple AssetClass PubKeyHash) UserConfig)) +users cid = getAaveResponseWith (Endpoint "users") _Users cid ContractUnit + +ownPubKey :: forall m. Contract m => ContractId -> m (Either APIError PubKeyHash) +ownPubKey cid = getAaveResponseWith (Endpoint "ownPubKey") _GetPubKey cid ContractUnit diff --git a/MetaLamp/lending-pool/client/src/AmountForm.purs b/MetaLamp/lending-pool/client/src/AmountForm.purs new file mode 100644 index 000000000..e284f1a38 --- /dev/null +++ b/MetaLamp/lending-pool/client/src/AmountForm.purs @@ -0,0 +1,57 @@ +module AmountForm where + +import Prelude + +import Data.BigInteger (BigInteger, fromString) +import Data.Maybe (Maybe(..), fromMaybe, maybe) +import Halogen as H +import Halogen.HTML as HH +import Halogen.HTML.Events as HE +import Halogen.HTML.Properties as HP + +type AmountInfo = { name :: String, amount :: BigInteger } + +data Output = Submit AmountInfo + +data Action = SubmitClick | EnterName String | EnterAmount String | Receive Input + +type State = { amounts :: Array AmountInfo, name :: Maybe String, amount :: Maybe BigInteger } + +type Input = Array AmountInfo + +initialState :: Input -> State +initialState amounts = { amounts, name: Nothing, amount: Nothing } + +amountForm :: forall query m. H.Component HH.HTML query Input Output m +amountForm = + H.mkComponent + { initialState: initialState + , render + , eval: H.mkEval $ H.defaultEval { handleAction = handleAction, receive = Just <<< Receive } + } + where + render state = + HH.div_ + [ HH.select + [HP.value (fromMaybe "" state.name), HE.onValueChange (Just <<< EnterName)] + (map (\({ name }) -> + HH.option [HP.value name, HP.selected (name == (fromMaybe "" state.name))] [HH.text name]) + state.amounts + ), + HH.input [HP.value $ maybe "" show state.amount, HE.onValueInput (Just <<< EnterAmount)], + HH.button [HE.onClick \_ -> Just SubmitClick] [HH.text "Submit"] + ] + + handleAction :: Action -> H.HalogenM State Action () Output m Unit + handleAction = case _ of + SubmitClick -> do + { name, amount } <- H.get + case name of + Just n -> + case amount of + Just a -> H.raise $ Submit { name: n, amount: a } + _ -> pure unit + _ -> pure unit + EnterName name -> H.modify_ _ { name = Just name } + EnterAmount amount -> H.modify_ _ { amount = fromString amount } + Receive amounts -> H.modify_ _ { amounts = amounts } diff --git a/MetaLamp/lending-pool/client/src/AppAff.purs b/MetaLamp/lending-pool/client/src/AppAff.purs new file mode 100644 index 000000000..b5edd88b6 --- /dev/null +++ b/MetaLamp/lending-pool/client/src/AppAff.purs @@ -0,0 +1,77 @@ +module AppAff where + +import Prelude + +import Affjax (Response, defaultRequest) +import Affjax.RequestBody (RequestBody, string) +import Capability (class Contract, class LogMessages, APIError(..), ContractId(..), Endpoint(..)) +import Control.Monad.Except (ExceptT, runExceptT) +import Control.Monad.Reader.Trans (class MonadAsk, ReaderT, asks, runReaderT) +import Data.Bifunctor (bimap) +import Data.Either (Either) +import Data.HTTP.Method (fromString) +import Data.Maybe (Maybe(..)) +import Effect.Aff (Aff, delay) +import Effect.Aff.Class (class MonadAff, liftAff) +import Effect.Class (class MonadEffect, liftEffect) +import Effect.Console as Console +import Foreign.Generic (class Decode, decode, encodeJSON) +import Servant.PureScript.Ajax (AjaxError(..), ErrorDescription(..), ajax) +import Type.Equality (class TypeEquals, from) + +type Env = { host :: String, port :: Int } + +newtype AppM a = AppM (ReaderT Env Aff a) + +derive newtype instance functorAppM :: Functor AppM +derive newtype instance applyAppM :: Apply AppM +derive newtype instance applicativeAppM :: Applicative AppM +derive newtype instance bindAppM :: Bind AppM +derive newtype instance monadAppM :: Monad AppM +derive newtype instance monadEffectAppM :: MonadEffect AppM +derive newtype instance monadAffAppM :: MonadAff AppM + +instance monadAskAppM :: TypeEquals e Env => MonadAsk e AppM where + ask = AppM $ asks from + +runAppM :: Env -> AppM ~> Aff +runAppM env (AppM m) = runReaderT m env + +instance logMessages :: LogMessages AppM where + logInfo = Console.log >>> liftEffect + logError = Console.error >>> liftEffect + +errorToString :: AjaxError -> String +errorToString (AjaxError e) = case e.description of + ResponseError _ _ -> "Response error" + ResponseFormatError s -> "Parsing error: " <> s + DecodingError s -> "Decoding error: " <> s + ConnectionError s -> "Connection error: " <> s + NotFound -> "Not found" + +getBaseURL :: Env -> String +getBaseURL { host, port } = "http://" <> host <> ":" <> (show port) + +runAjax :: forall m a. Monad m => ExceptT AjaxError m (Response a) -> m (Either APIError a) +runAjax = (map toCustom) <<< runExceptT + where + toCustom = bimap (AjaxCallError <<< errorToString) (\r -> r.body) + +get :: forall m a. MonadAsk Env m => MonadAff m => Decode a => String -> m (Either APIError a) +get path = do + url <- asks ((_ <> path) <<< getBaseURL) + let affReq = defaultRequest { method = fromString "GET", url = url } + runAjax $ ajax decode affReq + +post :: forall m a. MonadAsk Env m => MonadAff m => Decode a => String -> RequestBody -> m (Either APIError a) +post path body = do + url <- asks ((_ <> path) <<< getBaseURL) + let affReq = defaultRequest { method = fromString "POST", url = url, content = Just body } + runAjax $ ajax decode affReq + +instance contract :: Contract AppM where + getContracts = get "/api/new/contract/instances" + getContractStatus (ContractId cid) = get $ "/api/new/contract/instance/" <> cid <> "/status" + callEndpoint (Endpoint endpoint) (ContractId cid) params = + post ("/api/new/contract/instance/" <> cid <> "/endpoint/" <> endpoint) (string <<< encodeJSON $ params) + delay = delay >>> liftAff diff --git a/MetaLamp/lending-pool/client/src/AppComponent.purs b/MetaLamp/lending-pool/client/src/AppComponent.purs new file mode 100644 index 000000000..d5d2d3dcb --- /dev/null +++ b/MetaLamp/lending-pool/client/src/AppComponent.purs @@ -0,0 +1,232 @@ +module AppComponent where + +import Prelude + +import Aave as Aave +import AmountForm as AmountForm +import Capability (class Contract, class LogMessages, APIError(..), ContractId(..), logError, logInfo) +import Control.Monad.Except (class MonadError, lift, runExceptT, throwError) +import Data.Bifunctor (bimap, lmap) +import Data.BigInteger (BigInteger, fromInt) +import Data.Either (Either(..), either) +import Data.Foldable (find) +import Data.Json.JsonTuple (JsonTuple(..)) +import Data.Json.JsonUUID (JsonUUID(..)) +import Data.Maybe (Maybe(..)) +import Data.Symbol (SProxy(..)) +import Data.Tuple (Tuple(..)) +import Data.UUID (toString) as UUID +import Halogen as H +import Halogen.HTML as HH +import Halogen.HTML.Events as HE +import Network.RemoteData (RemoteData(..), fromEither) +import Plutus.Contracts.Core (Reserve(..)) +import Plutus.Contracts.Endpoints (BorrowParams(..), DepositParams(..), RepayParams(..), WithdrawParams(..)) +import Plutus.PAB.Webserver.Types (ContractInstanceClientState(..)) +import Plutus.V1.Ledger.Crypto (PubKeyHash) +import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..), Value(..)) +import PlutusTx.AssocMap as Map +import Wallet.Emulator.Wallet (Wallet(..)) +import Wallet.Types (ContractInstanceId(..)) + +type State = + { contractId :: RemoteData String ContractId, + walletPubKey :: RemoteData String PubKeyHash, + userFunds :: RemoteData String Value, + reserves :: RemoteData String (Map.Map AssetClass Reserve), + lastStatus :: RemoteData String String } + +initialState :: forall input. input -> State +initialState _ = + { contractId: NotAsked, + walletPubKey: NotAsked, + userFunds: NotAsked, + reserves: NotAsked, + lastStatus: NotAsked } + +data Action = + Init + | GetContractAt Wallet + | GetWalletPubKey + | GetUserFunds + | GetReserves + | GetFunds + | Deposit { amount :: BigInteger, asset :: AssetClass } + | Withdraw { amount :: BigInteger, asset :: AssetClass } + | Borrow { amount :: BigInteger, asset :: AssetClass } + | Repay { amount :: BigInteger, asset :: AssetClass } + | SubmitAmount SubmitOperation AmountForm.Output + +-- potentially should be separate actions - just a convenience for now, while they are identical +data SubmitOperation = SubmitDeposit | SubmitWithdraw | SubmitBorrow | SubmitRepay + +toContractIdParam :: ContractInstanceId -> ContractId +toContractIdParam (ContractInstanceId { unContractInstanceId: JsonUUID uuid }) = ContractId <<< UUID.toString $ uuid + +handleExcept :: forall e a m. LogMessages m => Show e => Either e a -> m Unit +handleExcept = either (show >>> logError) (const $ pure unit) + +getRD :: forall e a m. MonadError String m => Show e => Show a => String -> RemoteData e a -> m a +getRD _ (Success s) = pure s +getRD tag rd = throwError $ tag <> " is not available: " <> (show rd) + +getContractId :: forall e a m. MonadError String m => Show e => Show a => RemoteData e a -> m a +getContractId = getRD "contractId" + +getPubKey :: forall e a m. MonadError String m => Show e => Show a => RemoteData e a -> m a +getPubKey = getRD "pubKey" + +getReserves :: forall e a m. MonadError String m => Show e => Show a => RemoteData e a -> m a +getReserves = getRD "reserves" + +type Slots = ( amountForm :: forall query. H.Slot query AmountForm.Output Int ) +_amountForm = SProxy :: SProxy "amountForm" + +component :: forall input m query output. + LogMessages m => + Contract m => + H.Component HH.HTML query input output m +component = + H.mkComponent + { + initialState, + render, + eval: H.mkEval H.defaultEval { handleAction = handleAction } + } + where + handleAction :: Action -> H.HalogenM State Action Slots output m Unit + handleAction = case _ of + Init -> do + handleAction (GetContractAt $ Wallet { getWallet: fromInt 2 }) + handleAction GetWalletPubKey + handleAction GetFunds + GetContractAt wallet -> do + H.modify_ _ { contractId = Loading } + instancesRD <- Aave.getAaveContracts + case instancesRD of + Left e -> H.modify_ _ { contractId = Failure (show e) } + Right instances -> do + let contract = find (\(ContractInstanceClientState i) -> i.cicWallet == wallet) instances + case contract of + Nothing -> H.modify_ _ { contractId = Failure "Contract instance not found" } + Just (ContractInstanceClientState i) -> + H.modify_ _ { contractId = Success (toContractIdParam i.cicContract) } + GetWalletPubKey -> handleExcept <=< runExceptT $ do + lift $ H.modify_ _ { walletPubKey = Loading } + { contractId } <- lift H.get + cid <- getContractId contractId + pkh <- lift $ Aave.ownPubKey cid + lift $ H.modify_ _ { walletPubKey = fromEither <<< lmap show $ pkh } + GetUserFunds -> handleExcept <=< runExceptT $ do + lift $ H.modify_ _ { userFunds = Loading } + { contractId, walletPubKey } <- lift H.get + cid <- getContractId contractId + pkh <- getPubKey walletPubKey + funds <- lift $ Aave.fundsAt cid pkh + lift $ H.modify_ _ { userFunds = fromEither <<< lmap show $ funds } + GetReserves -> handleExcept <=< runExceptT $ do + lift $ H.modify_ _ { reserves = Loading } + { contractId } <- lift H.get + cid <- getContractId contractId + reserves <- lift $ Aave.reserves cid + lift $ H.modify_ _ { reserves = fromEither <<< lmap show $ reserves } + GetFunds -> do + handleAction GetUserFunds + handleAction GetReserves + + Deposit { amount, asset } -> handleExcept <=< runExceptT $ do + { contractId, walletPubKey } <- lift H.get + cid <- getContractId contractId + pkh <- getPubKey walletPubKey + res <- lift $ Aave.deposit cid $ DepositParams { dpAmount: amount, dpAsset: asset, dpOnBehalfOf: pkh } + lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } + Withdraw { amount, asset } -> handleExcept <=< runExceptT $ do + { contractId, walletPubKey } <- lift H.get + cid <- getContractId contractId + pkh <- getPubKey walletPubKey + res <- lift $ Aave.withdraw cid $ WithdrawParams { wpAmount: amount, wpAsset: asset, wpTo: pkh, wpFrom: pkh } + lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } + Borrow { amount, asset } -> handleExcept <=< runExceptT $ do + { contractId, walletPubKey } <- lift H.get + cid <- getContractId contractId + pkh <- getPubKey walletPubKey + res <- lift $ Aave.borrow cid $ BorrowParams { bpAmount: amount, bpAsset: asset, bpOnBehalfOf: pkh } + lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } + Repay { amount, asset } -> handleExcept <=< runExceptT $ do + { contractId, walletPubKey } <- lift H.get + cid <- getContractId contractId + pkh <- getPubKey walletPubKey + res <- lift $ Aave.repay cid $ RepayParams { rpAmount: amount, rpAsset: asset, rpOnBehalfOf: pkh } + lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } + + SubmitAmount operation (AmountForm.Submit { name, amount }) -> handleExcept <=< runExceptT $ do + { reserves: rs } <- lift H.get + reserves <- getReserves rs + case find (\(Tuple k _) -> getAssetName k == name) (Map.toTuples reserves) of + Just (Tuple asset _) -> do + case operation of + SubmitDeposit -> lift $ handleAction (Deposit { amount, asset }) + SubmitWithdraw -> lift $ handleAction (Withdraw { amount, asset }) + SubmitBorrow -> lift $ handleAction (Borrow { amount, asset }) + SubmitRepay -> lift $ handleAction (Repay { amount, asset }) + lift $ handleAction GetFunds + Nothing -> throwError "Asset name not found" + + render :: State -> H.ComponentHTML Action Slots m + render state = + HH.div_ + [ HH.button [ HE.onClick \_ -> Just Init ] [ HH.text "Start" ] + , remoteDataState (\v -> HH.div_ [HH.h2_ [HH.text "User funds"], fundsTable v]) state.userFunds + , remoteDataState + (\v -> HH.div_ $ [HH.h2_ [HH.text "Pool funds"]] <> map (\(Tuple a r) -> reserveTab a r) v) + (map Map.toTuples state.reserves) + , remoteDataState + (\v -> HH.h2_ [HH.text "Deposit", HH.slot _amountForm 0 AmountForm.amountForm v (Just <<< (SubmitAmount SubmitDeposit))]) + (map reservesToAmounts state.reserves) + , remoteDataState + (\v -> HH.h2_ [HH.text "Withdraw", HH.slot _amountForm 1 AmountForm.amountForm v (Just <<< (SubmitAmount SubmitWithdraw))]) + (map reservesToAmounts state.reserves) + , remoteDataState + (\v -> HH.h2_ [HH.text "Borrow", HH.slot _amountForm 1 AmountForm.amountForm v (Just <<< (SubmitAmount SubmitBorrow))]) + (map reservesToAmounts state.reserves) + , remoteDataState + (\v -> HH.h2_ [HH.text "Repay", HH.slot _amountForm 1 AmountForm.amountForm v (Just <<< (SubmitAmount SubmitRepay))]) + (map reservesToAmounts state.reserves) + ] + +remoteDataState :: forall props act e a. Show e => (a -> HH.HTML props act) -> RemoteData e a -> HH.HTML props act +remoteDataState _ NotAsked = HH.div_ [HH.text ""] +remoteDataState _ Loading = HH.div_ [HH.text "Loading..."] +remoteDataState _ (Failure e) = HH.div_ [HH.text $ "Error: " <> show e] +remoteDataState f (Success s) = f s + +getAssetName :: AssetClass -> String +getAssetName (AssetClass { unAssetClass: JsonTuple (Tuple _ (TokenName { unTokenName: name })) }) = name + +reservesToAmounts :: Map.Map AssetClass Reserve -> Array AmountForm.AmountInfo +reservesToAmounts = map toInfo <<< Map.toTuples + where + toInfo (Tuple k (Reserve { rAmount })) = { name: getAssetName k, amount: rAmount } + +reserveTab :: forall props act. AssetClass -> Reserve -> HH.HTML props act +reserveTab (AssetClass { unAssetClass: JsonTuple (Tuple _ name)}) (Reserve { rAmount }) = + poolTab name rAmount + +poolTab :: forall props act. TokenName -> BigInteger -> HH.HTML props act +poolTab (TokenName { unTokenName: name }) amount = + HH.div_ $ [HH.h4_ [HH.text (name <> " pool balance")], HH.text $ show amount] + +fundsTable :: forall props act. Value -> HH.HTML props act +fundsTable (Value ({ getValue: m })) = HH.div_ $ do + (Tuple _ amounts) <- Map.toTuples m + (Tuple name amount) <- Map.toTuples amounts + if amount > (fromInt 0) + then pure $ amountTab name amount + else [] + +amountTab :: forall props act. TokenName -> BigInteger -> HH.HTML props act +amountTab (TokenName { unTokenName: name }) amount = + HH.div_ $ [HH.text (showName name <> " " <> show amount)] + where + showName "" = "ADA" + showName n = n diff --git a/MetaLamp/lending-pool/client/src/Capability.purs b/MetaLamp/lending-pool/client/src/Capability.purs new file mode 100644 index 000000000..5738f90ff --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Capability.purs @@ -0,0 +1,51 @@ +module Capability where + +import Prelude + +import Data.Either (Either) +import Data.Generic.Rep (class Generic) +import Data.Generic.Rep.Show (genericShow) +import Data.Time.Duration (Milliseconds) +import Foreign (unsafeToForeign) +import Foreign.Generic (class Decode, class Encode) +import Halogen (HalogenM, lift) +import Plutus.PAB.Webserver.Types (ContractInstanceClientState) + +class Monad m <= LogMessages m where + logInfo :: String -> m Unit + logError :: String -> m Unit + +instance logMessagesHalogenM :: LogMessages m => LogMessages (HalogenM st act slots msg m) where + logInfo = logInfo >>> lift + logError = logError >>> lift + +data APIError = AjaxCallError String + +derive instance genericAPIError :: Generic APIError _ +instance showAPIError :: Show APIError where + show = genericShow + +newtype ContractId = ContractId String + +derive newtype instance showContractId :: Show ContractId + +newtype Endpoint = Endpoint String + +derive newtype instance showEndpoint :: Show Endpoint + +data ContractUnit = ContractUnit + +instance encodeContractUnit :: Encode ContractUnit where + encode value = unsafeToForeign [] + +class Monad m <= Contract m where + getContracts :: forall a. Decode a => m (Either APIError (Array (ContractInstanceClientState a))) + callEndpoint :: forall a. Encode a => Endpoint -> ContractId -> a -> m (Either APIError Unit) + getContractStatus :: forall a. Decode a => ContractId -> m (Either APIError (ContractInstanceClientState a)) + delay :: Milliseconds -> m Unit + +instance contractHalogenM :: Contract m => Contract (HalogenM st act slots msg m) where + getContracts = lift getContracts + callEndpoint endpoint cid params = lift $ callEndpoint endpoint cid params + getContractStatus = getContractStatus >>> lift + delay = delay >>> lift diff --git a/MetaLamp/lending-pool/client/src/Main.purs b/MetaLamp/lending-pool/client/src/Main.purs new file mode 100644 index 000000000..db1f7604c --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Main.purs @@ -0,0 +1,21 @@ +module Main where + +import Prelude + +import AppComponent as B +import AppAff (runAppM) +import Effect (Effect) +import Effect.Unsafe (unsafePerformEffect) +import Halogen as H +import Halogen.Aff (awaitBody, runHalogenAff) +import Halogen.VDom.Driver (runUI) + +main :: Effect Unit +main = + runHalogenAff do + let rootComponent = H.hoist (runAppM { host: "localhost", port: 8080 }) B.component + body <- awaitBody + runUI rootComponent unit body + +onLoad :: Unit +onLoad = unsafePerformEffect main diff --git a/MetaLamp/lending-pool/client/static/favicon.ico b/MetaLamp/lending-pool/client/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..c65686613290bb4b637c78a6495133833369ec1e GIT binary patch literal 1406 zcmeH{Jyg?B7>3`f)GAe@RjmKCV4)yjEU59{sG#u&EU5Hit5_5?%962b$BY@XX6%?T z>m4&@?3%G-$NIK9cpP;lIXB+i{3YbG=a~h&fha5t+ zJXVRa8^9tPZiu+kg+{Mi4h%1X-;U`e=OqN!Wpg=GLE4;0ZjTR?xLt^Fx?i}hvrBaoU=Gr)C`!GMfN$z@8p`M>!M6{!Zz%% z164O5$S&Cm+N=>8tePFbqiX~aUChir&=*w=sxX<^uU-!=dfn#pJdZAfP2Z!}L=%?d z!IpdvyU)k-3tpHJ5c^D|o$8HlAy;Y2o{FVqVY zrQIA-S3W;EbmvC?SS_6_mF95j+3V@|H*X&u9!{sv+*-lqH{->3JKy##o3+AybpdOm z@)5fIl5W98}L=?B~UlT%aVt4r56zc1b`t8AIU!+A9z`+tWL}+ z=eAO0@oBS~8Ji!Qd3*An=<|8S$Y@i_?uCtwwLS}RX=`Ck2=&9o-~8oZ--?mbgY`me N4v=?}`E&fQ@e|8(0FeLy literal 0 HcmV?d00001 diff --git a/MetaLamp/lending-pool/client/static/index.html b/MetaLamp/lending-pool/client/static/index.html new file mode 100644 index 000000000..7e5db2166 --- /dev/null +++ b/MetaLamp/lending-pool/client/static/index.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/MetaLamp/lending-pool/client/webpack.config.js b/MetaLamp/lending-pool/client/webpack.config.js new file mode 100644 index 000000000..0d77c0e52 --- /dev/null +++ b/MetaLamp/lending-pool/client/webpack.config.js @@ -0,0 +1,118 @@ +'use strict'; + +const ExtractTextPlugin = require("extract-text-webpack-plugin"); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const path = require('path'); +const webpack = require('webpack'); + +const isWebpackDevServer = process.argv.some(a => path.basename(a) === 'webpack-dev-server'); + +const isWatch = process.argv.some(a => a === '--watch'); + +const plugins = + isWebpackDevServer || !isWatch ? [] : [ + function(){ + this.plugin('done', function(stats){ + process.stderr.write(stats.toString('errors-only')); + }); + } + ] +; + +// source map adds many Mb to the output! +const devtool = isWebpackDevServer ? 'eval-source-map' : false; + +module.exports = { + devtool, + + devServer: { + contentBase: path.join(__dirname, "dist"), + compress: true, + port: 8009, + https: true, + proxy: { + "/api": { + target: 'http://localhost:8080' + }, + "/ws": { + target: 'ws://localhost:8080', + ws: true, + onError(err) { + console.log('Error with the WebSocket:', err); + } + } + } + }, + + entry: './entry.js', + + output: { + path: path.join(__dirname, 'dist'), + pathinfo: true, + filename: 'app.[hash].js' + }, + + module: { + rules: [ + { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&mimetype=application/font-woff" }, + { test: /fontawesome-.*\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader" }, + { + test: /\.purs$/, + use: [ + { + loader: 'purs-loader', + options: { + src: [ + 'src/**/*.purs', + 'generated/**/*.purs', + '.spago/*/*/src/**/*.purs', + 'plutus-purs/web-common-plutus/**/*.purs', + 'plutus-purs/web-common/**/*.purs' + ], + psc: null, + bundle: !(isWebpackDevServer || isWatch), + warnings: true, + watch: isWebpackDevServer || isWatch, + pscPackage: false, + pscIde: false + } + } + ] + }, + { + test: /\.css$/, + use: ['style-loader', 'css-loader'] + }, + { + test: /\.scss$/, + use: ['style-loader', 'css-loader', 'sass-loader'] + }, + { + test: /\.(gif|png|jpe?g|svg)$/i, + use: 'url-loader' + } + ] + }, + + resolve: { + modules: [ + // We need the second entry for node to be able to + // locate `node_modules` from client directory when + // modules are referenced from inside `web-common`. + 'node_modules', path.resolve(__dirname, './node_modules') + ], + extensions: [ '.purs', '.js'] + }, + + plugins: [ + new webpack.LoaderOptionsPlugin({ + debug: true + }), + new HtmlWebpackPlugin({ + template: 'static/index.html', + favicon: 'static/favicon.ico', + title: 'SCB', + productName: 'plutus-pab' + }) + ].concat(plugins) +}; diff --git a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs new file mode 100644 index 000000000..8df82ae5d --- /dev/null +++ b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs @@ -0,0 +1,38 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + +module AaveTypes where + +import Language.PureScript.Bridge (BridgePart, Language (Haskell), SumType, + TypeInfo (TypeInfo), buildBridge, equal, genericShow, + haskType, mkSumType, order, typeModule, typeName, + writePSTypesWith, (^==)) +import Data.Proxy (Proxy (Proxy)) +import qualified Plutus.Contracts.Core as Aave +import qualified Plutus.Contracts.Endpoints as Aave +import Plutus.PAB.Simulation (AaveContracts(..)) +import PlutusTx.Ratio (Ratio) +import Language.PureScript.Bridge.TypeParameters (A) + +aaveTypes :: [SumType 'Haskell] +aaveTypes = [ (equal <*> (genericShow <*> mkSumType)) (Proxy @AaveContracts) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.Aave) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.CreateParams) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.UserContractState) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.ReserveId) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.Reserve) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.UserConfigId) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.UserConfig) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(Ratio A)) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.DepositParams) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.WithdrawParams) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.BorrowParams) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.RepayParams) ] diff --git a/MetaLamp/lending-pool/generate-purs/Main.hs b/MetaLamp/lending-pool/generate-purs/Main.hs new file mode 100644 index 000000000..2627c835c --- /dev/null +++ b/MetaLamp/lending-pool/generate-purs/Main.hs @@ -0,0 +1,208 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE EmptyDataDecls #-} + +module Main where + +import Cardano.Metadata.Types (AnnotatedSignature, HashFunction, Property, PropertyKey, + Subject, SubjectProperties) +import Cardano.Wallet.Types (WalletInfo) +import Control.Applicative ((<|>)) +import Control.Lens (set, view, (&)) +import Control.Monad (void) +import Control.Monad.Freer.Extras.Log (LogLevel, LogMessage) +import qualified Data.Aeson.Encode.Pretty as JSON +import qualified Data.ByteString.Lazy as BSL +import Data.Proxy (Proxy (Proxy)) +import qualified Data.Text as Text +import Language.PureScript.Bridge (BridgePart, Language (Haskell), SumType, + TypeInfo (TypeInfo), buildBridge, equal, genericShow, + haskType, mkSumType, order, typeModule, typeName, + writePSTypesWith, (^==)) +import Language.PureScript.Bridge.CodeGenSwitches (ForeignOptions (ForeignOptions), genForeign, + unwrapSingleConstructors) +import Language.PureScript.Bridge.TypeParameters (A) +import Ledger.Constraints.OffChain (UnbalancedTx) +import qualified PSGenerator.Common +import Plutus.Contract.Checkpoint (CheckpointKey, CheckpointStore) +import Plutus.Contract.Effects.AwaitSlot (WaitingForSlot) +import Plutus.Contract.Effects.AwaitTxConfirmed (TxConfirmed) +import Plutus.Contract.Effects.ExposeEndpoint (ActiveEndpoint, EndpointValue) +import Plutus.Contract.Effects.Instance (OwnIdRequest) +import Plutus.Contract.Effects.OwnPubKey (OwnPubKeyRequest) +import Plutus.Contract.Effects.UtxoAt (UtxoAtAddress) +import Plutus.Contract.Effects.WriteTx (WriteTxResponse) +import Plutus.Contract.Resumable (Responses) +import Plutus.Contract.State (ContractRequest, State) +import Plutus.Contracts.Currency (SimpleMPS (..)) +import Plutus.PAB.Effects.Contract.ContractExe (ContractExe) +import Plutus.PAB.Effects.Contract.ContractTest (TestContracts (Currency, GameStateMachine)) +import Plutus.PAB.Events (PABEvent) +import Plutus.PAB.Events.Contract (ContractInstanceId (..), ContractPABRequest, + ContractResponse) +import Plutus.PAB.Events.ContractInstanceState (PartiallyDecodedResponse) +import qualified Plutus.PAB.Simulator as Simulator +import qualified Plutus.PAB.Webserver.API as API +import qualified Plutus.PAB.Webserver.Handler as Webserver +import Plutus.PAB.Webserver.Types (ChainReport, CombinedWSStreamToClient, + CombinedWSStreamToServer, ContractActivationArgs, + ContractInstanceClientState, ContractReport, + ContractSignatureResponse, FullReport, + InstanceStatusToClient) +import Servant ((:<|>)) +import Servant.PureScript (HasBridge, Settings, _generateSubscriberAPI, apiModuleName, + defaultBridge, defaultSettings, languageBridge, + writeAPIModuleWithSettings) +import System.FilePath (()) +import Wallet.Effects (AddressChangeRequest (..), AddressChangeResponse (..)) +import Wallet.Emulator.Wallet (Wallet (..)) +import AaveTypes (aaveTypes) +import System.Directory (removeDirectoryRecursive, doesDirectoryExist) +import Plutus.V1.Ledger.Value (AssetClass, TokenName (..)) +import Control.Monad (when) + +myBridge :: BridgePart +myBridge = + PSGenerator.Common.aesonBridge <|> + PSGenerator.Common.containersBridge <|> + PSGenerator.Common.languageBridge <|> + PSGenerator.Common.ledgerBridge <|> + PSGenerator.Common.servantBridge <|> + PSGenerator.Common.miscBridge <|> + metadataBridge <|> + defaultBridge + +-- Some of the metadata types have a datakind type parameter that +-- PureScript won't support, so we must drop it. +metadataBridge :: BridgePart +metadataBridge = do + (typeName ^== "Property") + <|> (typeName ^== "SubjectProperties") + <|> (typeName ^== "AnnotatedSignature") + typeModule ^== "Cardano.Metadata.Types" + moduleName <- view (haskType . typeModule) + name <- view (haskType . typeName) + pure $ TypeInfo "plutus-pab" moduleName name [] + +data MyBridge + +myBridgeProxy :: Proxy MyBridge +myBridgeProxy = Proxy + +instance HasBridge MyBridge where + languageBridge _ = buildBridge myBridge + +myTypes :: [SumType 'Haskell] +myTypes = + PSGenerator.Common.ledgerTypes <> + PSGenerator.Common.playgroundTypes <> + PSGenerator.Common.walletTypes <> + aaveTypes <> + [ (equal <*> (genericShow <*> mkSumType)) (Proxy @ContractExe) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @TestContracts) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(FullReport A)) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @ChainReport) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractReport A)) + , (equal <*> (genericShow <*> mkSumType)) + (Proxy @(ContractSignatureResponse A)) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(PartiallyDecodedResponse A)) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractRequest A)) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @ContractPABRequest) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @ContractResponse) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @UnbalancedTx) + + -- Contract request / response types + , (equal <*> (genericShow <*> mkSumType)) (Proxy @ActiveEndpoint) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(EndpointValue A)) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @OwnPubKeyRequest) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @TxConfirmed) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @UtxoAtAddress) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @WriteTxResponse) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @WaitingForSlot) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(State A)) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @CheckpointStore) + , (order <*> (genericShow <*> mkSumType)) (Proxy @CheckpointKey) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(Responses A)) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @AddressChangeRequest) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @AddressChangeResponse) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @OwnIdRequest) + + -- Logging types + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(LogMessage A)) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @LogLevel) + + -- Metadata types + , (order <*> (genericShow <*> mkSumType)) (Proxy @Subject) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(SubjectProperties A)) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(Property A)) + , (order <*> (genericShow <*> mkSumType)) (Proxy @PropertyKey) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @HashFunction) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(AnnotatedSignature A)) + + -- * Web API types + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(PABEvent A)) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractActivationArgs A)) + , (genericShow <*> mkSumType) (Proxy @(ContractInstanceClientState A)) + , (genericShow <*> mkSumType) (Proxy @InstanceStatusToClient) + , (genericShow <*> mkSumType) (Proxy @CombinedWSStreamToClient) + , (genericShow <*> mkSumType) (Proxy @CombinedWSStreamToServer) + , (genericShow <*> mkSumType) (Proxy @WalletInfo) + ] + +mySettings :: Settings +mySettings = + (defaultSettings & set apiModuleName "Plutus.PAB.Webserver") + {_generateSubscriberAPI = False} + +defaultWallet :: Wallet +defaultWallet = Wallet 1 + +------------------------------------------------------------ +writeTestData :: FilePath -> IO () +writeTestData outputDir = do + (fullReport, currencySchema) <- + fmap (either (error . show) id) $ Simulator.runSimulation $ do + currencyInstance1 <- Simulator.activateContract defaultWallet Currency + void $ Simulator.activateContract defaultWallet Currency + void $ Simulator.activateContract defaultWallet GameStateMachine + void $ Simulator.waitForEndpoint currencyInstance1 "Create native token" + void $ Simulator.callEndpointOnInstance currencyInstance1 "Create native token" SimpleMPS {tokenName = "TestCurrency", amount = 10000000000} + void $ Simulator.waitUntilFinished currencyInstance1 + report :: FullReport TestContracts <- Webserver.getFullReport + schema :: ContractSignatureResponse TestContracts <- Webserver.contractSchema (Text.pack $ show $ unContractInstanceId currencyInstance1) + pure (report, schema) + BSL.writeFile + (outputDir "full_report_response.json") + (JSON.encodePretty fullReport) + BSL.writeFile + (outputDir "contract_schema_response.json") + (JSON.encodePretty currencySchema) + +------------------------------------------------------------ + +generateTo :: FilePath -> IO () +generateTo outputDir = do + exists <- doesDirectoryExist outputDir + when exists $ removeDirectoryRecursive outputDir + writeAPIModuleWithSettings + mySettings + outputDir + myBridgeProxy + (Proxy @(API.API ContractExe :<|> API.NewAPI ContractExe Text.Text :<|> (API.WalletProxy Text.Text))) + writePSTypesWith + (genForeign (ForeignOptions {unwrapSingleConstructors = True})) + outputDir + (buildBridge myBridge) + myTypes + writeTestData outputDir + +main :: IO () +main = generateTo "client/generated" diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index dfc3f01e5..b65076421 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -1,217 +1,4 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RankNTypes #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} - -module Main - ( main - ) where - -import Control.Monad (forM, forM_, void, when) -import Control.Monad.Freer (Eff, Member, interpret, - type (~>)) -import Control.Monad.Freer.Error (Error) -import Control.Monad.Freer.Extras.Log (LogMsg) -import Control.Monad.IO.Class (MonadIO (..)) -import Data.Aeson (FromJSON, Result (..), - ToJSON, encode, fromJSON) -import qualified Data.ByteString as BS -import qualified Data.Map.Strict as Map -import qualified Data.Monoid as Monoid -import qualified Data.Semigroup as Semigroup -import Data.Text (Text) -import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) -import GHC.Generics (Generic) -import Ledger -import Ledger.Ada (adaSymbol, adaToken, - adaValueOf, - lovelaceValueOf) -import Ledger.Constraints -import qualified Ledger.Constraints.OffChain as Constraints -import qualified Ledger.Typed.Scripts as Scripts -import Ledger.Value as Value -import Plutus.Contract hiding (when) -import qualified Plutus.Contracts.Core as Aave -import Plutus.Contracts.Currency as Currency -import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Contracts.FungibleToken as FungibleToken -import Plutus.PAB.Effects.Contract (ContractEffect (..)) -import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), - type (.\\)) -import qualified Plutus.PAB.Effects.Contract.Builtin as Builtin -import Plutus.PAB.Monitoring.PABLogMsg (PABMultiAgentMsg) -import Plutus.PAB.Simulator (SimulatorEffectHandlers) -import qualified Plutus.PAB.Simulator as Simulator -import Plutus.PAB.Types (PABError (..)) -import qualified Plutus.PAB.Webserver.Server as PAB.Server -import Plutus.V1.Ledger.Crypto (getPubKeyHash, pubKeyHash) -import Prelude hiding (init) -import Wallet.Emulator.Types (Wallet (..), walletPubKey) - -wallets :: [Wallet] -wallets = [Wallet i | i <- [1 .. 4]] - -testCurrencyNames :: [TokenName] -testCurrencyNames = ["MOGUS", "USD"] - -toAsset :: TokenName -> AssetClass -toAsset tokenName = - assetClass (scriptCurrencySymbol . FungibleToken.makeLiquidityPolicy $ tokenName) tokenName - -testAssets :: [AssetClass] -testAssets = fmap toAsset testCurrencyNames - -initContract :: Contract (Maybe (Semigroup.Last Currency.OneShotCurrency)) Currency.CurrencySchema Currency.CurrencyError () -initContract = do - ownPK <- pubKeyHash <$> ownPubKey - let testCurrenciesValue = mconcat $ fmap (`assetClassValue` 1000) testAssets - policyLookups = mconcat $ - fmap (Constraints.monetaryPolicy . FungibleToken.makeLiquidityPolicy . Prelude.snd . unAssetClass) testAssets - adaValue = lovelaceValueOf amount - forM_ wallets $ \w -> do - let pkh = pubKeyHash $ walletPubKey w - lookups = policyLookups - tx = mustForgeValue testCurrenciesValue <> mustPayToPubKey pkh (adaValue <> testCurrenciesValue) - when (pkh /= ownPK) $ do - ledgerTx <- submitTxConstraintsWith @Scripts.Any lookups tx - void $ awaitTxConfirmed $ txId ledgerTx - where - amount = 1000000 +import Plutus.PAB.Simulation (runLendingPoolSimulation) main :: IO () -main = void $ Simulator.runSimulationWith handlers $ do - Simulator.logString @(Builtin AaveContracts) "Starting Aave PAB webserver on port 8080. Press enter to exit." - shutdown <- PAB.Server.startServerDebug - - cidInit <- Simulator.activateContract (Wallet 1) Init - _ <- Simulator.waitUntilFinished cidInit - - Simulator.logString @(Builtin AaveContracts) "Initialization finished." - - let params = fmap Aave.CreateParams testAssets - cidStart <- Simulator.activateContract (Wallet 1) (AaveStart params) - aa <- flip Simulator.waitForState cidStart $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.Aave))) of - Success (Monoid.Last (Just (Right aa))) -> Just aa - _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Aave instance created: " ++ show aa - - cids <- fmap Map.fromList $ forM wallets $ \w -> do - cid <- Simulator.activateContract w $ AaveUser aa - Simulator.logString @(Builtin AaveContracts) $ "Aave user contract started for " ++ show w - return (w, cid) - - let userCid = cids Map.! Wallet 2 - sender = pubKeyHash . walletPubKey $ Wallet 2 - - _ <- - Simulator.callEndpointOnInstance userCid "deposit" $ - Aave.DepositParams { Aave.dpAsset = head testAssets, Aave.dpOnBehalfOf = sender, Aave.dpAmount = 100 } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right Aave.Deposited))) -> Just () - _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Successful deposit" - - _ <- - Simulator.callEndpointOnInstance userCid "withdraw" $ - Aave.WithdrawParams { Aave.wpAsset = head testAssets, Aave.wpTo = sender, Aave.wpFrom = sender, Aave.wpAmount = 30 } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right Aave.Withdrawn))) -> Just () - _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Successful withdraw" - - let lenderCid = cids Map.! Wallet 3 - let lender = pubKeyHash . walletPubKey $ Wallet 3 - _ <- - Simulator.callEndpointOnInstance lenderCid "deposit" $ - Aave.DepositParams { Aave.dpAsset = testAssets !! 1, Aave.dpOnBehalfOf = lender, Aave.dpAmount = 200 } - flip Simulator.waitForState lenderCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right Aave.Deposited))) -> Just () - _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Successful deposit from lender" - - _ <- - Simulator.callEndpointOnInstance userCid "borrow" $ - Aave.BorrowParams { Aave.bpAsset = testAssets !! 1, Aave.bpAmount = 35, Aave.bpOnBehalfOf = sender } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right Aave.Borrowed))) -> Just () - _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Successful borrow" - - _ <- - Simulator.callEndpointOnInstance userCid "repay" $ - Aave.RepayParams { Aave.rpAsset = testAssets !! 1, Aave.rpAmount = 25, Aave.rpOnBehalfOf = sender } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right Aave.Repaid))) -> Just () - _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Successful repay" - - _ <- Simulator.callEndpointOnInstance userCid "fundsAt" sender - v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right (Aave.FundsAt v)))) -> Just v - _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Final user funds: " <> show v - - _ <- Simulator.callEndpointOnInstance lenderCid "fundsAt" lender - v <- flip Simulator.waitForState lenderCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right (Aave.FundsAt v)))) -> Just v - _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Final lender funds: " <> show v - - _ <- Simulator.callEndpointOnInstance userCid "reserves" () - reserves <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right (Aave.Reserves reserves)))) -> Just reserves - _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Final reserves: " <> show reserves - - _ <- Simulator.callEndpointOnInstance userCid "poolFunds" () - v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right (Aave.PoolFunds v)))) -> Just v - _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Final pool funds: " <> show v - - _ <- Simulator.callEndpointOnInstance userCid "users" () - v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right (Aave.Users v)))) -> Just v - _ -> Nothing - Simulator.logString @(Builtin AaveContracts) $ "Final users: " <> show v - - _ <- liftIO getLine - shutdown - -data AaveContracts = - Init - | AaveStart [Aave.CreateParams] - | AaveUser Aave.Aave - deriving (Show, Generic) - deriving anyclass (FromJSON, ToJSON) - -instance Pretty AaveContracts where - pretty = viaShow - -handleAaveContract :: - ( Member (Error PABError) effs - , Member (LogMsg (PABMultiAgentMsg (Builtin AaveContracts))) effs - ) - => ContractEffect (Builtin AaveContracts) - ~> Eff effs -handleAaveContract = Builtin.handleBuiltin getSchema getContract where - getSchema = \case - AaveUser _ -> Builtin.endpointsToSchemas @(Aave.AaveUserSchema .\\ BlockchainActions) - AaveStart _ -> Builtin.endpointsToSchemas @(Aave.AaveOwnerSchema .\\ BlockchainActions) - Init -> Builtin.endpointsToSchemas @Empty - getContract = \case - AaveUser us -> SomeBuiltin $ Aave.userEndpoints us - AaveStart params -> SomeBuiltin $ Aave.ownerEndpoint params - Init -> SomeBuiltin initContract - -handlers :: SimulatorEffectHandlers (Builtin AaveContracts) -handlers = - Simulator.mkSimulatorHandlers @(Builtin AaveContracts) [] -- [Init, AaveStart, AaveUser ???] - $ interpret handleAaveContract +main = runLendingPoolSimulation diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 4d707892c..066f3b52b 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -23,13 +23,16 @@ maintainer: Your email library exposed-modules: - Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.State Plutus.State.Select Plutus.State.Update Plutus.Contracts.TxUtils Plutus.OutputValue + Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.State Plutus.State.Select Plutus.State.Update Plutus.Contracts.TxUtils Plutus.OutputValue Plutus.PAB.Simulation build-depends: base >= 4.9 && < 5, aeson, bytestring, containers, text, + freer-simple, + freer-extras, + prettyprinter, -- Plutus: playground-common, plutus-contract, @@ -37,7 +40,8 @@ library plutus-tx, plutus-ledger, plutus-ledger-api, - plutus-use-cases + plutus-use-cases, + plutus-pab hs-source-dirs: src default-language: Haskell2010 ghc-options: @@ -47,23 +51,37 @@ library executable plutus-starter-pab main-is: Main.hs hs-source-dirs: pab + ghc-options: + -threaded + build-depends: + base >= 4.9 && < 5, + plutus-starter + +executable generate-purs + main-is: Main.hs + hs-source-dirs: generate-purs + other-modules: AaveTypes ghc-options: -threaded build-depends: base >= 4.9 && < 5, aeson, - freer-simple, + directory, + servant-purescript, + filepath, + servant-server, + bytestring, + aeson-pretty, freer-extras, - prettyprinter, - containers, - row-types, + lens, text, -- Plutus: - plutus-ledger, - plutus-contract, - plutus-pab, - plutus-starter, + plutus-ledger-api, + purescript-bridge, playground-common, + plutus-starter, + plutus-pab, + plutus-contract, plutus-use-cases, - plutus-ledger-api, - bytestring + plutus-ledger, + plutus-tx diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 5d01c92c4..a0d9b98a7 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -40,17 +40,11 @@ deriving anyclass instance ToSchema AssetClass newtype Aave = Aave { aaveProtocolInst :: AssetClass - } deriving stock (Show, Generic) + } deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) PlutusTx.makeLift ''Aave -instance Prelude.Eq Aave where - u == v = aaveProtocolInst u Prelude.== aaveProtocolInst v - -instance Prelude.Ord Aave where - compare u v = Prelude.compare (aaveProtocolInst u) (aaveProtocolInst v) - type ReserveId = AssetClass deriving anyclass instance ToSchema Rational @@ -63,7 +57,7 @@ data Reserve = Reserve rLiquidityIndex :: Integer, rCurrentStableBorrowRate :: Rational } - deriving stock (Show, Generic) + deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) PlutusTx.unstableMakeIsData ''Reserve @@ -76,7 +70,7 @@ data UserConfig = UserConfig ucUsingAsCollateral :: Bool, ucDebt :: Maybe Integer } - deriving stock (Show, Generic) + deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) PlutusTx.unstableMakeIsData ''UserConfig diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 74afab4ed..503ca5e86 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -55,11 +55,12 @@ import PlutusTx.Prelude hiding (Semigroup (..), import Prelude (Semigroup (..)) import qualified Prelude import Text.Printf (printf) +import qualified Data.Text as Text newtype CreateParams = CreateParams { cpAsset :: AssetClass } - deriving (Show, Generic) + deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (FromJSON, ToJSON, ToSchema) PlutusTx.makeLift ''CreateParams @@ -116,6 +117,9 @@ valueAt address = do os <- map snd . Map.toList <$> utxoAt address pure $ mconcat [txOutValue $ txOutTxOut o | o <- os] +getOwnPubKey :: HasBlockchainActions s => Contract w s Text PubKeyHash +getOwnPubKey = pubKeyHash <$> ownPubKey + fundsAt :: HasBlockchainActions s => PubKeyHash -> Contract w s Text Value fundsAt pkh = valueAt (pubKeyHashAddress pkh) @@ -131,7 +135,7 @@ data DepositParams = dpOnBehalfOf :: PubKeyHash, dpAmount :: Integer } - deriving stock (Show, Generic) + deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) PlutusTx.unstableMakeIsData ''DepositParams @@ -168,7 +172,7 @@ data WithdrawParams = wpFrom :: PubKeyHash, wpAmount :: Integer } - deriving stock (Show, Generic) + deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) PlutusTx.unstableMakeIsData ''WithdrawParams @@ -194,7 +198,7 @@ data BorrowParams = bpAmount :: Integer, bpOnBehalfOf :: PubKeyHash } - deriving stock (Show, Generic) + deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) PlutusTx.unstableMakeIsData ''BorrowParams @@ -234,7 +238,7 @@ data RepayParams = rpAmount :: Integer, rpOnBehalfOf :: PubKeyHash } - deriving stock (Show, Generic) + deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) PlutusTx.unstableMakeIsData ''RepayParams @@ -269,8 +273,14 @@ type AaveUserSchema = .\/ Endpoint "poolFunds" () .\/ Endpoint "reserves" () .\/ Endpoint "users" () + .\/ Endpoint "ownPubKey" () + +instance (Prelude.Eq k, Prelude.Eq v) => Prelude.Eq (AssocMap.Map k v) where + a == b = (AssocMap.toList a) Prelude.== (AssocMap.toList b) -data UserContractState = Created +data UserContractState = + Pending + | Created | Closed | Stopped | Deposited @@ -281,7 +291,8 @@ data UserContractState = Created | PoolFunds Value | Reserves (AssocMap.Map ReserveId Reserve) | Users (AssocMap.Map UserConfigId UserConfig) - deriving (Show, Generic, FromJSON, ToJSON) + | GetPubKey PubKeyHash + deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) userEndpoints :: Aave -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () userEndpoints aa = forever $ @@ -293,9 +304,10 @@ userEndpoints aa = forever $ `select` f (Proxy @"poolFunds") PoolFunds (\aave () -> poolFunds aave) `select` f (Proxy @"reserves") Reserves (\aave () -> reserves aave) `select` f (Proxy @"users") Users (\aave () -> users aave) + `select` f (Proxy @"ownPubKey") GetPubKey (\_ () -> getOwnPubKey) where f :: forall l a p. - HasEndpoint l p AaveUserSchema + HasEndpoint l p AaveUserSchema => Proxy l -> (a -> UserContractState) -> (Aave -> p -> Contract (Last (Either Text UserContractState)) AaveUserSchema Text a) @@ -303,6 +315,7 @@ userEndpoints aa = forever $ f _ g c = do e <- runError $ do p <- endpoint @l + _ <- tell $ Last $ Just $ Right $ Pending errorHandler `handleError` c aa p tell $ Last $ Just $ case e of Left err -> Left err diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs new file mode 100644 index 000000000..269f50c59 --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -0,0 +1,143 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + +module Plutus.PAB.Simulation + ( runLendingPoolSimulation, + AaveContracts(..) + ) where + +import Control.Monad (forM, forM_, void, when) +import Control.Monad.Freer (Eff, Member, interpret, + type (~>)) +import Control.Monad.Freer.Error (Error) +import Control.Monad.Freer.Extras.Log (LogMsg) +import Control.Monad.IO.Class (MonadIO (..)) +import Data.Aeson (FromJSON, Result (..), + ToJSON, encode, fromJSON) +import qualified Data.ByteString as BS +import qualified Data.Map.Strict as Map +import qualified Data.Monoid as Monoid +import qualified Data.Semigroup as Semigroup +import Data.Text (Text) +import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) +import GHC.Generics (Generic) +import Ledger +import Ledger.Ada (adaSymbol, adaToken, + adaValueOf, + lovelaceValueOf) +import Ledger.Constraints +import qualified Ledger.Constraints.OffChain as Constraints +import qualified Ledger.Typed.Scripts as Scripts +import Ledger.Value as Value +import Plutus.Contract hiding (when) +import qualified Plutus.Contracts.Core as Aave +import Plutus.Contracts.Currency as Currency +import qualified Plutus.Contracts.Endpoints as Aave +import qualified Plutus.Contracts.FungibleToken as FungibleToken +import Plutus.PAB.Effects.Contract (ContractEffect (..)) +import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), + type (.\\)) +import qualified Plutus.PAB.Effects.Contract.Builtin as Builtin +import Plutus.PAB.Monitoring.PABLogMsg (PABMultiAgentMsg) +import Plutus.PAB.Simulator (SimulatorEffectHandlers) +import qualified Plutus.PAB.Simulator as Simulator +import Plutus.PAB.Types (PABError (..)) +import qualified Plutus.PAB.Webserver.Server as PAB.Server +import Plutus.V1.Ledger.Crypto (getPubKeyHash, pubKeyHash) +import Prelude hiding (init) +import Wallet.Emulator.Types (Wallet (..), walletPubKey) + +wallets :: [Wallet] +wallets = [Wallet i | i <- [1 .. 4]] + +testCurrencyNames :: [TokenName] +testCurrencyNames = ["MOGUS", "USD"] + +toAsset :: TokenName -> AssetClass +toAsset tokenName = + assetClass (scriptCurrencySymbol . FungibleToken.makeLiquidityPolicy $ tokenName) tokenName + +testAssets :: [AssetClass] +testAssets = fmap toAsset testCurrencyNames + +initContract :: Contract (Maybe (Semigroup.Last Currency.OneShotCurrency)) Currency.CurrencySchema Currency.CurrencyError () +initContract = do + ownPK <- pubKeyHash <$> ownPubKey + let testCurrenciesValue = mconcat $ fmap (`assetClassValue` 1000) testAssets + policyLookups = mconcat $ + fmap (Constraints.monetaryPolicy . FungibleToken.makeLiquidityPolicy . Prelude.snd . unAssetClass) testAssets + adaValue = lovelaceValueOf amount + forM_ wallets $ \w -> do + let pkh = pubKeyHash $ walletPubKey w + lookups = policyLookups + tx = mustForgeValue testCurrenciesValue <> mustPayToPubKey pkh (adaValue <> testCurrenciesValue) + when (pkh /= ownPK) $ do + ledgerTx <- submitTxConstraintsWith @Scripts.Any lookups tx + void $ awaitTxConfirmed $ txId ledgerTx + where + amount = 1000000 + +runLendingPoolSimulation :: IO () +runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do + Simulator.logString @(Builtin AaveContracts) "Starting Aave PAB webserver on port 8080. Press enter to exit." + shutdown <- PAB.Server.startServerDebug + + cidInit <- Simulator.activateContract (Wallet 1) Init + _ <- Simulator.waitUntilFinished cidInit + + Simulator.logString @(Builtin AaveContracts) "Initialization finished." + + let params = fmap Aave.CreateParams testAssets + cidStart <- Simulator.activateContract (Wallet 1) (AaveStart params) + aa <- flip Simulator.waitForState cidStart $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.Aave))) of + Success (Monoid.Last (Just (Right aa))) -> Just aa + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Aave instance created: " ++ show aa + + cids <- fmap Map.fromList $ forM wallets $ \w -> do + cid <- Simulator.activateContract w $ AaveUser aa + Simulator.logString @(Builtin AaveContracts) $ "Aave user contract started for " ++ show w + return (w, cid) + + _ <- liftIO getLine + shutdown + +data AaveContracts = + Init + | AaveStart [Aave.CreateParams] + | AaveUser Aave.Aave + deriving (Eq, Show, Generic) + deriving anyclass (FromJSON, ToJSON) + +instance Pretty AaveContracts where + pretty = viaShow + +handleAaveContract :: + ( Member (Error PABError) effs + , Member (LogMsg (PABMultiAgentMsg (Builtin AaveContracts))) effs + ) + => ContractEffect (Builtin AaveContracts) + ~> Eff effs +handleAaveContract = Builtin.handleBuiltin getSchema getContract where + getSchema = \case + AaveUser _ -> Builtin.endpointsToSchemas @(Aave.AaveUserSchema .\\ BlockchainActions) + AaveStart _ -> Builtin.endpointsToSchemas @(Aave.AaveOwnerSchema .\\ BlockchainActions) + Init -> Builtin.endpointsToSchemas @Empty + getContract = \case + AaveUser us -> SomeBuiltin $ Aave.userEndpoints us + AaveStart params -> SomeBuiltin $ Aave.ownerEndpoint params + Init -> SomeBuiltin initContract + +handlers :: SimulatorEffectHandlers (Builtin AaveContracts) +handlers = + Simulator.mkSimulatorHandlers @(Builtin AaveContracts) [] + $ interpret handleAaveContract From 556650f840582175bd9f1d6bb1cb955f676dabac Mon Sep 17 00:00:00 2001 From: megakaban Date: Mon, 7 Jun 2021 13:27:32 +0700 Subject: [PATCH 063/169] Split simulation into two executables --- MetaLamp/lending-pool/pab-simulation/Main.hs | 4 + MetaLamp/lending-pool/pab/Main.hs | 4 +- MetaLamp/lending-pool/plutus-starter.cabal | 11 +- .../src/Plutus/Contracts/Endpoints.hs | 2 +- .../lending-pool/src/Plutus/PAB/Simulation.hs | 106 ++++++++++++++++-- 5 files changed, 111 insertions(+), 16 deletions(-) create mode 100644 MetaLamp/lending-pool/pab-simulation/Main.hs diff --git a/MetaLamp/lending-pool/pab-simulation/Main.hs b/MetaLamp/lending-pool/pab-simulation/Main.hs new file mode 100644 index 000000000..b65076421 --- /dev/null +++ b/MetaLamp/lending-pool/pab-simulation/Main.hs @@ -0,0 +1,4 @@ +import Plutus.PAB.Simulation (runLendingPoolSimulation) + +main :: IO () +main = runLendingPoolSimulation diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index b65076421..75da03bb4 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -1,4 +1,4 @@ -import Plutus.PAB.Simulation (runLendingPoolSimulation) +import Plutus.PAB.Simulation (runLendingPool) main :: IO () -main = runLendingPoolSimulation +main = runLendingPool diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 066f3b52b..3a236579a 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -48,7 +48,7 @@ library -- See Plutus Tx readme -fobject-code -fno-ignore-interface-pragmas -fno-omit-interface-pragmas -executable plutus-starter-pab +executable pab main-is: Main.hs hs-source-dirs: pab ghc-options: @@ -57,6 +57,15 @@ executable plutus-starter-pab base >= 4.9 && < 5, plutus-starter +executable pab-simulation + main-is: Main.hs + hs-source-dirs: pab-simulation + ghc-options: + -threaded + build-depends: + base >= 4.9 && < 5, + plutus-starter + executable generate-purs main-is: Main.hs hs-source-dirs: generate-purs diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 503ca5e86..e56330274 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -24,6 +24,7 @@ import qualified Data.Map as Map import Data.Monoid (Last (..)) import Data.Proxy (Proxy (..)) import Data.Text (Text, pack) +import qualified Data.Text as Text import Data.Void (Void) import Ledger hiding (singleton) import Ledger.Constraints as Constraints @@ -55,7 +56,6 @@ import PlutusTx.Prelude hiding (Semigroup (..), import Prelude (Semigroup (..)) import qualified Prelude import Text.Printf (printf) -import qualified Data.Text as Text newtype CreateParams = CreateParams diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 269f50c59..a6fd536f7 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -10,10 +10,7 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -module Plutus.PAB.Simulation - ( runLendingPoolSimulation, - AaveContracts(..) - ) where +module Plutus.PAB.Simulation where import Control.Monad (forM, forM_, void, when) import Control.Monad.Freer (Eff, Member, interpret, @@ -48,13 +45,15 @@ import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), type (.\\)) import qualified Plutus.PAB.Effects.Contract.Builtin as Builtin import Plutus.PAB.Monitoring.PABLogMsg (PABMultiAgentMsg) -import Plutus.PAB.Simulator (SimulatorEffectHandlers) +import Plutus.PAB.Simulator (Simulation, + SimulatorEffectHandlers) import qualified Plutus.PAB.Simulator as Simulator import Plutus.PAB.Types (PABError (..)) import qualified Plutus.PAB.Webserver.Server as PAB.Server import Plutus.V1.Ledger.Crypto (getPubKeyHash, pubKeyHash) import Prelude hiding (init) import Wallet.Emulator.Types (Wallet (..), walletPubKey) +import Wallet.Types (ContractInstanceId) wallets :: [Wallet] wallets = [Wallet i | i <- [1 .. 4]] @@ -86,14 +85,10 @@ initContract = do where amount = 1000000 -runLendingPoolSimulation :: IO () -runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do - Simulator.logString @(Builtin AaveContracts) "Starting Aave PAB webserver on port 8080. Press enter to exit." - shutdown <- PAB.Server.startServerDebug - +activateContracts :: Simulation (Builtin AaveContracts) (Map.Map Wallet ContractInstanceId) +activateContracts = do cidInit <- Simulator.activateContract (Wallet 1) Init _ <- Simulator.waitUntilFinished cidInit - Simulator.logString @(Builtin AaveContracts) "Initialization finished." let params = fmap Aave.CreateParams testAssets @@ -103,11 +98,98 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Aave instance created: " ++ show aa - cids <- fmap Map.fromList $ forM wallets $ \w -> do + fmap Map.fromList $ forM wallets $ \w -> do cid <- Simulator.activateContract w $ AaveUser aa Simulator.logString @(Builtin AaveContracts) $ "Aave user contract started for " ++ show w return (w, cid) +runLendingPool :: IO () +runLendingPool = void $ Simulator.runSimulationWith handlers $ do + Simulator.logString @(Builtin AaveContracts) "Starting Aave PAB webserver on port 8080. Press enter to exit." + shutdown <- PAB.Server.startServerDebug + _ <- activateContracts + _ <- liftIO getLine + shutdown + +runLendingPoolSimulation :: IO () +runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do + Simulator.logString @(Builtin AaveContracts) "Starting Aave PAB webserver on port 8080. Press enter to exit." + shutdown <- PAB.Server.startServerDebug + cids <- activateContracts + let userCid = cids Map.! Wallet 2 + sender = pubKeyHash . walletPubKey $ Wallet 2 + + _ <- + Simulator.callEndpointOnInstance userCid "deposit" $ + Aave.DepositParams { Aave.dpAsset = head testAssets, Aave.dpOnBehalfOf = sender, Aave.dpAmount = 100 } + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right Aave.Deposited))) -> Just () + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Successful deposit" + + _ <- + Simulator.callEndpointOnInstance userCid "withdraw" $ + Aave.WithdrawParams { Aave.wpAsset = head testAssets, Aave.wpTo = sender, Aave.wpFrom = sender, Aave.wpAmount = 30 } + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right Aave.Withdrawn))) -> Just () + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Successful withdraw" + + let lenderCid = cids Map.! Wallet 3 + let lender = pubKeyHash . walletPubKey $ Wallet 3 + _ <- + Simulator.callEndpointOnInstance lenderCid "deposit" $ + Aave.DepositParams { Aave.dpAsset = testAssets !! 1, Aave.dpOnBehalfOf = lender, Aave.dpAmount = 200 } + flip Simulator.waitForState lenderCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right Aave.Deposited))) -> Just () + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Successful deposit from lender" + + _ <- + Simulator.callEndpointOnInstance userCid "borrow" $ + Aave.BorrowParams { Aave.bpAsset = testAssets !! 1, Aave.bpAmount = 35, Aave.bpOnBehalfOf = sender } + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right Aave.Borrowed))) -> Just () + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Successful borrow" + + _ <- + Simulator.callEndpointOnInstance userCid "repay" $ + Aave.RepayParams { Aave.rpAsset = testAssets !! 1, Aave.rpAmount = 25, Aave.rpOnBehalfOf = sender } + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right Aave.Repaid))) -> Just () + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Successful repay" + + _ <- Simulator.callEndpointOnInstance userCid "fundsAt" sender + v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right (Aave.FundsAt v)))) -> Just v + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Final user funds: " <> show v + + _ <- Simulator.callEndpointOnInstance lenderCid "fundsAt" lender + v <- flip Simulator.waitForState lenderCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right (Aave.FundsAt v)))) -> Just v + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Final lender funds: " <> show v + + _ <- Simulator.callEndpointOnInstance userCid "reserves" () + reserves <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right (Aave.Reserves reserves)))) -> Just reserves + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Final reserves: " <> show reserves + + _ <- Simulator.callEndpointOnInstance userCid "poolFunds" () + v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right (Aave.PoolFunds v)))) -> Just v + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Final pool funds: " <> show v + + _ <- Simulator.callEndpointOnInstance userCid "users" () + v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + Success (Monoid.Last (Just (Right (Aave.Users v)))) -> Just v + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Final users: " <> show v _ <- liftIO getLine shutdown From 35594c1f35ebdd40966b2522a27a30ffe48ff45f Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 7 Jun 2021 15:11:24 +0700 Subject: [PATCH 064/169] refactor error msgs --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 231d0c641..61ae0148d 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -100,7 +100,7 @@ PlutusTx.makeLift ''AaveRedeemer type LendingPoolOperator = PubKeyHash data AaveDatum = - LendingPoolDatum LendingPoolOperator + LendingPoolDatum LendingPoolOperator | ReservesDatum AssetClass (AssocMap.Map ReserveId Reserve) | UserConfigsDatum AssetClass (AssocMap.Map UserConfigId UserConfig) | DepositDatum @@ -132,7 +132,6 @@ instance Scripts.ScriptType AaveScript where -- Main validator -- Each state field must have one or more associated actions(Redeemer types), -- produced on state update, which are then validated here --- TODO: write validations makeAaveValidator :: Aave -> AaveDatum -> AaveRedeemer @@ -212,11 +211,8 @@ validateDeposit aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) checkReserveState :: (Value, Reserve, Reserve) -> Bool checkReserveState (value, oldState, newState) = assetClassValueOf value reserveId == (rAmount newState - rAmount oldState) -validateDeposit aave (LendingPoolDatum _) ctx userConfigId = trace "LendingPoolDatum" False -validateDeposit aave DepositDatum ctx userConfigId = trace "DepositDatum" False -validateDeposit aave WithdrawDatum ctx userConfigId = trace "WithdrawDatum" False -validateDeposit aave BorrowDatum ctx userConfigId = trace "BorrowDatum" False -validateDeposit aave RepayDatum ctx userConfigId = trace "RepayDatum" False + +validateDeposit _ _ _ _ = trace "validateDeposit: Lending Pool Datum management is not allowed" False aaveProtocolName :: TokenName aaveProtocolName = "Aave" From 1d6a81c851fc13a8e038ba185151145044ad75ae Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 7 Jun 2021 15:55:19 +0700 Subject: [PATCH 065/169] separate parse datum function --- .../src/Ext/Plutus/Ledger/Contexts.hs | 11 ++++++++-- .../lending-pool/src/Plutus/Contracts/Core.hs | 22 ++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs index 44c1149cd..22bf239e2 100644 --- a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs +++ b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs @@ -3,8 +3,11 @@ module Ext.Plutus.Ledger.Contexts where -import Ledger (DatumHash, Value) -import PlutusTx.Prelude (Eq ((==)), Maybe, find, fst, snd, (<$>)) +import Ledger (Datum (getDatum), DatumHash, TxInfo, Value, + findDatum) +import qualified PlutusTx +import PlutusTx.Prelude (Eq ((==)), Maybe, Monad ((>>=)), find, fst, + snd, (.), (<$>)) {-# INLINABLE findDatumHashByValue #-} -- | Find the hash of a datum, if it is part of the pending transaction's @@ -21,3 +24,7 @@ findValueByDatumHash :: DatumHash -> [(DatumHash, Value)] -> Maybe Value findValueByDatumHash dh outs = snd <$> find f outs where f (dh', _) = dh' == dh + +{-# INLINABLE parseDatum #-} +parseDatum :: PlutusTx.IsData a => TxInfo -> DatumHash -> Maybe a +parseDatum txInfo dh = findDatum dh txInfo >>= (PlutusTx.fromData . getDatum) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 61ae0148d..92ba7389f 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -23,7 +23,9 @@ import qualified Data.ByteString as BS import qualified Data.Map as Map import Data.Text (Text, pack) import Data.Void (Void) -import Ext.Plutus.Ledger.Contexts (findDatumHashByValue, findValueByDatumHash) +import Ext.Plutus.Ledger.Contexts (findDatumHashByValue, + findValueByDatumHash, + parseDatum) import Ledger hiding (singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints @@ -121,7 +123,7 @@ pickUserConfigs _ = Nothing {-# INLINABLE pickReserves #-} pickReserves :: AaveDatum -> Maybe (AssetClass, AssocMap.Map ReserveId Reserve) pickReserves (ReservesDatum stateToken configs) = Just (stateToken, configs) -pickReserves _ = Nothing +pickReserves _ = Nothing data AaveScript instance Scripts.ScriptType AaveScript where @@ -139,10 +141,9 @@ makeAaveValidator :: Aave -> Bool makeAaveValidator aave datum StartRedeemer ctx = trace "StartRedeemer" $ validateStart aave datum ctx makeAaveValidator aave datum (DepositRedeemer userConfigId) ctx = trace "DepositRedeemer" $ validateDeposit aave datum ctx userConfigId -makeAaveValidator _ _ WithdrawRedeemer _ = True +makeAaveValidator aave datum WithdrawRedeemer ctx = trace "WithdrawRedeemer" $ validateWithdraw aave datum ctx makeAaveValidator _ _ BorrowRedeemer _ = True makeAaveValidator _ _ RepayRedeemer _ = True --- makeAaveValidator _ _ _ _ = False validateStart :: Aave -> AaveDatum -> ScriptContext -> Bool validateStart aave (LendingPoolDatum operator) ctx = @@ -168,7 +169,7 @@ validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId userConfigsOutputDatum :: Maybe (AssetClass, AssocMap.Map UserConfigId UserConfig) userConfigsOutputDatum = - userConfigsOutputDatumHash >>= (`findDatum` txInfo) >>= (PlutusTx.fromData . getDatum) >>= pickUserConfigs + userConfigsOutputDatumHash >>= parseDatum txInfo >>= pickUserConfigs isValidUserConfigsTransformation :: Bool isValidUserConfigsTransformation = @@ -193,7 +194,7 @@ validateDeposit aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) reservesOutputDatum :: Maybe (AssetClass, AssocMap.Map ReserveId Reserve) reservesOutputDatum = - reservesOutputDatumHash >>= (`findDatum` txInfo) >>= (PlutusTx.fromData . getDatum) >>= pickReserves + reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves investmentDatumHash = findDatumHash (Datum $ PlutusTx.toData DepositDatum) txInfo investmentValue = investmentDatumHash >>= (`findValueByDatumHash` scriptOutputs) @@ -214,6 +215,15 @@ validateDeposit aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) validateDeposit _ _ _ _ = trace "validateDeposit: Lending Pool Datum management is not allowed" False +validateWithdraw :: Aave -> AaveDatum -> ScriptContext -> Bool +validateWithdraw aave (LendingPoolDatum _) _ = trace "validateWithdraw: LendingPoolDatum" False +validateWithdraw aave (ReservesDatum _ _) _ = trace "validateWithdraw: ReservesDatum" False +validateWithdraw aave (UserConfigsDatum _ _) _ = trace "validateWithdraw: UserConfigsDatum" False +validateWithdraw aave DepositDatum _ = trace "validateWithdraw: DepositDatum" False +validateWithdraw aave WithdrawDatum _ = trace "validateWithdraw: WithdrawDatum" False +validateWithdraw aave BorrowDatum _ = trace "validateWithdraw: BorrowDatum" False +validateWithdraw aave RepayDatum _ = trace "validateWithdraw: RepayDatum" False + aaveProtocolName :: TokenName aaveProtocolName = "Aave" From bddaeaad3e9a2d11de74dc5667e30611c2829996 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 7 Jun 2021 16:25:28 +0700 Subject: [PATCH 066/169] simplify datum type --- .../src/Plutus/Contracts/AToken.hs | 4 ++-- .../lending-pool/src/Plutus/Contracts/Core.hs | 20 +++++++++---------- .../src/Plutus/Contracts/Endpoints.hs | 4 ++-- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 4e9fb2c48..107a7548b 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -97,7 +97,7 @@ forgeATokensFrom aave reserve pkh amount = do pure $ TxUtils.mustForgeValue @AaveScript policy forgeValue <> (Prelude.mempty, mustPayToPubKey pkh forgeValue) - <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.DepositDatum payment + <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.ReserveFundsDatum payment burnATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text (TxUtils.TxPair AaveScript) burnATokensFrom aave reserve pkh amount = do @@ -114,4 +114,4 @@ burnATokensFrom aave reserve pkh amount = do pure $ TxUtils.mustForgeValue policy burnValue <> TxUtils.mustSpendFromScript (Core.aaveInstance aave) spendInputs pkh (assetClassValue asset aTokenAmount) - <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.WithdrawDatum (assetClassValue asset remainder) + <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.ReserveFundsDatum (assetClassValue asset remainder) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 92ba7389f..0b548b7c3 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -105,10 +105,7 @@ data AaveDatum = LendingPoolDatum LendingPoolOperator | ReservesDatum AssetClass (AssocMap.Map ReserveId Reserve) | UserConfigsDatum AssetClass (AssocMap.Map UserConfigId UserConfig) - | DepositDatum - | WithdrawDatum - | BorrowDatum - | RepayDatum + | ReserveFundsDatum deriving stock (Show) PlutusTx.unstableMakeIsData ''AaveDatum @@ -179,6 +176,7 @@ validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId checkUserConfigs (newStateToken, newUserConfigs) = newStateToken == stateToken && maybe False checkRedeemerConfig (AssocMap.lookup userConfigId newUserConfigs) + -- TODO check that other fields are not changed checkRedeemerConfig :: UserConfig -> Bool checkRedeemerConfig UserConfig{..} = ucUsingAsCollateral @@ -196,7 +194,7 @@ validateDeposit aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) reservesOutputDatum = reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves - investmentDatumHash = findDatumHash (Datum $ PlutusTx.toData DepositDatum) txInfo + investmentDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo investmentValue = investmentDatumHash >>= (`findValueByDatumHash` scriptOutputs) isValidReservesTransformation :: Bool @@ -209,6 +207,7 @@ validateDeposit aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) False checkReserveState ((,,) <$> investmentValue <*> AssocMap.lookup reserveId reserves <*> AssocMap.lookup reserveId newReserves) + -- TODO check that other fields are not changed checkReserveState :: (Value, Reserve, Reserve) -> Bool checkReserveState (value, oldState, newState) = assetClassValueOf value reserveId == (rAmount newState - rAmount oldState) @@ -216,13 +215,12 @@ validateDeposit aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) validateDeposit _ _ _ _ = trace "validateDeposit: Lending Pool Datum management is not allowed" False validateWithdraw :: Aave -> AaveDatum -> ScriptContext -> Bool +validateWithdraw aave (UserConfigsDatum stateToken userConfigs) ctx = + traceIfFalse "validateWithdraw: User Configs Datum change is not valid" False +validateWithdraw aave (ReservesDatum stateToken reserves) ctx = + traceIfFalse "validateWithdraw: Reserves Datum change is not valid" True +validateWithdraw aave ReserveFundsDatum _ = trace "validateWithdraw: ReserveFundsDatum" False validateWithdraw aave (LendingPoolDatum _) _ = trace "validateWithdraw: LendingPoolDatum" False -validateWithdraw aave (ReservesDatum _ _) _ = trace "validateWithdraw: ReservesDatum" False -validateWithdraw aave (UserConfigsDatum _ _) _ = trace "validateWithdraw: UserConfigsDatum" False -validateWithdraw aave DepositDatum _ = trace "validateWithdraw: DepositDatum" False -validateWithdraw aave WithdrawDatum _ = trace "validateWithdraw: WithdrawDatum" False -validateWithdraw aave BorrowDatum _ = trace "validateWithdraw: BorrowDatum" False -validateWithdraw aave RepayDatum _ = trace "validateWithdraw: RepayDatum" False aaveProtocolName :: TokenName aaveProtocolName = "Aave" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 4f21b2e44..e378507c7 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -224,7 +224,7 @@ borrow aave BorrowParams {..} = do let payment = assetClassValue (rCurrency reserve) bpAmount let remainder = assetClassValue (rCurrency reserve) (rAmount reserve - bpAmount) let disbursementTx = TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs bpOnBehalfOf payment <> - TxUtils.mustPayToScript (Core.aaveInstance aave) bpOnBehalfOf Core.BorrowDatum remainder + TxUtils.mustPayToScript (Core.aaveInstance aave) bpOnBehalfOf Core.ReserveFundsDatum remainder userConfigs <- ovValue <$> State.findAaveUserConfigs aave let userConfigId = (rCurrency reserve, bpOnBehalfOf) @@ -260,7 +260,7 @@ repay aave RepayParams {..} = do reserve <- State.findAaveReserve aave rpAsset let payment = assetClassValue (rCurrency reserve) rpAmount - let reimbursementTx = TxUtils.mustPayToScript (Core.aaveInstance aave) rpOnBehalfOf Core.RepayDatum payment + let reimbursementTx = TxUtils.mustPayToScript (Core.aaveInstance aave) rpOnBehalfOf Core.ReserveFundsDatum payment userConfigs <- ovValue <$> State.findAaveUserConfigs aave let userConfigId = (rCurrency reserve, rpOnBehalfOf) From 28d2ff816906a7146941ba16fb572a2362e8ab55 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 7 Jun 2021 16:41:38 +0700 Subject: [PATCH 067/169] add user config id to withdraw --- MetaLamp/lending-pool/pab/Main.hs | 2 +- .../lending-pool/src/Plutus/Contracts/AToken.hs | 3 ++- .../lending-pool/src/Plutus/Contracts/Core.hs | 14 +++++++------- .../src/Plutus/Contracts/Endpoints.hs | 15 +++++++-------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/MetaLamp/lending-pool/pab/Main.hs b/MetaLamp/lending-pool/pab/Main.hs index dfc3f01e5..d037b0d5b 100644 --- a/MetaLamp/lending-pool/pab/Main.hs +++ b/MetaLamp/lending-pool/pab/Main.hs @@ -120,7 +120,7 @@ main = void $ Simulator.runSimulationWith handlers $ do _ <- Simulator.callEndpointOnInstance userCid "withdraw" $ - Aave.WithdrawParams { Aave.wpAsset = head testAssets, Aave.wpTo = sender, Aave.wpFrom = sender, Aave.wpAmount = 30 } + Aave.WithdrawParams { Aave.wpAsset = head testAssets, Aave.wpUser = sender, Aave.wpAmount = 30 } flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of Success (Monoid.Last (Just (Right Aave.Withdrawn))) -> Just () _ -> Nothing diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 107a7548b..1bf1181da 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -102,6 +102,7 @@ forgeATokensFrom aave reserve pkh amount = do burnATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text (TxUtils.TxPair AaveScript) burnATokensFrom aave reserve pkh amount = do let asset = rCurrency reserve + let userConfigId = (asset, pkh) utxos <- Map.filter ((> 0) . flip assetClassValueOf asset . txOutValue . txOutTxOut) <$> utxoAt (Core.aaveAddress aave) @@ -110,7 +111,7 @@ burnATokensFrom aave reserve pkh amount = do remainder = assetClassValueOf balance asset - aTokenAmount policy = makeLiquidityPolicy asset burnValue = negate $ assetClassValue (rAToken reserve) aTokenAmount - spendInputs = (\(ref, tx) -> OutputValue ref tx Core.WithdrawRedeemer) <$> Map.toList utxos + spendInputs = (\(ref, tx) -> OutputValue ref tx (Core.WithdrawRedeemer userConfigId)) <$> Map.toList utxos pure $ TxUtils.mustForgeValue policy burnValue <> TxUtils.mustSpendFromScript (Core.aaveInstance aave) spendInputs pkh (assetClassValue asset aTokenAmount) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 0b548b7c3..0601ddaa0 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -91,7 +91,7 @@ PlutusTx.makeLift ''UserConfig data AaveRedeemer = StartRedeemer | DepositRedeemer UserConfigId - | WithdrawRedeemer + | WithdrawRedeemer UserConfigId | BorrowRedeemer | RepayRedeemer deriving Show @@ -138,7 +138,7 @@ makeAaveValidator :: Aave -> Bool makeAaveValidator aave datum StartRedeemer ctx = trace "StartRedeemer" $ validateStart aave datum ctx makeAaveValidator aave datum (DepositRedeemer userConfigId) ctx = trace "DepositRedeemer" $ validateDeposit aave datum ctx userConfigId -makeAaveValidator aave datum WithdrawRedeemer ctx = trace "WithdrawRedeemer" $ validateWithdraw aave datum ctx +makeAaveValidator aave datum (WithdrawRedeemer userConfigId) ctx = trace "WithdrawRedeemer" $ validateWithdraw aave datum ctx userConfigId makeAaveValidator _ _ BorrowRedeemer _ = True makeAaveValidator _ _ RepayRedeemer _ = True @@ -214,13 +214,13 @@ validateDeposit aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) validateDeposit _ _ _ _ = trace "validateDeposit: Lending Pool Datum management is not allowed" False -validateWithdraw :: Aave -> AaveDatum -> ScriptContext -> Bool -validateWithdraw aave (UserConfigsDatum stateToken userConfigs) ctx = +validateWithdraw :: Aave -> AaveDatum -> ScriptContext -> UserConfigId -> Bool +validateWithdraw aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId = traceIfFalse "validateWithdraw: User Configs Datum change is not valid" False -validateWithdraw aave (ReservesDatum stateToken reserves) ctx = +validateWithdraw aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateWithdraw: Reserves Datum change is not valid" True -validateWithdraw aave ReserveFundsDatum _ = trace "validateWithdraw: ReserveFundsDatum" False -validateWithdraw aave (LendingPoolDatum _) _ = trace "validateWithdraw: LendingPoolDatum" False +validateWithdraw aave ReserveFundsDatum _ userConfigId = trace "validateWithdraw: ReserveFundsDatum" True +validateWithdraw _ _ _ _ = trace "validateWithdraw: Lending Pool Datum management is not allowed" False aaveProtocolName :: TokenName aaveProtocolName = "Aave" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index e378507c7..91658f004 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -172,8 +172,7 @@ deposit aave DepositParams {..} = do data WithdrawParams = WithdrawParams { wpAsset :: AssetClass, - wpTo :: PubKeyHash, - wpFrom :: PubKeyHash, + wpUser :: PubKeyHash, wpAmount :: Integer } deriving stock (Show, Generic) @@ -186,16 +185,16 @@ withdraw :: (HasBlockchainActions s) => Aave -> WithdrawParams -> Contract w s T withdraw aave WithdrawParams {..} = do reserve <- State.findAaveReserve aave wpAsset - balance <- balanceAt wpFrom (rAToken reserve) - userConfigsTx <- if (wpAmount == balance) then do - let userConfigId = (wpAsset, wpFrom) + let userConfigId = (wpAsset, wpUser) + balance <- balanceAt wpUser (rAToken reserve) + userConfigsTx <- if wpAmount == balance then do userConfig <- State.findAaveUserConfig aave userConfigId - State.updateUserConfig aave Core.WithdrawRedeemer userConfigId $ userConfig { ucUsingAsCollateral = False } + State.updateUserConfig aave (Core.WithdrawRedeemer userConfigId) userConfigId $ userConfig { ucUsingAsCollateral = False } else pure mempty - burnTx <- AToken.burnATokensFrom aave reserve wpTo wpAmount + burnTx <- AToken.burnATokensFrom aave reserve wpUser wpAmount - reservesTx <- State.updateReserve aave Core.WithdrawRedeemer wpAsset (reserve { rAmount = rAmount reserve - wpAmount }) + reservesTx <- State.updateReserve aave (Core.WithdrawRedeemer userConfigId) wpAsset (reserve { rAmount = rAmount reserve - wpAmount }) ledgerTx <- TxUtils.submitTxPair $ burnTx <> reservesTx <> userConfigsTx _ <- awaitTxConfirmed $ txId ledgerTx From 3450dd3a2505bc0ba82b0b1c107a7b6237c2a2b9 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 7 Jun 2021 17:20:26 +0700 Subject: [PATCH 068/169] add validate withdraw --- .../lending-pool/src/Plutus/Contracts/Core.hs | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 0601ddaa0..30517f820 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -216,10 +216,54 @@ validateDeposit _ _ _ _ = trace "validateDeposit: Lending Pool Datum management validateWithdraw :: Aave -> AaveDatum -> ScriptContext -> UserConfigId -> Bool validateWithdraw aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId = + -- TODO add implementation for this case traceIfFalse "validateWithdraw: User Configs Datum change is not valid" False -validateWithdraw aave (ReservesDatum stateToken reserves) ctx userConfigId = - traceIfFalse "validateWithdraw: Reserves Datum change is not valid" True -validateWithdraw aave ReserveFundsDatum _ userConfigId = trace "validateWithdraw: ReserveFundsDatum" True +validateWithdraw aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) = + traceIfFalse "validateDeposit: Reserves Datum change is not valid" isValidReservesTransformation + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + + reservesOutputDatumHash = + findDatumHashByValue (assetClassValue stateToken 1) scriptOutputs + reservesOutputDatum :: + Maybe (AssetClass, AssocMap.Map ReserveId Reserve) + reservesOutputDatum = + reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves + + remainderDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo + remainderValue = remainderDatumHash >>= (`findValueByDatumHash` scriptOutputs) + + isValidReservesTransformation :: Bool + isValidReservesTransformation = + maybe False checkreserves reservesOutputDatum + checkreserves :: (AssetClass, AssocMap.Map ReserveId Reserve) -> Bool + checkreserves (newStateToken, newReserves) = + newStateToken == stateToken && + maybe + False + checkReserveState + ((,,) <$> remainderValue <*> AssocMap.lookup reserveId reserves <*> AssocMap.lookup reserveId newReserves) + -- TODO check that other fields are not changed + checkReserveState :: (Value, Reserve, Reserve) -> Bool + checkReserveState (value, oldState, newState) = + assetClassValueOf value reserveId == rAmount newState +validateWithdraw aave ReserveFundsDatum ctx (reserveId, actor) = + traceIfFalse "validateWithdraw: Reserve Funds Datum change is not valid" isValidFundsTransformation + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + + spentValue = txOutValue . txInInfoResolved <$> findOwnInput ctx + remainderValue = findValueByDatumHash scriptsDatumHash scriptOutputs + paidValue = valuePaidTo txInfo actor + + isValidFundsTransformation = maybe False checkFundsState $ (,) <$> spentValue <*> remainderValue + checkFundsState :: (Value, Value) -> Bool + checkFundsState (oldFunds, newFunds) = assetClassValueOf oldFunds reserveId - assetClassValueOf newFunds reserveId == assetClassValueOf paidValue reserveId + validateWithdraw _ _ _ _ = trace "validateWithdraw: Lending Pool Datum management is not allowed" False aaveProtocolName :: TokenName From a6c27d349f227a1f430d5848f3f646c15e43053e Mon Sep 17 00:00:00 2001 From: megakaban Date: Mon, 7 Jun 2021 17:24:56 +0700 Subject: [PATCH 069/169] Cleanup --- MetaLamp/lending-pool/client/src/AppAff.purs | 12 +- .../client/src/{ => Business}/Aave.purs | 29 ++-- .../Contract.purs} | 13 +- .../client/src/Capability/Delay.purs | 12 ++ .../client/src/Capability/LogMessages.purs | 13 ++ .../src/{ => Components}/AmountForm.purs | 12 +- .../App.purs} | 159 +++++++----------- MetaLamp/lending-pool/client/src/Main.purs | 4 +- .../client/src/Utils/RemoteDataState.purs | 17 ++ .../client/src/View/FundsTable.purs | 24 +++ .../client/src/View/RemoteDataState.purs | 16 ++ .../client/src/View/ReserveInfo.purs | 18 ++ 12 files changed, 198 insertions(+), 131 deletions(-) rename MetaLamp/lending-pool/client/src/{ => Business}/Aave.purs (72%) rename MetaLamp/lending-pool/client/src/{Capability.purs => Capability/Contract.purs} (78%) create mode 100644 MetaLamp/lending-pool/client/src/Capability/Delay.purs create mode 100644 MetaLamp/lending-pool/client/src/Capability/LogMessages.purs rename MetaLamp/lending-pool/client/src/{ => Components}/AmountForm.purs (86%) rename MetaLamp/lending-pool/client/src/{AppComponent.purs => Components/App.purs} (56%) create mode 100644 MetaLamp/lending-pool/client/src/Utils/RemoteDataState.purs create mode 100644 MetaLamp/lending-pool/client/src/View/FundsTable.purs create mode 100644 MetaLamp/lending-pool/client/src/View/RemoteDataState.purs create mode 100644 MetaLamp/lending-pool/client/src/View/ReserveInfo.purs diff --git a/MetaLamp/lending-pool/client/src/AppAff.purs b/MetaLamp/lending-pool/client/src/AppAff.purs index b5edd88b6..7e1b1c052 100644 --- a/MetaLamp/lending-pool/client/src/AppAff.purs +++ b/MetaLamp/lending-pool/client/src/AppAff.purs @@ -4,7 +4,9 @@ import Prelude import Affjax (Response, defaultRequest) import Affjax.RequestBody (RequestBody, string) -import Capability (class Contract, class LogMessages, APIError(..), ContractId(..), Endpoint(..)) +import Capability.Contract (class Contract, ContractId(..), Endpoint(..), APIError(..)) +import Capability.Delay (class Delay) +import Capability.LogMessages (class LogMessages) import Control.Monad.Except (ExceptT, runExceptT) import Control.Monad.Reader.Trans (class MonadAsk, ReaderT, asks, runReaderT) import Data.Bifunctor (bimap) @@ -37,7 +39,7 @@ instance monadAskAppM :: TypeEquals e Env => MonadAsk e AppM where runAppM :: Env -> AppM ~> Aff runAppM env (AppM m) = runReaderT m env -instance logMessages :: LogMessages AppM where +instance logMessagesAppM :: LogMessages AppM where logInfo = Console.log >>> liftEffect logError = Console.error >>> liftEffect @@ -69,9 +71,11 @@ post path body = do let affReq = defaultRequest { method = fromString "POST", url = url, content = Just body } runAjax $ ajax decode affReq -instance contract :: Contract AppM where +instance contractAppM :: Contract AppM where getContracts = get "/api/new/contract/instances" getContractStatus (ContractId cid) = get $ "/api/new/contract/instance/" <> cid <> "/status" callEndpoint (Endpoint endpoint) (ContractId cid) params = post ("/api/new/contract/instance/" <> cid <> "/endpoint/" <> endpoint) (string <<< encodeJSON $ params) - delay = delay >>> liftAff + +instance delayAppM :: Delay AppM where + delay = liftAff <<< delay diff --git a/MetaLamp/lending-pool/client/src/Aave.purs b/MetaLamp/lending-pool/client/src/Business/Aave.purs similarity index 72% rename from MetaLamp/lending-pool/client/src/Aave.purs rename to MetaLamp/lending-pool/client/src/Business/Aave.purs index 5e30fdad3..5a41c05be 100644 --- a/MetaLamp/lending-pool/client/src/Aave.purs +++ b/MetaLamp/lending-pool/client/src/Business/Aave.purs @@ -1,9 +1,11 @@ -module Aave where +module Business.Aave where import Prelude -import Capability (class Contract, APIError(..), ContractId, ContractUnit(..), Endpoint(..), callEndpoint, delay, getContractStatus, getContracts) -import Control.Monad.Except (lift, runExcept, runExceptT, throwError) +import Capability.Contract (class Contract, APIError(..), ContractId, ContractUnit(..), Endpoint(..), callEndpoint, getContractStatus, getContracts) +import Capability.Delay (class Delay, delay) +import Control.Monad.Except (runExcept, runExceptT, throwError) +import Control.Monad.Trans.Class (lift) import Data.Bifunctor (lmap) import Data.Either (Either(..), either) import Data.Json.JsonTuple (JsonTuple) @@ -20,6 +22,7 @@ import Plutus.PAB.Webserver.Types (ContractInstanceClientState(..)) import Plutus.V1.Ledger.Crypto (PubKeyHash) import Plutus.V1.Ledger.Value (AssetClass, Value) import PlutusTx.AssocMap (Map) + getAaveContracts :: forall m. Contract m => m (Either APIError (Array (ContractInstanceClientState AaveContracts))) getAaveContracts = getContracts @@ -38,6 +41,7 @@ getAaveResponse (ContractInstanceClientState { cicCurrentState: PartiallyDecoded getAaveResponseWith :: forall m a p. Contract m => + Delay m => Encode p => Endpoint -> Prism' UserContractState a -> @@ -50,6 +54,7 @@ getAaveResponseWith endpoint pick cid param = runExceptT $ do pollStatus :: forall m a. Contract m => + Delay m => Endpoint -> Prism' UserContractState a -> ContractId -> @@ -64,29 +69,29 @@ pollStatus endpoint pick cid = runExceptT $ do Just v -> pure v Nothing -> throwError $ AjaxCallError $ "Invalid state: " <> (show res) -deposit :: forall m. Contract m => ContractId -> DepositParams -> m (Either APIError Unit) +deposit :: forall m. Contract m => Delay m => ContractId -> DepositParams -> m (Either APIError Unit) deposit = getAaveResponseWith (Endpoint "deposit") _Deposited -withdraw :: forall m. Contract m => ContractId -> WithdrawParams -> m (Either APIError Unit) +withdraw :: forall m. Contract m => Delay m => ContractId -> WithdrawParams -> m (Either APIError Unit) withdraw = getAaveResponseWith (Endpoint "withdraw") _Withdrawn -borrow :: forall m. Contract m => ContractId -> BorrowParams -> m (Either APIError Unit) +borrow :: forall m. Contract m => Delay m => ContractId -> BorrowParams -> m (Either APIError Unit) borrow = getAaveResponseWith (Endpoint "borrow") _Borrowed -repay :: forall m. Contract m => ContractId -> RepayParams -> m (Either APIError Unit) +repay :: forall m. Contract m => Delay m => ContractId -> RepayParams -> m (Either APIError Unit) repay = getAaveResponseWith (Endpoint "repay") _Repaid -fundsAt :: forall m. Contract m => ContractId -> PubKeyHash -> m (Either APIError Value) +fundsAt :: forall m. Contract m => Delay m => ContractId -> PubKeyHash -> m (Either APIError Value) fundsAt = getAaveResponseWith (Endpoint "fundsAt") _FundsAt -poolFunds :: forall m. Contract m => ContractId -> m (Either APIError Value) +poolFunds :: forall m. Contract m => Delay m => ContractId -> m (Either APIError Value) poolFunds cid = getAaveResponseWith (Endpoint "poolFunds") _PoolFunds cid ContractUnit -reserves :: forall m. Contract m => ContractId -> m (Either APIError (Map AssetClass Reserve)) +reserves :: forall m. Contract m => Delay m => ContractId -> m (Either APIError (Map AssetClass Reserve)) reserves cid = getAaveResponseWith (Endpoint "reserves") _Reserves cid ContractUnit -users :: forall m. Contract m => ContractId -> m (Either APIError (Map (JsonTuple AssetClass PubKeyHash) UserConfig)) +users :: forall m. Contract m => Delay m => ContractId -> m (Either APIError (Map (JsonTuple AssetClass PubKeyHash) UserConfig)) users cid = getAaveResponseWith (Endpoint "users") _Users cid ContractUnit -ownPubKey :: forall m. Contract m => ContractId -> m (Either APIError PubKeyHash) +ownPubKey :: forall m. Contract m => Delay m => ContractId -> m (Either APIError PubKeyHash) ownPubKey cid = getAaveResponseWith (Endpoint "ownPubKey") _GetPubKey cid ContractUnit diff --git a/MetaLamp/lending-pool/client/src/Capability.purs b/MetaLamp/lending-pool/client/src/Capability/Contract.purs similarity index 78% rename from MetaLamp/lending-pool/client/src/Capability.purs rename to MetaLamp/lending-pool/client/src/Capability/Contract.purs index 5738f90ff..d9c5a74b7 100644 --- a/MetaLamp/lending-pool/client/src/Capability.purs +++ b/MetaLamp/lending-pool/client/src/Capability/Contract.purs @@ -1,24 +1,15 @@ -module Capability where +module Capability.Contract where import Prelude import Data.Either (Either) import Data.Generic.Rep (class Generic) import Data.Generic.Rep.Show (genericShow) -import Data.Time.Duration (Milliseconds) import Foreign (unsafeToForeign) import Foreign.Generic (class Decode, class Encode) import Halogen (HalogenM, lift) import Plutus.PAB.Webserver.Types (ContractInstanceClientState) -class Monad m <= LogMessages m where - logInfo :: String -> m Unit - logError :: String -> m Unit - -instance logMessagesHalogenM :: LogMessages m => LogMessages (HalogenM st act slots msg m) where - logInfo = logInfo >>> lift - logError = logError >>> lift - data APIError = AjaxCallError String derive instance genericAPIError :: Generic APIError _ @@ -42,10 +33,8 @@ class Monad m <= Contract m where getContracts :: forall a. Decode a => m (Either APIError (Array (ContractInstanceClientState a))) callEndpoint :: forall a. Encode a => Endpoint -> ContractId -> a -> m (Either APIError Unit) getContractStatus :: forall a. Decode a => ContractId -> m (Either APIError (ContractInstanceClientState a)) - delay :: Milliseconds -> m Unit instance contractHalogenM :: Contract m => Contract (HalogenM st act slots msg m) where getContracts = lift getContracts callEndpoint endpoint cid params = lift $ callEndpoint endpoint cid params getContractStatus = getContractStatus >>> lift - delay = delay >>> lift diff --git a/MetaLamp/lending-pool/client/src/Capability/Delay.purs b/MetaLamp/lending-pool/client/src/Capability/Delay.purs new file mode 100644 index 000000000..d59618865 --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Capability/Delay.purs @@ -0,0 +1,12 @@ +module Capability.Delay where + +import Prelude + +import Data.Time.Duration (Milliseconds) +import Halogen (HalogenM, lift) + +class Monad m <= Delay m where + delay :: Milliseconds -> m Unit + +instance delayHalogenM :: Delay m => Delay (HalogenM st act slots msg m) where + delay = delay >>> lift diff --git a/MetaLamp/lending-pool/client/src/Capability/LogMessages.purs b/MetaLamp/lending-pool/client/src/Capability/LogMessages.purs new file mode 100644 index 000000000..5d5a07bab --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Capability/LogMessages.purs @@ -0,0 +1,13 @@ +module Capability.LogMessages where + +import Prelude + +import Halogen (HalogenM, lift) + +class Monad m <= LogMessages m where + logInfo :: String -> m Unit + logError :: String -> m Unit + +instance logMessagesHalogenM :: LogMessages m => LogMessages (HalogenM st act slots msg m) where + logInfo = logInfo >>> lift + logError = logError >>> lift diff --git a/MetaLamp/lending-pool/client/src/AmountForm.purs b/MetaLamp/lending-pool/client/src/Components/AmountForm.purs similarity index 86% rename from MetaLamp/lending-pool/client/src/AmountForm.purs rename to MetaLamp/lending-pool/client/src/Components/AmountForm.purs index e284f1a38..c04593862 100644 --- a/MetaLamp/lending-pool/client/src/AmountForm.purs +++ b/MetaLamp/lending-pool/client/src/Components/AmountForm.purs @@ -1,7 +1,8 @@ -module AmountForm where +module Components.AmountForm where import Prelude +import Data.Array (head) import Data.BigInteger (BigInteger, fromString) import Data.Maybe (Maybe(..), fromMaybe, maybe) import Halogen as H @@ -20,7 +21,7 @@ type State = { amounts :: Array AmountInfo, name :: Maybe String, amount :: Mayb type Input = Array AmountInfo initialState :: Input -> State -initialState amounts = { amounts, name: Nothing, amount: Nothing } +initialState amounts = { amounts, name: _.name <$> head amounts, amount: Nothing } amountForm :: forall query m. H.Component HH.HTML query Input Output m amountForm = @@ -46,11 +47,8 @@ amountForm = handleAction = case _ of SubmitClick -> do { name, amount } <- H.get - case name of - Just n -> - case amount of - Just a -> H.raise $ Submit { name: n, amount: a } - _ -> pure unit + case { name: _, amount: _ } <$> name <*> amount of + Just params -> H.raise <<< Submit $ params _ -> pure unit EnterName name -> H.modify_ _ { name = Just name } EnterAmount amount -> H.modify_ _ { amount = fromString amount } diff --git a/MetaLamp/lending-pool/client/src/AppComponent.purs b/MetaLamp/lending-pool/client/src/Components/App.purs similarity index 56% rename from MetaLamp/lending-pool/client/src/AppComponent.purs rename to MetaLamp/lending-pool/client/src/Components/App.purs index d5d2d3dcb..da2bd511c 100644 --- a/MetaLamp/lending-pool/client/src/AppComponent.purs +++ b/MetaLamp/lending-pool/client/src/Components/App.purs @@ -1,11 +1,14 @@ -module AppComponent where +module Components.App where import Prelude -import Aave as Aave -import AmountForm as AmountForm -import Capability (class Contract, class LogMessages, APIError(..), ContractId(..), logError, logInfo) -import Control.Monad.Except (class MonadError, lift, runExceptT, throwError) +import Business.Aave as Aave +import Capability.Contract (class Contract, ContractId(..)) +import Capability.Delay (class Delay) +import Capability.LogMessages (class LogMessages, logError) +import Components.AmountForm as AmountForm +import Control.Monad.Except (lift, runExceptT, throwError) +import Data.Array (mapWithIndex) import Data.Bifunctor (bimap, lmap) import Data.BigInteger (BigInteger, fromInt) import Data.Either (Either(..), either) @@ -20,12 +23,16 @@ import Halogen as H import Halogen.HTML as HH import Halogen.HTML.Events as HE import Network.RemoteData (RemoteData(..), fromEither) +import Network.RemoteData as RD import Plutus.Contracts.Core (Reserve(..)) import Plutus.Contracts.Endpoints (BorrowParams(..), DepositParams(..), RepayParams(..), WithdrawParams(..)) import Plutus.PAB.Webserver.Types (ContractInstanceClientState(..)) import Plutus.V1.Ledger.Crypto (PubKeyHash) -import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..), Value(..)) +import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..), Value) import PlutusTx.AssocMap as Map +import View.FundsTable (fundsTable) +import View.RemoteDataState (remoteDataState) +import View.ReserveInfo (reserveInfo) import Wallet.Emulator.Wallet (Wallet(..)) import Wallet.Types (ContractInstanceId(..)) @@ -63,21 +70,8 @@ data SubmitOperation = SubmitDeposit | SubmitWithdraw | SubmitBorrow | SubmitRep toContractIdParam :: ContractInstanceId -> ContractId toContractIdParam (ContractInstanceId { unContractInstanceId: JsonUUID uuid }) = ContractId <<< UUID.toString $ uuid -handleExcept :: forall e a m. LogMessages m => Show e => Either e a -> m Unit -handleExcept = either (show >>> logError) (const $ pure unit) - -getRD :: forall e a m. MonadError String m => Show e => Show a => String -> RemoteData e a -> m a -getRD _ (Success s) = pure s -getRD tag rd = throwError $ tag <> " is not available: " <> (show rd) - -getContractId :: forall e a m. MonadError String m => Show e => Show a => RemoteData e a -> m a -getContractId = getRD "contractId" - -getPubKey :: forall e a m. MonadError String m => Show e => Show a => RemoteData e a -> m a -getPubKey = getRD "pubKey" - -getReserves :: forall e a m. MonadError String m => Show e => Show a => RemoteData e a -> m a -getReserves = getRD "reserves" +handleException :: forall e a m. LogMessages m => Show e => Either e a -> m Unit +handleException = either (logError <<< show) (const $ pure unit) type Slots = ( amountForm :: forall query. H.Slot query AmountForm.Output Int ) _amountForm = SProxy :: SProxy "amountForm" @@ -85,6 +79,7 @@ _amountForm = SProxy :: SProxy "amountForm" component :: forall input m query output. LogMessages m => Contract m => + Delay m => H.Component HH.HTML query input output m component = H.mkComponent @@ -111,57 +106,62 @@ component = Nothing -> H.modify_ _ { contractId = Failure "Contract instance not found" } Just (ContractInstanceClientState i) -> H.modify_ _ { contractId = Success (toContractIdParam i.cicContract) } - GetWalletPubKey -> handleExcept <=< runExceptT $ do + GetWalletPubKey -> handleException <=< runExceptT $ do lift $ H.modify_ _ { walletPubKey = Loading } - { contractId } <- lift H.get - cid <- getContractId contractId + state <- lift H.get + cid <- RD.maybe (throwError "Failed to get wallet public key") pure $ state.contractId pkh <- lift $ Aave.ownPubKey cid lift $ H.modify_ _ { walletPubKey = fromEither <<< lmap show $ pkh } - GetUserFunds -> handleExcept <=< runExceptT $ do + GetUserFunds -> handleException <=< runExceptT $ do lift $ H.modify_ _ { userFunds = Loading } - { contractId, walletPubKey } <- lift H.get - cid <- getContractId contractId - pkh <- getPubKey walletPubKey + state <- lift H.get + { cid, pkh } <- + RD.maybe (throwError "Failed to get user funds") pure $ + { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey funds <- lift $ Aave.fundsAt cid pkh lift $ H.modify_ _ { userFunds = fromEither <<< lmap show $ funds } - GetReserves -> handleExcept <=< runExceptT $ do + GetReserves -> handleException <=< runExceptT $ do lift $ H.modify_ _ { reserves = Loading } - { contractId } <- lift H.get - cid <- getContractId contractId + state <- lift H.get + cid <- RD.maybe (throwError "Failed to get reserves") pure $ state.contractId reserves <- lift $ Aave.reserves cid lift $ H.modify_ _ { reserves = fromEither <<< lmap show $ reserves } GetFunds -> do handleAction GetUserFunds handleAction GetReserves - Deposit { amount, asset } -> handleExcept <=< runExceptT $ do - { contractId, walletPubKey } <- lift H.get - cid <- getContractId contractId - pkh <- getPubKey walletPubKey + Deposit { amount, asset } -> handleException <=< runExceptT $ do + state <- lift H.get + { cid, pkh } <- + RD.maybe (throwError "Failed to deposit") pure $ + { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey res <- lift $ Aave.deposit cid $ DepositParams { dpAmount: amount, dpAsset: asset, dpOnBehalfOf: pkh } lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } - Withdraw { amount, asset } -> handleExcept <=< runExceptT $ do - { contractId, walletPubKey } <- lift H.get - cid <- getContractId contractId - pkh <- getPubKey walletPubKey + Withdraw { amount, asset } -> handleException <=< runExceptT $ do + state <- lift H.get + { cid, pkh } <- + RD.maybe (throwError "Failed to deposit") pure $ + { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey res <- lift $ Aave.withdraw cid $ WithdrawParams { wpAmount: amount, wpAsset: asset, wpTo: pkh, wpFrom: pkh } lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } - Borrow { amount, asset } -> handleExcept <=< runExceptT $ do - { contractId, walletPubKey } <- lift H.get - cid <- getContractId contractId - pkh <- getPubKey walletPubKey + Borrow { amount, asset } -> handleException <=< runExceptT $ do + state <- lift H.get + { cid, pkh } <- + RD.maybe (throwError "Failed to deposit") pure $ + { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey res <- lift $ Aave.borrow cid $ BorrowParams { bpAmount: amount, bpAsset: asset, bpOnBehalfOf: pkh } lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } - Repay { amount, asset } -> handleExcept <=< runExceptT $ do - { contractId, walletPubKey } <- lift H.get - cid <- getContractId contractId - pkh <- getPubKey walletPubKey + Repay { amount, asset } -> handleException <=< runExceptT $ do + state <- lift H.get + { cid, pkh } <- + RD.maybe (throwError "Failed to deposit") pure $ + { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey res <- lift $ Aave.repay cid $ RepayParams { rpAmount: amount, rpAsset: asset, rpOnBehalfOf: pkh } lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } - SubmitAmount operation (AmountForm.Submit { name, amount }) -> handleExcept <=< runExceptT $ do - { reserves: rs } <- lift H.get - reserves <- getReserves rs + SubmitAmount operation (AmountForm.Submit { name, amount }) -> handleException <=< runExceptT $ do + state <- lift H.get + reserves <- RD.maybe (throwError "Failed to submit") pure $ state.reserves case find (\(Tuple k _) -> getAssetName k == name) (Map.toTuples reserves) of Just (Tuple asset _) -> do case operation of @@ -175,58 +175,29 @@ component = render :: State -> H.ComponentHTML Action Slots m render state = HH.div_ - [ HH.button [ HE.onClick \_ -> Just Init ] [ HH.text "Start" ] - , remoteDataState (\v -> HH.div_ [HH.h2_ [HH.text "User funds"], fundsTable v]) state.userFunds - , remoteDataState - (\v -> HH.div_ $ [HH.h2_ [HH.text "Pool funds"]] <> map (\(Tuple a r) -> reserveTab a r) v) - (map Map.toTuples state.reserves) + [ HH.button [HE.onClick \_ -> Just Init] [HH.text "Start"] , remoteDataState - (\v -> HH.h2_ [HH.text "Deposit", HH.slot _amountForm 0 AmountForm.amountForm v (Just <<< (SubmitAmount SubmitDeposit))]) - (map reservesToAmounts state.reserves) + (\userFunds -> HH.div_ [HH.h2_ [HH.text "User funds"], fundsTable userFunds]) + state.userFunds , remoteDataState - (\v -> HH.h2_ [HH.text "Withdraw", HH.slot _amountForm 1 AmountForm.amountForm v (Just <<< (SubmitAmount SubmitWithdraw))]) - (map reservesToAmounts state.reserves) - , remoteDataState - (\v -> HH.h2_ [HH.text "Borrow", HH.slot _amountForm 1 AmountForm.amountForm v (Just <<< (SubmitAmount SubmitBorrow))]) - (map reservesToAmounts state.reserves) + (\reserves -> HH.div_ $ + [HH.h2_ [HH.text "Pool funds"]] <> + map (\(Tuple a r) -> reserveInfo a r) reserves + ) + (map Map.toTuples state.reserves) , remoteDataState - (\v -> HH.h2_ [HH.text "Repay", HH.slot _amountForm 1 AmountForm.amountForm v (Just <<< (SubmitAmount SubmitRepay))]) + (\amounts -> HH.div_ $ mapWithIndex + (\index (Tuple title operation) -> + HH.h2_ [HH.text title, HH.slot _amountForm index AmountForm.amountForm amounts (Just <<< (SubmitAmount operation))]) + [Tuple "Deposit" SubmitDeposit, Tuple "Withdraw" SubmitWithdraw, Tuple "Borrow" SubmitBorrow, Tuple "Repay" SubmitRepay] + ) (map reservesToAmounts state.reserves) ] -remoteDataState :: forall props act e a. Show e => (a -> HH.HTML props act) -> RemoteData e a -> HH.HTML props act -remoteDataState _ NotAsked = HH.div_ [HH.text ""] -remoteDataState _ Loading = HH.div_ [HH.text "Loading..."] -remoteDataState _ (Failure e) = HH.div_ [HH.text $ "Error: " <> show e] -remoteDataState f (Success s) = f s - -getAssetName :: AssetClass -> String -getAssetName (AssetClass { unAssetClass: JsonTuple (Tuple _ (TokenName { unTokenName: name })) }) = name - reservesToAmounts :: Map.Map AssetClass Reserve -> Array AmountForm.AmountInfo reservesToAmounts = map toInfo <<< Map.toTuples where toInfo (Tuple k (Reserve { rAmount })) = { name: getAssetName k, amount: rAmount } -reserveTab :: forall props act. AssetClass -> Reserve -> HH.HTML props act -reserveTab (AssetClass { unAssetClass: JsonTuple (Tuple _ name)}) (Reserve { rAmount }) = - poolTab name rAmount - -poolTab :: forall props act. TokenName -> BigInteger -> HH.HTML props act -poolTab (TokenName { unTokenName: name }) amount = - HH.div_ $ [HH.h4_ [HH.text (name <> " pool balance")], HH.text $ show amount] - -fundsTable :: forall props act. Value -> HH.HTML props act -fundsTable (Value ({ getValue: m })) = HH.div_ $ do - (Tuple _ amounts) <- Map.toTuples m - (Tuple name amount) <- Map.toTuples amounts - if amount > (fromInt 0) - then pure $ amountTab name amount - else [] - -amountTab :: forall props act. TokenName -> BigInteger -> HH.HTML props act -amountTab (TokenName { unTokenName: name }) amount = - HH.div_ $ [HH.text (showName name <> " " <> show amount)] - where - showName "" = "ADA" - showName n = n +getAssetName :: AssetClass -> String +getAssetName (AssetClass { unAssetClass: JsonTuple (Tuple _ (TokenName { unTokenName: name })) }) = name diff --git a/MetaLamp/lending-pool/client/src/Main.purs b/MetaLamp/lending-pool/client/src/Main.purs index db1f7604c..452bd7852 100644 --- a/MetaLamp/lending-pool/client/src/Main.purs +++ b/MetaLamp/lending-pool/client/src/Main.purs @@ -2,7 +2,7 @@ module Main where import Prelude -import AppComponent as B +import Components.App as App import AppAff (runAppM) import Effect (Effect) import Effect.Unsafe (unsafePerformEffect) @@ -13,7 +13,7 @@ import Halogen.VDom.Driver (runUI) main :: Effect Unit main = runHalogenAff do - let rootComponent = H.hoist (runAppM { host: "localhost", port: 8080 }) B.component + let rootComponent = H.hoist (runAppM { host: "localhost", port: 8080 }) App.component body <- awaitBody runUI rootComponent unit body diff --git a/MetaLamp/lending-pool/client/src/Utils/RemoteDataState.purs b/MetaLamp/lending-pool/client/src/Utils/RemoteDataState.purs new file mode 100644 index 000000000..659389bfb --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Utils/RemoteDataState.purs @@ -0,0 +1,17 @@ +module Utils.RemoteDataState where + +import Halogen.HTML as HH +import Network.RemoteData (RemoteData(..)) + +type RemoteDataHandle props act e a = { + onNotAsked :: HH.HTML props act, + onLoading :: HH.HTML props act, + onFailure :: e -> HH.HTML props act, + onSuccess :: a -> HH.HTML props act +} + +makeRemoteDataState :: forall props act e a. RemoteDataHandle props act e a -> RemoteData e a -> HH.HTML props act +makeRemoteDataState { onNotAsked } NotAsked = onNotAsked +makeRemoteDataState { onLoading } Loading = onLoading +makeRemoteDataState { onFailure } (Failure e) = onFailure e +makeRemoteDataState { onSuccess } (Success s) = onSuccess s diff --git a/MetaLamp/lending-pool/client/src/View/FundsTable.purs b/MetaLamp/lending-pool/client/src/View/FundsTable.purs new file mode 100644 index 000000000..68b7f4fea --- /dev/null +++ b/MetaLamp/lending-pool/client/src/View/FundsTable.purs @@ -0,0 +1,24 @@ +module View.FundsTable where + +import Prelude + +import Data.BigInteger (BigInteger, fromInt) +import Data.Tuple (Tuple(..)) +import Halogen.HTML as HH +import Plutus.V1.Ledger.Value (TokenName(..), Value(..)) +import PlutusTx.AssocMap as Map + +fundsTable :: forall props act. Value -> HH.HTML props act +fundsTable (Value ({ getValue: m })) = HH.div_ $ do + (Tuple _ amounts) <- Map.toTuples m + (Tuple name amount) <- Map.toTuples amounts + if amount > (fromInt 0) + then pure $ amountTab name amount + else [] + +amountTab :: forall props act. TokenName -> BigInteger -> HH.HTML props act +amountTab (TokenName { unTokenName: name }) amount = + HH.div_ $ [HH.text (showName name <> " " <> show amount)] + where + showName "" = "ADA" + showName n = n diff --git a/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs b/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs new file mode 100644 index 000000000..cdf9d14eb --- /dev/null +++ b/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs @@ -0,0 +1,16 @@ +module View.RemoteDataState where + +import Prelude + +import Halogen.HTML as HH +import Network.RemoteData (RemoteData) +import Utils.RemoteDataState (makeRemoteDataState) + +remoteDataState :: forall props act e a. Show e => (a -> HH.HTML props act) -> RemoteData e a -> HH.HTML props act +remoteDataState onSuccess = + makeRemoteDataState + { onNotAsked: HH.div_ [HH.text ""], + onLoading: HH.div_ [HH.text "Loading..."], + onFailure: \e -> HH.div_ [HH.text $ "Error: " <> show e], + onSuccess + } diff --git a/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs b/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs new file mode 100644 index 000000000..a7e1c1d5d --- /dev/null +++ b/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs @@ -0,0 +1,18 @@ +module View.ReserveInfo where + +import Prelude + +import Data.BigInteger (BigInteger) +import Data.Json.JsonTuple (JsonTuple(..)) +import Data.Tuple (Tuple(..)) +import Halogen.HTML as HH +import Plutus.Contracts.Core (Reserve(..)) +import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..)) + +reserveInfo :: forall props act. AssetClass -> Reserve -> HH.HTML props act +reserveInfo (AssetClass { unAssetClass: JsonTuple (Tuple _ name)}) (Reserve { rAmount }) = + poolTab name rAmount + +poolTab :: forall props act. TokenName -> BigInteger -> HH.HTML props act +poolTab (TokenName { unTokenName: name }) amount = + HH.div_ $ [HH.h4_ [HH.text (name <> " pool balance")], HH.text $ show amount] From 0873943120ac6bccf5461bd5dfd9f6dafc0d5f91 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 7 Jun 2021 18:14:04 +0700 Subject: [PATCH 070/169] check funds state in withdraw --- .../src/Ext/Plutus/Ledger/Contexts.hs | 25 ++++++++++++++++--- .../lending-pool/src/Plutus/Contracts/Core.hs | 15 ++++++----- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs index 22bf239e2..ea7e2b417 100644 --- a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs +++ b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs @@ -1,13 +1,22 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# OPTIONS_GHC -fno-specialise #-} +{-# LANGUAGE NamedFieldPuns #-} module Ext.Plutus.Ledger.Contexts where -import Ledger (Datum (getDatum), DatumHash, TxInfo, Value, - findDatum) +import Ledger (Address (Address), + Datum (getDatum), DatumHash, + PubKeyHash, + TxInInfo (txInInfoResolved), + TxInfo (txInfoInputs), + TxOut (TxOut, txOutAddress, txOutValue), + Value, findDatum) +import Plutus.V1.Ledger.Credential (Credential (PubKeyCredential)) import qualified PlutusTx -import PlutusTx.Prelude (Eq ((==)), Maybe, Monad ((>>=)), find, fst, - snd, (.), (<$>)) +import PlutusTx.Prelude (Eq ((==)), Maybe (..), + Monad ((>>=)), find, fst, + mapMaybe, mconcat, snd, ($), (.), + (<$>)) {-# INLINABLE findDatumHashByValue #-} -- | Find the hash of a datum, if it is part of the pending transaction's @@ -28,3 +37,11 @@ findValueByDatumHash dh outs = snd <$> find f outs {-# INLINABLE parseDatum #-} parseDatum :: PlutusTx.IsData a => TxInfo -> DatumHash -> Maybe a parseDatum txInfo dh = findDatum dh txInfo >>= (PlutusTx.fromData . getDatum) + +{-# INLINABLE valueSpentFrom #-} +valueSpentFrom :: TxInfo -> PubKeyHash -> Value +valueSpentFrom txInfo pk = + let flt TxOut {txOutAddress = Address (PubKeyCredential pk') _, txOutValue} + | pk == pk' = Just txOutValue + flt _ = Nothing + in mconcat $ mapMaybe flt (txInInfoResolved <$> txInfoInputs txInfo) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 30517f820..dc9f6d899 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -24,7 +24,7 @@ import qualified Data.Map as Map import Data.Text (Text, pack) import Data.Void (Void) import Ext.Plutus.Ledger.Contexts (findDatumHashByValue, - findValueByDatumHash, + findValueByDatumHash,valueSpentFrom, parseDatum) import Ledger hiding (singleton) import Ledger.Constraints as Constraints @@ -256,13 +256,16 @@ validateWithdraw aave ReserveFundsDatum ctx (reserveId, actor) = (scriptsHash, scriptsDatumHash) = ownHashes ctx scriptOutputs = scriptOutputsAt scriptsHash txInfo - spentValue = txOutValue . txInInfoResolved <$> findOwnInput ctx - remainderValue = findValueByDatumHash scriptsDatumHash scriptOutputs - paidValue = valuePaidTo txInfo actor + scriptSpentValue = txOutValue . txInInfoResolved <$> findOwnInput ctx + scriptRemainderValue = findValueByDatumHash scriptsDatumHash scriptOutputs + actorSpentValue = valueSpentFrom txInfo actor + actorRemainderValue = valuePaidTo txInfo actor - isValidFundsTransformation = maybe False checkFundsState $ (,) <$> spentValue <*> remainderValue + isValidFundsTransformation = maybe False checkFundsState $ (,) <$> scriptSpentValue <*> scriptRemainderValue checkFundsState :: (Value, Value) -> Bool - checkFundsState (oldFunds, newFunds) = assetClassValueOf oldFunds reserveId - assetClassValueOf newFunds reserveId == assetClassValueOf paidValue reserveId + checkFundsState (oldFunds, newFunds) = + let paidAmout = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId + in assetClassValueOf oldFunds reserveId - assetClassValueOf newFunds reserveId == paidAmout validateWithdraw _ _ _ _ = trace "validateWithdraw: Lending Pool Datum management is not allowed" False From 09b2ad0f0a85be195fa698bf82a0fabb3001276f Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 7 Jun 2021 20:31:11 +0700 Subject: [PATCH 071/169] add borrow validator --- .../lending-pool/src/Plutus/Contracts/Core.hs | 93 ++++++++++++++++++- .../src/Plutus/Contracts/Endpoints.hs | 10 +- 2 files changed, 95 insertions(+), 8 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index dc9f6d899..7985728ec 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -92,7 +92,7 @@ data AaveRedeemer = StartRedeemer | DepositRedeemer UserConfigId | WithdrawRedeemer UserConfigId - | BorrowRedeemer + | BorrowRedeemer UserConfigId | RepayRedeemer deriving Show @@ -131,6 +131,7 @@ instance Scripts.ScriptType AaveScript where -- Main validator -- Each state field must have one or more associated actions(Redeemer types), -- produced on state update, which are then validated here +-- TODO Check amounts are > 0 makeAaveValidator :: Aave -> AaveDatum -> AaveRedeemer @@ -139,7 +140,7 @@ makeAaveValidator :: Aave makeAaveValidator aave datum StartRedeemer ctx = trace "StartRedeemer" $ validateStart aave datum ctx makeAaveValidator aave datum (DepositRedeemer userConfigId) ctx = trace "DepositRedeemer" $ validateDeposit aave datum ctx userConfigId makeAaveValidator aave datum (WithdrawRedeemer userConfigId) ctx = trace "WithdrawRedeemer" $ validateWithdraw aave datum ctx userConfigId -makeAaveValidator _ _ BorrowRedeemer _ = True +makeAaveValidator aave datum (BorrowRedeemer userConfigId) ctx = trace "BorrowRedeemer" $ validateBorrow aave datum ctx userConfigId makeAaveValidator _ _ RepayRedeemer _ = True validateStart :: Aave -> AaveDatum -> ScriptContext -> Bool @@ -219,7 +220,7 @@ validateWithdraw aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId -- TODO add implementation for this case traceIfFalse "validateWithdraw: User Configs Datum change is not valid" False validateWithdraw aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) = - traceIfFalse "validateDeposit: Reserves Datum change is not valid" isValidReservesTransformation + traceIfFalse "validateWithdraw: Reserves Datum change is not valid" isValidReservesTransformation where txInfo = scriptContextTxInfo ctx (scriptsHash, scriptsDatumHash) = ownHashes ctx @@ -249,6 +250,7 @@ validateWithdraw aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) checkReserveState :: (Value, Reserve, Reserve) -> Bool checkReserveState (value, oldState, newState) = assetClassValueOf value reserveId == rAmount newState + validateWithdraw aave ReserveFundsDatum ctx (reserveId, actor) = traceIfFalse "validateWithdraw: Reserve Funds Datum change is not valid" isValidFundsTransformation where @@ -269,6 +271,91 @@ validateWithdraw aave ReserveFundsDatum ctx (reserveId, actor) = validateWithdraw _ _ _ _ = trace "validateWithdraw: Lending Pool Datum management is not allowed" False +validateBorrow :: Aave -> AaveDatum -> ScriptContext -> UserConfigId -> Bool +validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) = + traceIfFalse "validateBorrow: User Configs Datum change is not valid" isValidUserConfigsTransformation + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + userConfigsOutputDatumHash = + findDatumHashByValue (assetClassValue stateToken 1) scriptOutputs + userConfigsOutputDatum :: + Maybe (AssetClass, AssocMap.Map UserConfigId UserConfig) + userConfigsOutputDatum = + userConfigsOutputDatumHash >>= parseDatum txInfo >>= pickUserConfigs + + actorSpentValue = valueSpentFrom txInfo actor + actorRemainderValue = valuePaidTo txInfo actor + + isValidUserConfigsTransformation :: Bool + isValidUserConfigsTransformation = + maybe False checkUserConfigs userConfigsOutputDatum + checkUserConfigs :: + (AssetClass, AssocMap.Map UserConfigId UserConfig) -> Bool + checkUserConfigs (newStateToken, newUserConfigs) = + newStateToken == stateToken && + maybe False (checkRedeemerConfig $ AssocMap.lookup userConfigId userConfigs) (AssocMap.lookup userConfigId newUserConfigs) + -- TODO check that other fields are not changed + checkRedeemerConfig :: Maybe UserConfig -> UserConfig -> Bool + checkRedeemerConfig oldState newState = + let oldDebt = fromMaybe 0 $ oldState >>= ucDebt + debtAmount = maybe 0 (flip (-) oldDebt) (ucDebt newState) + disbursementAmout = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId + in debtAmount == disbursementAmout + +validateBorrow aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) = + traceIfFalse "validateBorrow: Reserves Datum change is not valid" isValidReservesTransformation + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + + reservesOutputDatumHash = + findDatumHashByValue (assetClassValue stateToken 1) scriptOutputs + reservesOutputDatum :: + Maybe (AssetClass, AssocMap.Map ReserveId Reserve) + reservesOutputDatum = + reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves + + remainderDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo + remainderValue = remainderDatumHash >>= (`findValueByDatumHash` scriptOutputs) + + isValidReservesTransformation :: Bool + isValidReservesTransformation = + maybe False checkreserves reservesOutputDatum + checkreserves :: (AssetClass, AssocMap.Map ReserveId Reserve) -> Bool + checkreserves (newStateToken, newReserves) = + newStateToken == stateToken && + maybe + False + checkReserveState + ((,,) <$> remainderValue <*> AssocMap.lookup reserveId reserves <*> AssocMap.lookup reserveId newReserves) + -- TODO check that other fields are not changed + checkReserveState :: (Value, Reserve, Reserve) -> Bool + checkReserveState (value, oldState, newState) = + assetClassValueOf value reserveId == rAmount newState + +validateBorrow aave ReserveFundsDatum ctx (reserveId, actor) = + traceIfFalse "validateBorrow: Reserve Funds Datum change is not valid" isValidFundsTransformation + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + + scriptSpentValue = txOutValue . txInInfoResolved <$> findOwnInput ctx + scriptRemainderValue = findValueByDatumHash scriptsDatumHash scriptOutputs + actorSpentValue = valueSpentFrom txInfo actor + actorRemainderValue = valuePaidTo txInfo actor + + isValidFundsTransformation = maybe False checkFundsState $ (,) <$> scriptSpentValue <*> scriptRemainderValue + checkFundsState :: (Value, Value) -> Bool + checkFundsState (oldFunds, newFunds) = + let paidAmout = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId + in assetClassValueOf oldFunds reserveId - assetClassValueOf newFunds reserveId == paidAmout + +validateBorrow _ _ _ _ = trace "validateBorrow: Lending Pool Datum management is not allowed" False + aaveProtocolName :: TokenName aaveProtocolName = "Aave" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 91658f004..c2ee53a53 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -219,24 +219,24 @@ borrow aave BorrowParams {..} = do utxos <- Map.filter ((> 0) . flip assetClassValueOf bpAsset . txOutValue . txOutTxOut) <$> utxoAt (Core.aaveAddress aave) - let inputs = (\(ref, tx) -> OutputValue ref tx Core.BorrowRedeemer) <$> Map.toList utxos + let userConfigId = (rCurrency reserve, bpOnBehalfOf) + let inputs = (\(ref, tx) -> OutputValue ref tx (Core.BorrowRedeemer userConfigId)) <$> Map.toList utxos let payment = assetClassValue (rCurrency reserve) bpAmount let remainder = assetClassValue (rCurrency reserve) (rAmount reserve - bpAmount) let disbursementTx = TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs bpOnBehalfOf payment <> TxUtils.mustPayToScript (Core.aaveInstance aave) bpOnBehalfOf Core.ReserveFundsDatum remainder userConfigs <- ovValue <$> State.findAaveUserConfigs aave - let userConfigId = (rCurrency reserve, bpOnBehalfOf) userConfigsTx <- case AssocMap.lookup userConfigId userConfigs of Nothing -> State.addUserConfig - aave Core.BorrowRedeemer + aave (Core.BorrowRedeemer userConfigId) userConfigId UserConfig { ucUsingAsCollateral = False, ucDebt = Just bpAmount } Just userConfig -> - State.updateUserConfig aave Core.BorrowRedeemer userConfigId $ userConfig { ucDebt = (+ bpAmount) <$> ucDebt userConfig } + State.updateUserConfig aave (Core.BorrowRedeemer userConfigId) userConfigId $ userConfig { ucDebt = (+ bpAmount) <$> ucDebt userConfig } - reservesTx <- State.updateReserve aave Core.BorrowRedeemer bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) + reservesTx <- State.updateReserve aave (Core.BorrowRedeemer userConfigId) bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) ledgerTx <- TxUtils.submitTxPair $ disbursementTx <> reservesTx <> userConfigsTx _ <- awaitTxConfirmed $ txId ledgerTx From 4089ea8b06a38cc77c1189b6666a0aa81b6b6a50 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 7 Jun 2021 20:47:18 +0700 Subject: [PATCH 072/169] abstract similar validators --- .../lending-pool/src/Plutus/Contracts/Core.hs | 117 +++++++----------- 1 file changed, 43 insertions(+), 74 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 7985728ec..cf1c94dbd 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -141,7 +141,7 @@ makeAaveValidator aave datum StartRedeemer ctx = trace "StartRedeemer" $ vali makeAaveValidator aave datum (DepositRedeemer userConfigId) ctx = trace "DepositRedeemer" $ validateDeposit aave datum ctx userConfigId makeAaveValidator aave datum (WithdrawRedeemer userConfigId) ctx = trace "WithdrawRedeemer" $ validateWithdraw aave datum ctx userConfigId makeAaveValidator aave datum (BorrowRedeemer userConfigId) ctx = trace "BorrowRedeemer" $ validateBorrow aave datum ctx userConfigId -makeAaveValidator _ _ RepayRedeemer _ = True +makeAaveValidator aave datum RepayRedeemer ctx = trace "RepayRedeemer" $ validateRepay aave datum ctx validateStart :: Aave -> AaveDatum -> ScriptContext -> Bool validateStart aave (LendingPoolDatum operator) ctx = @@ -219,55 +219,11 @@ validateWithdraw :: Aave -> AaveDatum -> ScriptContext -> UserConfigId -> Bool validateWithdraw aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId = -- TODO add implementation for this case traceIfFalse "validateWithdraw: User Configs Datum change is not valid" False -validateWithdraw aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) = - traceIfFalse "validateWithdraw: Reserves Datum change is not valid" isValidReservesTransformation - where - txInfo = scriptContextTxInfo ctx - (scriptsHash, scriptsDatumHash) = ownHashes ctx - scriptOutputs = scriptOutputsAt scriptsHash txInfo - - reservesOutputDatumHash = - findDatumHashByValue (assetClassValue stateToken 1) scriptOutputs - reservesOutputDatum :: - Maybe (AssetClass, AssocMap.Map ReserveId Reserve) - reservesOutputDatum = - reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves - - remainderDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo - remainderValue = remainderDatumHash >>= (`findValueByDatumHash` scriptOutputs) - - isValidReservesTransformation :: Bool - isValidReservesTransformation = - maybe False checkreserves reservesOutputDatum - checkreserves :: (AssetClass, AssocMap.Map ReserveId Reserve) -> Bool - checkreserves (newStateToken, newReserves) = - newStateToken == stateToken && - maybe - False - checkReserveState - ((,,) <$> remainderValue <*> AssocMap.lookup reserveId reserves <*> AssocMap.lookup reserveId newReserves) - -- TODO check that other fields are not changed - checkReserveState :: (Value, Reserve, Reserve) -> Bool - checkReserveState (value, oldState, newState) = - assetClassValueOf value reserveId == rAmount newState +validateWithdraw aave (ReservesDatum stateToken reserves) ctx userConfigId = + traceIfFalse "validateWithdraw: Reserves Datum change is not valid" $ checkNegativeReservesTransformation stateToken reserves ctx userConfigId -validateWithdraw aave ReserveFundsDatum ctx (reserveId, actor) = - traceIfFalse "validateWithdraw: Reserve Funds Datum change is not valid" isValidFundsTransformation - where - txInfo = scriptContextTxInfo ctx - (scriptsHash, scriptsDatumHash) = ownHashes ctx - scriptOutputs = scriptOutputsAt scriptsHash txInfo - - scriptSpentValue = txOutValue . txInInfoResolved <$> findOwnInput ctx - scriptRemainderValue = findValueByDatumHash scriptsDatumHash scriptOutputs - actorSpentValue = valueSpentFrom txInfo actor - actorRemainderValue = valuePaidTo txInfo actor - - isValidFundsTransformation = maybe False checkFundsState $ (,) <$> scriptSpentValue <*> scriptRemainderValue - checkFundsState :: (Value, Value) -> Bool - checkFundsState (oldFunds, newFunds) = - let paidAmout = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId - in assetClassValueOf oldFunds reserveId - assetClassValueOf newFunds reserveId == paidAmout +validateWithdraw aave ReserveFundsDatum ctx userConfigId = + traceIfFalse "validateWithdraw: Reserve Funds Datum change is not valid" $ checkNegativeFundsTransformation ctx userConfigId validateWithdraw _ _ _ _ = trace "validateWithdraw: Lending Pool Datum management is not allowed" False @@ -304,8 +260,44 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( disbursementAmout = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId in debtAmount == disbursementAmout -validateBorrow aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) = - traceIfFalse "validateBorrow: Reserves Datum change is not valid" isValidReservesTransformation +validateBorrow aave (ReservesDatum stateToken reserves) ctx userConfigId = + traceIfFalse "validateBorrow: Reserves Datum change is not valid" $ checkNegativeReservesTransformation stateToken reserves ctx userConfigId + +validateBorrow aave ReserveFundsDatum ctx userConfigId = + traceIfFalse "validateBorrow: Reserve Funds Datum change is not valid" $ checkNegativeFundsTransformation ctx userConfigId + +validateBorrow _ _ _ _ = trace "validateBorrow: Lending Pool Datum management is not allowed" False + +validateRepay :: Aave -> AaveDatum -> ScriptContext -> Bool +validateRepay aave ReserveFundsDatum ctx = trace "validateRepay: ReserveFundsDatum" False +validateRepay aave (LendingPoolDatum _) ctx = trace "validateRepay: LendingPoolDatum" False +validateRepay aave (ReservesDatum _ _) ctx = trace "validateRepay: ReservesDatum" False +validateRepay aave (UserConfigsDatum _ _) ctx = trace "validateRepay: UserConfigsDatum" False + +checkNegativeFundsTransformation :: ScriptContext -> UserConfigId -> Bool +checkNegativeFundsTransformation ctx (reserveId, actor) = maybe False checkFundsState $ (,) <$> scriptSpentValue <*> scriptRemainderValue + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + + scriptSpentValue = txOutValue . txInInfoResolved <$> findOwnInput ctx + scriptRemainderValue = findValueByDatumHash scriptsDatumHash scriptOutputs + actorSpentValue = valueSpentFrom txInfo actor + actorRemainderValue = valuePaidTo txInfo actor + + checkFundsState :: (Value, Value) -> Bool + checkFundsState (oldFunds, newFunds) = + let paidAmout = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId + in assetClassValueOf oldFunds reserveId - assetClassValueOf newFunds reserveId == paidAmout + +checkNegativeReservesTransformation :: AssetClass + -> AssocMap.Map AssetClass Reserve + -> ScriptContext + -> UserConfigId + -> Bool +checkNegativeReservesTransformation stateToken reserves ctx (reserveId, _) = + maybe False checkreserves reservesOutputDatum where txInfo = scriptContextTxInfo ctx (scriptsHash, scriptsDatumHash) = ownHashes ctx @@ -321,9 +313,6 @@ validateBorrow aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) = remainderDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo remainderValue = remainderDatumHash >>= (`findValueByDatumHash` scriptOutputs) - isValidReservesTransformation :: Bool - isValidReservesTransformation = - maybe False checkreserves reservesOutputDatum checkreserves :: (AssetClass, AssocMap.Map ReserveId Reserve) -> Bool checkreserves (newStateToken, newReserves) = newStateToken == stateToken && @@ -336,26 +325,6 @@ validateBorrow aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) = checkReserveState (value, oldState, newState) = assetClassValueOf value reserveId == rAmount newState -validateBorrow aave ReserveFundsDatum ctx (reserveId, actor) = - traceIfFalse "validateBorrow: Reserve Funds Datum change is not valid" isValidFundsTransformation - where - txInfo = scriptContextTxInfo ctx - (scriptsHash, scriptsDatumHash) = ownHashes ctx - scriptOutputs = scriptOutputsAt scriptsHash txInfo - - scriptSpentValue = txOutValue . txInInfoResolved <$> findOwnInput ctx - scriptRemainderValue = findValueByDatumHash scriptsDatumHash scriptOutputs - actorSpentValue = valueSpentFrom txInfo actor - actorRemainderValue = valuePaidTo txInfo actor - - isValidFundsTransformation = maybe False checkFundsState $ (,) <$> scriptSpentValue <*> scriptRemainderValue - checkFundsState :: (Value, Value) -> Bool - checkFundsState (oldFunds, newFunds) = - let paidAmout = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId - in assetClassValueOf oldFunds reserveId - assetClassValueOf newFunds reserveId == paidAmout - -validateBorrow _ _ _ _ = trace "validateBorrow: Lending Pool Datum management is not allowed" False - aaveProtocolName :: TokenName aaveProtocolName = "Aave" From 1f48df7d85fb453baa2e7cddd696a5707db303ad Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 7 Jun 2021 21:27:10 +0700 Subject: [PATCH 073/169] add repay validator --- .../lending-pool/src/Plutus/Contracts/Core.hs | 111 ++++++++++++------ .../src/Plutus/Contracts/Endpoints.hs | 4 +- 2 files changed, 75 insertions(+), 40 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index cf1c94dbd..247afc66a 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -93,7 +93,7 @@ data AaveRedeemer = | DepositRedeemer UserConfigId | WithdrawRedeemer UserConfigId | BorrowRedeemer UserConfigId - | RepayRedeemer + | RepayRedeemer UserConfigId deriving Show PlutusTx.unstableMakeIsData ''AaveRedeemer @@ -141,7 +141,7 @@ makeAaveValidator aave datum StartRedeemer ctx = trace "StartRedeemer" $ vali makeAaveValidator aave datum (DepositRedeemer userConfigId) ctx = trace "DepositRedeemer" $ validateDeposit aave datum ctx userConfigId makeAaveValidator aave datum (WithdrawRedeemer userConfigId) ctx = trace "WithdrawRedeemer" $ validateWithdraw aave datum ctx userConfigId makeAaveValidator aave datum (BorrowRedeemer userConfigId) ctx = trace "BorrowRedeemer" $ validateBorrow aave datum ctx userConfigId -makeAaveValidator aave datum RepayRedeemer ctx = trace "RepayRedeemer" $ validateRepay aave datum ctx +makeAaveValidator aave datum (RepayRedeemer userConfigId) ctx = trace "RepayRedeemer" $ validateRepay aave datum ctx userConfigId validateStart :: Aave -> AaveDatum -> ScriptContext -> Bool validateStart aave (LendingPoolDatum operator) ctx = @@ -181,37 +181,8 @@ validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId checkRedeemerConfig :: UserConfig -> Bool checkRedeemerConfig UserConfig{..} = ucUsingAsCollateral -validateDeposit aave (ReservesDatum stateToken reserves) ctx (reserveId, actor) = - traceIfFalse "validateDeposit: Reserves Datum change is not valid" isValidReservesTransformation - where - txInfo = scriptContextTxInfo ctx - (scriptsHash, scriptsDatumHash) = ownHashes ctx - scriptOutputs = scriptOutputsAt scriptsHash txInfo - - reservesOutputDatumHash = - findDatumHashByValue (assetClassValue stateToken 1) scriptOutputs - reservesOutputDatum :: - Maybe (AssetClass, AssocMap.Map ReserveId Reserve) - reservesOutputDatum = - reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves - - investmentDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo - investmentValue = investmentDatumHash >>= (`findValueByDatumHash` scriptOutputs) - - isValidReservesTransformation :: Bool - isValidReservesTransformation = - maybe False checkreserves reservesOutputDatum - checkreserves :: (AssetClass, AssocMap.Map ReserveId Reserve) -> Bool - checkreserves (newStateToken, newReserves) = - newStateToken == stateToken && - maybe - False - checkReserveState - ((,,) <$> investmentValue <*> AssocMap.lookup reserveId reserves <*> AssocMap.lookup reserveId newReserves) - -- TODO check that other fields are not changed - checkReserveState :: (Value, Reserve, Reserve) -> Bool - checkReserveState (value, oldState, newState) = - assetClassValueOf value reserveId == (rAmount newState - rAmount oldState) +validateDeposit aave (ReservesDatum stateToken reserves) ctx userConfigId = + traceIfFalse "validateDeposit: Reserves Datum change is not valid" $ checkPositiveReservesTransformation stateToken reserves ctx userConfigId validateDeposit _ _ _ _ = trace "validateDeposit: Lending Pool Datum management is not allowed" False @@ -268,11 +239,42 @@ validateBorrow aave ReserveFundsDatum ctx userConfigId = validateBorrow _ _ _ _ = trace "validateBorrow: Lending Pool Datum management is not allowed" False -validateRepay :: Aave -> AaveDatum -> ScriptContext -> Bool -validateRepay aave ReserveFundsDatum ctx = trace "validateRepay: ReserveFundsDatum" False -validateRepay aave (LendingPoolDatum _) ctx = trace "validateRepay: LendingPoolDatum" False -validateRepay aave (ReservesDatum _ _) ctx = trace "validateRepay: ReservesDatum" False -validateRepay aave (UserConfigsDatum _ _) ctx = trace "validateRepay: UserConfigsDatum" False +validateRepay :: Aave -> AaveDatum -> ScriptContext -> UserConfigId -> Bool +validateRepay aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) = + traceIfFalse "validateRepay: User Configs Datum change is not valid" isValidUserConfigsTransformation + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + userConfigsOutputDatumHash = + findDatumHashByValue (assetClassValue stateToken 1) scriptOutputs + userConfigsOutputDatum :: + Maybe (AssetClass, AssocMap.Map UserConfigId UserConfig) + userConfigsOutputDatum = + userConfigsOutputDatumHash >>= parseDatum txInfo >>= pickUserConfigs + + actorSpentValue = valueSpentFrom txInfo actor + actorRemainderValue = valuePaidTo txInfo actor + + isValidUserConfigsTransformation :: Bool + isValidUserConfigsTransformation = + maybe False checkUserConfigs userConfigsOutputDatum + checkUserConfigs :: (AssetClass, AssocMap.Map UserConfigId UserConfig) -> Bool + checkUserConfigs (newStateToken, newUserConfigs) = + newStateToken == stateToken && + (Just True == + (checkRedeemerConfig <$> AssocMap.lookup userConfigId userConfigs <*> AssocMap.lookup userConfigId newUserConfigs)) + -- TODO check that other fields are not changed + checkRedeemerConfig :: UserConfig -> UserConfig -> Bool + checkRedeemerConfig oldState newState = + let debtChange = fromMaybe 0 $ (-) <$> ucDebt oldState <*> ucDebt newState + reimbursementAmout = assetClassValueOf actorSpentValue reserveId - assetClassValueOf actorRemainderValue reserveId + in debtChange == reimbursementAmout + +validateRepay aave (ReservesDatum stateToken reserves) ctx userConfigId = + traceIfFalse "validateRepay: Reserves Datum change is not valid" $ checkPositiveReservesTransformation stateToken reserves ctx userConfigId + +validateRepay _ _ _ _ = trace "validateRepay: Lending Pool Datum management is not allowed" False checkNegativeFundsTransformation :: ScriptContext -> UserConfigId -> Bool checkNegativeFundsTransformation ctx (reserveId, actor) = maybe False checkFundsState $ (,) <$> scriptSpentValue <*> scriptRemainderValue @@ -325,6 +327,39 @@ checkNegativeReservesTransformation stateToken reserves ctx (reserveId, _) = checkReserveState (value, oldState, newState) = assetClassValueOf value reserveId == rAmount newState +checkPositiveReservesTransformation :: AssetClass + -> AssocMap.Map AssetClass Reserve + -> ScriptContext + -> UserConfigId + -> Bool +checkPositiveReservesTransformation stateToken reserves ctx (reserveId, _) = maybe False checkreserves reservesOutputDatum + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + + reservesOutputDatumHash = + findDatumHashByValue (assetClassValue stateToken 1) scriptOutputs + reservesOutputDatum :: + Maybe (AssetClass, AssocMap.Map ReserveId Reserve) + reservesOutputDatum = + reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves + + investmentDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo + investmentValue = investmentDatumHash >>= (`findValueByDatumHash` scriptOutputs) + + checkreserves :: (AssetClass, AssocMap.Map ReserveId Reserve) -> Bool + checkreserves (newStateToken, newReserves) = + newStateToken == stateToken && + maybe + False + checkReserveState + ((,,) <$> investmentValue <*> AssocMap.lookup reserveId reserves <*> AssocMap.lookup reserveId newReserves) + -- TODO check that other fields are not changed + checkReserveState :: (Value, Reserve, Reserve) -> Bool + checkReserveState (value, oldState, newState) = + assetClassValueOf value reserveId == (rAmount newState - rAmount oldState) + aaveProtocolName :: TokenName aaveProtocolName = "Aave" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index c2ee53a53..80dd49c29 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -267,9 +267,9 @@ repay aave RepayParams {..} = do Nothing -> throwError "User does not have any debt." Just userConfig -> - State.updateUserConfig aave Core.RepayRedeemer userConfigId $ userConfig { ucDebt = subtract rpAmount <$> ucDebt userConfig } + State.updateUserConfig aave (Core.RepayRedeemer userConfigId) userConfigId $ userConfig { ucDebt = subtract rpAmount <$> ucDebt userConfig } - reservesTx <- State.updateReserve aave Core.RepayRedeemer rpAsset (reserve { rAmount = rAmount reserve + rpAmount }) + reservesTx <- State.updateReserve aave (Core.RepayRedeemer userConfigId) rpAsset (reserve { rAmount = rAmount reserve + rpAmount }) ledgerTx <- TxUtils.submitTxPair $ reimbursementTx <> reservesTx <> userConfigsTx _ <- awaitTxConfirmed $ txId ledgerTx From 711431403c1903a18910d41fea84745403ce3ca7 Mon Sep 17 00:00:00 2001 From: stanislav-az Date: Tue, 8 Jun 2021 00:03:07 +0700 Subject: [PATCH 074/169] check amounts are positive --- .../src/Plutus/Contracts/AToken.hs | 1 + .../lending-pool/src/Plutus/Contracts/Core.hs | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 1bf1181da..276d5ff9e 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -51,6 +51,7 @@ import Prelude (Semigroup (..)) import qualified Prelude {-# INLINABLE validator #-} +-- TODO Check amounts are > 0 validator :: AssetClass -> TokenName -> ScriptContext -> Bool validator underlyingAsset aTokenName ctx = hasEnoughUnderlyingAsset where diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 247afc66a..ee145903d 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -131,7 +131,6 @@ instance Scripts.ScriptType AaveScript where -- Main validator -- Each state field must have one or more associated actions(Redeemer types), -- produced on state update, which are then validated here --- TODO Check amounts are > 0 makeAaveValidator :: Aave -> AaveDatum -> AaveRedeemer @@ -228,8 +227,8 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( checkRedeemerConfig oldState newState = let oldDebt = fromMaybe 0 $ oldState >>= ucDebt debtAmount = maybe 0 (flip (-) oldDebt) (ucDebt newState) - disbursementAmout = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId - in debtAmount == disbursementAmout + disbursementAmount = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId + in debtAmount == disbursementAmount && debtAmount > 0 && disbursementAmount > 0 validateBorrow aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateBorrow: Reserves Datum change is not valid" $ checkNegativeReservesTransformation stateToken reserves ctx userConfigId @@ -268,8 +267,8 @@ validateRepay aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(r checkRedeemerConfig :: UserConfig -> UserConfig -> Bool checkRedeemerConfig oldState newState = let debtChange = fromMaybe 0 $ (-) <$> ucDebt oldState <*> ucDebt newState - reimbursementAmout = assetClassValueOf actorSpentValue reserveId - assetClassValueOf actorRemainderValue reserveId - in debtChange == reimbursementAmout + reimbursementAmount = assetClassValueOf actorSpentValue reserveId - assetClassValueOf actorRemainderValue reserveId + in debtChange == reimbursementAmount && debtChange > 0 && reimbursementAmount > 0 validateRepay aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateRepay: Reserves Datum change is not valid" $ checkPositiveReservesTransformation stateToken reserves ctx userConfigId @@ -291,7 +290,8 @@ checkNegativeFundsTransformation ctx (reserveId, actor) = maybe False checkFunds checkFundsState :: (Value, Value) -> Bool checkFundsState (oldFunds, newFunds) = let paidAmout = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId - in assetClassValueOf oldFunds reserveId - assetClassValueOf newFunds reserveId == paidAmout + fundsChange = assetClassValueOf oldFunds reserveId - assetClassValueOf newFunds reserveId + in fundsChange == paidAmout && fundsChange > 0 && paidAmout > 0 checkNegativeReservesTransformation :: AssetClass -> AssocMap.Map AssetClass Reserve @@ -325,7 +325,8 @@ checkNegativeReservesTransformation stateToken reserves ctx (reserveId, _) = -- TODO check that other fields are not changed checkReserveState :: (Value, Reserve, Reserve) -> Bool checkReserveState (value, oldState, newState) = - assetClassValueOf value reserveId == rAmount newState + let fundsAmount = rAmount newState + in assetClassValueOf value reserveId == fundsAmount && fundsAmount >= 0 checkPositiveReservesTransformation :: AssetClass -> AssocMap.Map AssetClass Reserve @@ -358,7 +359,8 @@ checkPositiveReservesTransformation stateToken reserves ctx (reserveId, _) = may -- TODO check that other fields are not changed checkReserveState :: (Value, Reserve, Reserve) -> Bool checkReserveState (value, oldState, newState) = - assetClassValueOf value reserveId == (rAmount newState - rAmount oldState) + let fundsChange = rAmount newState - rAmount oldState + in assetClassValueOf value reserveId == fundsChange && fundsChange > 0 aaveProtocolName :: TokenName aaveProtocolName = "Aave" From 3566ceb2b2f12b9a8fb78c11d7da4234cded54b5 Mon Sep 17 00:00:00 2001 From: stanislav-az Date: Tue, 8 Jun 2021 00:34:52 +0700 Subject: [PATCH 075/169] check some state fields are not changed --- .../lending-pool/src/Plutus/Contracts/Core.hs | 38 +++++++++++-------- .../src/Plutus/Contracts/Endpoints.hs | 1 - 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index ee145903d..bc5846aaa 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -65,7 +65,6 @@ data Reserve = Reserve { rCurrency :: ReserveId, rAToken :: AssetClass, rAmount :: Integer, - rDebtToken :: AssetClass, rLiquidityIndex :: Integer, rCurrentStableBorrowRate :: Rational } @@ -171,14 +170,18 @@ validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId isValidUserConfigsTransformation :: Bool isValidUserConfigsTransformation = maybe False checkUserConfigs userConfigsOutputDatum - checkUserConfigs :: - (AssetClass, AssocMap.Map UserConfigId UserConfig) -> Bool + checkUserConfigs :: (AssetClass, AssocMap.Map UserConfigId UserConfig) -> Bool checkUserConfigs (newStateToken, newUserConfigs) = newStateToken == stateToken && - maybe False checkRedeemerConfig (AssocMap.lookup userConfigId newUserConfigs) - -- TODO check that other fields are not changed - checkRedeemerConfig :: UserConfig -> Bool - checkRedeemerConfig UserConfig{..} = ucUsingAsCollateral + maybe + False + (checkRedeemerConfig (AssocMap.lookup userConfigId userConfigs)) + (AssocMap.lookup userConfigId newUserConfigs) + + checkRedeemerConfig :: Maybe UserConfig -> UserConfig -> Bool + checkRedeemerConfig oldState newState = + ucUsingAsCollateral newState && + maybe True ((ucDebt newState ==) . ucDebt) oldState validateDeposit aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateDeposit: Reserves Datum change is not valid" $ checkPositiveReservesTransformation stateToken reserves ctx userConfigId @@ -222,13 +225,13 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( checkUserConfigs (newStateToken, newUserConfigs) = newStateToken == stateToken && maybe False (checkRedeemerConfig $ AssocMap.lookup userConfigId userConfigs) (AssocMap.lookup userConfigId newUserConfigs) - -- TODO check that other fields are not changed checkRedeemerConfig :: Maybe UserConfig -> UserConfig -> Bool checkRedeemerConfig oldState newState = let oldDebt = fromMaybe 0 $ oldState >>= ucDebt debtAmount = maybe 0 (flip (-) oldDebt) (ucDebt newState) disbursementAmount = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId - in debtAmount == disbursementAmount && debtAmount > 0 && disbursementAmount > 0 + in debtAmount == disbursementAmount && debtAmount > 0 && disbursementAmount > 0 && + maybe (not $ ucUsingAsCollateral newState) ((ucUsingAsCollateral newState ==) . ucUsingAsCollateral) oldState validateBorrow aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateBorrow: Reserves Datum change is not valid" $ checkNegativeReservesTransformation stateToken reserves ctx userConfigId @@ -263,12 +266,12 @@ validateRepay aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(r newStateToken == stateToken && (Just True == (checkRedeemerConfig <$> AssocMap.lookup userConfigId userConfigs <*> AssocMap.lookup userConfigId newUserConfigs)) - -- TODO check that other fields are not changed checkRedeemerConfig :: UserConfig -> UserConfig -> Bool checkRedeemerConfig oldState newState = let debtChange = fromMaybe 0 $ (-) <$> ucDebt oldState <*> ucDebt newState reimbursementAmount = assetClassValueOf actorSpentValue reserveId - assetClassValueOf actorRemainderValue reserveId - in debtChange == reimbursementAmount && debtChange > 0 && reimbursementAmount > 0 + in debtChange == reimbursementAmount && debtChange > 0 && reimbursementAmount > 0 && + ucUsingAsCollateral oldState == ucUsingAsCollateral newState validateRepay aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateRepay: Reserves Datum change is not valid" $ checkPositiveReservesTransformation stateToken reserves ctx userConfigId @@ -322,11 +325,10 @@ checkNegativeReservesTransformation stateToken reserves ctx (reserveId, _) = False checkReserveState ((,,) <$> remainderValue <*> AssocMap.lookup reserveId reserves <*> AssocMap.lookup reserveId newReserves) - -- TODO check that other fields are not changed checkReserveState :: (Value, Reserve, Reserve) -> Bool checkReserveState (value, oldState, newState) = let fundsAmount = rAmount newState - in assetClassValueOf value reserveId == fundsAmount && fundsAmount >= 0 + in assetClassValueOf value reserveId == fundsAmount && fundsAmount >= 0 && checkReservesConsistency oldState newState checkPositiveReservesTransformation :: AssetClass -> AssocMap.Map AssetClass Reserve @@ -356,11 +358,17 @@ checkPositiveReservesTransformation stateToken reserves ctx (reserveId, _) = may False checkReserveState ((,,) <$> investmentValue <*> AssocMap.lookup reserveId reserves <*> AssocMap.lookup reserveId newReserves) - -- TODO check that other fields are not changed checkReserveState :: (Value, Reserve, Reserve) -> Bool checkReserveState (value, oldState, newState) = let fundsChange = rAmount newState - rAmount oldState - in assetClassValueOf value reserveId == fundsChange && fundsChange > 0 + in assetClassValueOf value reserveId == fundsChange && fundsChange > 0 && checkReservesConsistency oldState newState + +checkReservesConsistency :: Reserve -> Reserve -> Bool +checkReservesConsistency oldState newState = + rCurrency oldState == rCurrency newState && + rAToken oldState == rAToken newState && + rLiquidityIndex oldState == rLiquidityIndex newState && + rCurrentStableBorrowRate oldState == rCurrentStableBorrowRate newState aaveProtocolName :: TokenName aaveProtocolName = "Aave" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 80dd49c29..11c576bd9 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -71,7 +71,6 @@ createReserve CreateParams {..} = { rCurrency = cpAsset, rAmount = 0, rAToken = AToken.makeAToken cpAsset, - rDebtToken = cpAsset, rLiquidityIndex = 1, rCurrentStableBorrowRate = 11 % 10 -- TODO configure borrow rate when lending core will be ready } From 59313b63aae403bd30c416f9a39e8758e470e985 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 8 Jun 2021 12:34:09 +0700 Subject: [PATCH 076/169] fix state forging policy --- .../src/Ext/Plutus/Ledger/Contexts.hs | 13 +++++-- .../src/Plutus/Contracts/State.hs | 4 +- .../lending-pool/src/Plutus/State/Update.hs | 39 ++++++++++--------- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs index ea7e2b417..7c109af29 100644 --- a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs +++ b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs @@ -9,9 +9,9 @@ import Ledger (Address (Address), PubKeyHash, TxInInfo (txInInfoResolved), TxInfo (txInfoInputs), - TxOut (TxOut, txOutAddress, txOutValue), - Value, findDatum) -import Plutus.V1.Ledger.Credential (Credential (PubKeyCredential)) + TxOut (TxOut, txOutAddress, txOutDatumHash, txOutValue), + ValidatorHash, Value, findDatum) +import Plutus.V1.Ledger.Credential (Credential (PubKeyCredential, ScriptCredential)) import qualified PlutusTx import PlutusTx.Prelude (Eq ((==)), Maybe (..), Monad ((>>=)), find, fst, @@ -45,3 +45,10 @@ valueSpentFrom txInfo pk = | pk == pk' = Just txOutValue flt _ = Nothing in mconcat $ mapMaybe flt (txInInfoResolved <$> txInfoInputs txInfo) + +{-# INLINABLE scriptInputsAt #-} +scriptInputsAt :: ValidatorHash -> TxInfo -> [(DatumHash, Value)] +scriptInputsAt h p = + let flt TxOut{txOutDatumHash=Just ds, txOutAddress=Address (ScriptCredential s) _, txOutValue} | s == h = Just (ds, txOutValue) + flt _ = Nothing + in mapMaybe flt (txInInfoResolved <$> txInfoInputs p) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 7302b0072..04948c004 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -60,8 +60,8 @@ findAaveOwnerToken :: HasBlockchainActions s => Aave -> Contract w s Text (Outpu findAaveOwnerToken aave@Aave{..} = findOutputBy aave aaveProtocolInst (^? Core._LendingPoolDatum) reserveStateToken, userStateToken :: Aave -> AssetClass -reserveStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveReserve" -userStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveUser" +reserveStateToken aave = Update.makeStateToken (Core.aaveHash aave) (aaveProtocolInst aave) "aaveReserve" +userStateToken aave = Update.makeStateToken (Core.aaveHash aave) (aaveProtocolInst aave) "aaveUser" findAaveReserves :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map ReserveId Reserve)) findAaveReserves aave = findOutputBy aave (reserveStateToken aave) (^? Core._ReservesDatum . _2) diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index 9d0082434..b3f2d714c 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -41,33 +41,36 @@ import PlutusTx.Prelude hiding (Semigroup (..), unless) import Prelude (Semigroup (..)) import qualified Prelude +import Ext.Plutus.Ledger.Contexts (scriptInputsAt) type OwnerToken = AssetClass --- State token can be only be forged when there is an input containing an owner token --- TODO: add rules: --- 1. output contains same owner token with same owner (aave script) --- 2. output contains the forged state token with same owner (aave script) +-- State token can be only be forged when there is an input and outpu containing an owner token belonging to a script {-# INLINABLE validateStateForging #-} -validateStateForging :: OwnerToken -> TokenName -> ScriptContext -> Bool -validateStateForging ownerToken tokenName ctx = - any hasOwnerToken inputValues || traceError "State forging without OwnerToken input" +validateStateForging :: ValidatorHash -> OwnerToken -> TokenName -> ScriptContext -> Bool +validateStateForging ownerScript ownerToken tokenName ctx = traceIfFalse "State forging not authorized" $ + hasOneOwnerToken outputValues && hasOneOwnerToken inputValues && hasOneStateToken forgedValue && hasOneStateToken (mconcat outputValues) where - inputs = txInfoInputs (scriptContextTxInfo ctx) - inputValues = txOutValue . txInInfoResolved <$> inputs - hasOwnerToken value = assetClassValueOf value ownerToken == 1 + txInfo = scriptContextTxInfo ctx + outputValues = snd <$> scriptOutputsAt ownerScript txInfo + inputValues = snd <$> scriptInputsAt ownerScript txInfo + forgedValue = txInfoForge txInfo + stateToken = assetClass (ownCurrencySymbol ctx) tokenName + hasOneOwnerToken values = assetClassValueOf (mconcat values) ownerToken == 1 + hasOneStateToken value = assetClassValueOf value stateToken == 1 -makeStatePolicy :: OwnerToken -> TokenName -> MonetaryPolicy -makeStatePolicy ownerToken tokenName = mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| \ot tn -> Scripts.wrapMonetaryPolicy $ validateStateForging ot tn||]) +makeStatePolicy :: ValidatorHash -> OwnerToken -> TokenName -> MonetaryPolicy +makeStatePolicy ownerScript ownerToken tokenName = mkMonetaryPolicyScript $ + $$(PlutusTx.compile [|| \os ot tn -> Scripts.wrapMonetaryPolicy $ validateStateForging os ot tn||]) + `PlutusTx.applyCode` PlutusTx.liftCode ownerScript `PlutusTx.applyCode` PlutusTx.liftCode ownerToken `PlutusTx.applyCode` PlutusTx.liftCode tokenName -makeStateCurrency :: OwnerToken -> TokenName -> CurrencySymbol -makeStateCurrency ownerToken tokenName = scriptCurrencySymbol $ makeStatePolicy ownerToken tokenName +makeStateCurrency :: ValidatorHash -> OwnerToken -> TokenName -> CurrencySymbol +makeStateCurrency ownerScript ownerToken tokenName = scriptCurrencySymbol $ makeStatePolicy ownerScript ownerToken tokenName -makeStateToken :: OwnerToken -> TokenName -> AssetClass -makeStateToken ownerToken tokenName = assetClass (makeStateCurrency ownerToken tokenName) tokenName +makeStateToken :: ValidatorHash -> OwnerToken -> TokenName -> AssetClass +makeStateToken ownerScript ownerToken tokenName = assetClass (makeStateCurrency ownerScript ownerToken tokenName) tokenName data PutStateHandle scriptType = PutStateHandle { script :: Scripts.ScriptInstance scriptType, @@ -91,7 +94,7 @@ putState PutStateHandle {..} StateHandle{..} newState = do pkh <- pubKeyHash <$> ownPubKey let (_, stateTokenName) = unAssetClass stateToken pure $ - TxUtils.mustForgeValue (makeStatePolicy ownerToken stateTokenName) (assetClassValue stateToken 1) + TxUtils.mustForgeValue (makeStatePolicy (Scripts.scriptHash script) ownerToken stateTokenName) (assetClassValue stateToken 1) <> TxUtils.mustPayToScript script pkh (toDatum newState) (assetClassValue stateToken 1) <> TxUtils.mustRoundTripToScript script From 9485293a62e44f352b1f88e58702d8a3c017c956 Mon Sep 17 00:00:00 2001 From: megakaban Date: Tue, 8 Jun 2021 15:51:40 +0700 Subject: [PATCH 077/169] Fix purescript generation --- MetaLamp/lending-pool/.gitignore | 1 + MetaLamp/lending-pool/client/README.md | 18 +++++++++- .../client/src/Components/App.purs | 2 +- .../lending-pool/generate-purs/AaveTypes.hs | 22 ++++++++++--- MetaLamp/lending-pool/generate-purs/Main.hs | 3 +- MetaLamp/lending-pool/plutus-starter.cabal | 1 + .../lending-pool/src/Plutus/Contracts/Core.hs | 14 +++----- .../src/Plutus/Contracts/Endpoints.hs | 13 ++++---- .../src/Plutus/Contracts/State.hs | 33 +++++++++---------- 9 files changed, 66 insertions(+), 41 deletions(-) diff --git a/MetaLamp/lending-pool/.gitignore b/MetaLamp/lending-pool/.gitignore index 4c9e245b5..d30d08b07 100644 --- a/MetaLamp/lending-pool/.gitignore +++ b/MetaLamp/lending-pool/.gitignore @@ -21,3 +21,4 @@ cabal.project.local cabal.project.local~ .HTF/ .ghc.environment.* +.psc-ide-port \ No newline at end of file diff --git a/MetaLamp/lending-pool/client/README.md b/MetaLamp/lending-pool/client/README.md index c4f2eea83..fa54d2c5e 100644 --- a/MetaLamp/lending-pool/client/README.md +++ b/MetaLamp/lending-pool/client/README.md @@ -1 +1,17 @@ -# lending pool client \ No newline at end of file +# lending pool client + +## Running the project + +``` +npm install +``` + +``` +npm start +``` + +CORS protection needs to be disabled. You can use this script to launch chrome: + +``` +npm run start-chrome +``` diff --git a/MetaLamp/lending-pool/client/src/Components/App.purs b/MetaLamp/lending-pool/client/src/Components/App.purs index da2bd511c..a3c89664f 100644 --- a/MetaLamp/lending-pool/client/src/Components/App.purs +++ b/MetaLamp/lending-pool/client/src/Components/App.purs @@ -5,7 +5,7 @@ import Prelude import Business.Aave as Aave import Capability.Contract (class Contract, ContractId(..)) import Capability.Delay (class Delay) -import Capability.LogMessages (class LogMessages, logError) +import Capability.LogMessages (class LogMessages, logError, logInfo) import Components.AmountForm as AmountForm import Control.Monad.Except (lift, runExceptT, throwError) import Data.Array (mapWithIndex) diff --git a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs index 8df82ae5d..6349f8414 100644 --- a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs +++ b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs @@ -14,24 +14,36 @@ module AaveTypes where import Language.PureScript.Bridge (BridgePart, Language (Haskell), SumType, TypeInfo (TypeInfo), buildBridge, equal, genericShow, haskType, mkSumType, order, typeModule, typeName, - writePSTypesWith, (^==)) + writePSTypesWith, (^==), PSType, psTypeParameters) import Data.Proxy (Proxy (Proxy)) import qualified Plutus.Contracts.Core as Aave import qualified Plutus.Contracts.Endpoints as Aave import Plutus.PAB.Simulation (AaveContracts(..)) -import PlutusTx.Ratio (Ratio) import Language.PureScript.Bridge.TypeParameters (A) +import Control.Monad.Reader (MonadReader) +import Language.PureScript.Bridge.Builder (BridgeData) +import qualified PSGenerator.Common +import Plutus.V1.Ledger.Value (AssetClass) + +ratioBridge :: BridgePart +ratioBridge = do + typeName ^== "Ratio" + typeModule ^== "PlutusTx.Ratio" + psRatio + +psRatio :: MonadReader BridgeData m => m PSType +psRatio = expand <$> psTypeParameters + where + expand [x] = TypeInfo "web-common" "Data.Json.JsonTuple" "JsonTuple" [x, x] aaveTypes :: [SumType 'Haskell] aaveTypes = [ (equal <*> (genericShow <*> mkSumType)) (Proxy @AaveContracts) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.Aave) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.CreateParams) + , (order <*> (equal <*> (genericShow <*> mkSumType))) (Proxy @AssetClass) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.UserContractState) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.ReserveId) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.Reserve) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.UserConfigId) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.UserConfig) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @(Ratio A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.DepositParams) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.WithdrawParams) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.BorrowParams) diff --git a/MetaLamp/lending-pool/generate-purs/Main.hs b/MetaLamp/lending-pool/generate-purs/Main.hs index 2627c835c..d60ddcc44 100644 --- a/MetaLamp/lending-pool/generate-purs/Main.hs +++ b/MetaLamp/lending-pool/generate-purs/Main.hs @@ -64,7 +64,7 @@ import Servant.PureScript (HasBridge, Settings import System.FilePath (()) import Wallet.Effects (AddressChangeRequest (..), AddressChangeResponse (..)) import Wallet.Emulator.Wallet (Wallet (..)) -import AaveTypes (aaveTypes) +import AaveTypes (aaveTypes, ratioBridge) import System.Directory (removeDirectoryRecursive, doesDirectoryExist) import Plutus.V1.Ledger.Value (AssetClass, TokenName (..)) import Control.Monad (when) @@ -77,6 +77,7 @@ myBridge = PSGenerator.Common.ledgerBridge <|> PSGenerator.Common.servantBridge <|> PSGenerator.Common.miscBridge <|> + ratioBridge <|> metadataBridge <|> defaultBridge diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 3a236579a..056e1c9cf 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -84,6 +84,7 @@ executable generate-purs freer-extras, lens, text, + mtl, -- Plutus: plutus-ledger-api, purescript-bridge, diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index a0d9b98a7..b4b16a120 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -45,12 +45,10 @@ newtype Aave = Aave PlutusTx.makeLift ''Aave -type ReserveId = AssetClass - deriving anyclass instance ToSchema Rational data Reserve = Reserve - { rCurrency :: ReserveId, + { rCurrency :: AssetClass, -- reserve id rAToken :: AssetClass, rAmount :: Integer, rDebtToken :: AssetClass, @@ -63,8 +61,6 @@ data Reserve = Reserve PlutusTx.unstableMakeIsData ''Reserve PlutusTx.makeLift ''Reserve -type UserConfigId = (ReserveId, PubKeyHash) - data UserConfig = UserConfig { ucUsingAsCollateral :: Bool, @@ -77,9 +73,9 @@ PlutusTx.unstableMakeIsData ''UserConfig PlutusTx.makeLift ''UserConfig data AaveRedeemer = - CreateReservesRedeemer (AssocMap.Map ReserveId Reserve) + CreateReservesRedeemer (AssocMap.Map AssetClass Reserve) | UpdateReservesRedeemer - | CreateUserConfigsRedeemer (AssocMap.Map UserConfigId UserConfig) + | CreateUserConfigsRedeemer (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) | UpdateUserConfigsRedeemer | WithdrawRedeemer | BorrowRedeemer @@ -91,8 +87,8 @@ PlutusTx.makeLift ''AaveRedeemer data AaveDatum = LendingPoolDatum - | ReservesDatum (AssocMap.Map ReserveId Reserve) - | UserConfigsDatum (AssocMap.Map UserConfigId UserConfig) + | ReservesDatum (AssocMap.Map AssetClass Reserve) + | UserConfigsDatum (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) | DepositDatum | BorrowDatum | RepayDatum diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index e56330274..47fd5e9b6 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -37,9 +37,8 @@ import Plutus.Contract hiding (when) import qualified Plutus.Contracts.AToken as AToken import Plutus.Contracts.Core (Aave, AaveDatum (..), AaveRedeemer (..), - Reserve (..), ReserveId, - UserConfig (..), - UserConfigId) + Reserve (..), + UserConfig (..)) import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken @@ -106,10 +105,10 @@ type AaveOwnerSchema = BlockchainActions .\/ Endpoint "start" () -reserves :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map ReserveId Reserve) +reserves :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map AssetClass Reserve) reserves aave = ovValue <$> State.findAaveReserves aave -users :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map UserConfigId UserConfig) +users :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) users aave = ovValue <$> State.findAaveUserConfigs aave valueAt :: HasBlockchainActions s => Address -> Contract w s Text Value @@ -289,8 +288,8 @@ data UserContractState = | Repaid | FundsAt Value | PoolFunds Value - | Reserves (AssocMap.Map ReserveId Reserve) - | Users (AssocMap.Map UserConfigId UserConfig) + | Reserves (AssocMap.Map AssetClass Reserve) + | Users (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) | GetPubKey PubKeyHash deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 6d4542fc5..6d5b17f09 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -29,8 +29,7 @@ import Plutus.Contract hiding (when) import Plutus.Contracts.Core (Aave (..), AaveDatum (..), AaveRedeemer (..), AaveScript, Reserve (..), - ReserveId, UserConfig (..), - UserConfigId) + UserConfig (..)) import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken @@ -65,26 +64,26 @@ reserveStateToken, userStateToken :: Aave -> AssetClass reserveStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveReserve" userStateToken aave = Update.makeStateToken (aaveProtocolInst aave) "aaveUser" -findAaveReserves :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map ReserveId Reserve)) +findAaveReserves :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map AssetClass Reserve)) findAaveReserves aave = findOutputBy aave (reserveStateToken aave) pickReserves -pickReserves :: AaveDatum -> Maybe (AssocMap.Map ReserveId Reserve) +pickReserves :: AaveDatum -> Maybe (AssocMap.Map AssetClass Reserve) pickReserves (Core.ReservesDatum r) = Just r pickReserves _ = Nothing -findAaveReserve :: HasBlockchainActions s => Aave -> ReserveId -> Contract w s Text Reserve +findAaveReserve :: HasBlockchainActions s => Aave -> AssetClass -> Contract w s Text Reserve findAaveReserve aave reserveId = do reserves <- ovValue <$> findAaveReserves aave maybe (throwError "Reserve not found") pure $ AssocMap.lookup reserveId reserves -findAaveUserConfigs :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map UserConfigId UserConfig)) +findAaveUserConfigs :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map (AssetClass, PubKeyHash) UserConfig)) findAaveUserConfigs aave = findOutputBy aave (userStateToken aave) pickUserConfig -pickUserConfig :: AaveDatum -> Maybe (AssocMap.Map UserConfigId UserConfig) +pickUserConfig :: AaveDatum -> Maybe (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) pickUserConfig (Core.UserConfigsDatum userConfig) = Just userConfig pickUserConfig _ = Nothing -findAaveUserConfig :: HasBlockchainActions s => Aave -> UserConfigId -> Contract w s Text UserConfig +findAaveUserConfig :: HasBlockchainActions s => Aave -> (AssetClass, PubKeyHash) -> Contract w s Text UserConfig findAaveUserConfig aave userConfigId = do configs <- ovValue <$> findAaveUserConfigs aave maybe (throwError "UserConfig not found") pure $ AssocMap.lookup userConfigId configs @@ -100,7 +99,7 @@ putState aave stateHandle newState = do updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> OutputValue a -> Contract w s Text () updateState aave = Update.updateState (Core.aaveInstance aave) -makeReserveHandle :: Aave -> (AssocMap.Map ReserveId Reserve -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map ReserveId Reserve) +makeReserveHandle :: Aave -> (AssocMap.Map AssetClass Reserve -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map AssetClass Reserve) makeReserveHandle aave toRedeemer = StateHandle { stateToken = reserveStateToken aave, @@ -108,20 +107,20 @@ makeReserveHandle aave toRedeemer = toRedeemer = toRedeemer } -putReserves :: (HasBlockchainActions s) => Aave -> AssocMap.Map ReserveId Reserve -> Contract w s Text () +putReserves :: (HasBlockchainActions s) => Aave -> AssocMap.Map AssetClass Reserve -> Contract w s Text () putReserves aave = putState aave $ makeReserveHandle aave Core.CreateReservesRedeemer -updateReserves :: (HasBlockchainActions s) => Aave -> OutputValue (AssocMap.Map ReserveId Reserve) -> Contract w s Text () +updateReserves :: (HasBlockchainActions s) => Aave -> OutputValue (AssocMap.Map AssetClass Reserve) -> Contract w s Text () updateReserves aave = updateState aave $ makeReserveHandle aave (const Core.UpdateReservesRedeemer) -updateReserve :: (HasBlockchainActions s) => Aave -> ReserveId -> Reserve -> Contract w s Text () +updateReserve :: (HasBlockchainActions s) => Aave -> AssetClass -> Reserve -> Contract w s Text () updateReserve aave reserveId reserve = do reservesOutput <- findAaveReserves aave _ <- maybe (throwError "Update failed: reserve not found") pure $ AssocMap.lookup reserveId (ovValue reservesOutput) updateReserves aave $ Prelude.fmap (AssocMap.insert reserveId reserve) reservesOutput -makeUserHandle :: Aave -> (AssocMap.Map UserConfigId UserConfig -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map UserConfigId UserConfig) +makeUserHandle :: Aave -> (AssocMap.Map (AssetClass, PubKeyHash) UserConfig -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) makeUserHandle aave toRedeemer = StateHandle { stateToken = userStateToken aave, @@ -129,20 +128,20 @@ makeUserHandle aave toRedeemer = toRedeemer = toRedeemer } -putUserConfigs :: (HasBlockchainActions s) => Aave -> AssocMap.Map UserConfigId UserConfig -> Contract w s Text () +putUserConfigs :: (HasBlockchainActions s) => Aave -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig -> Contract w s Text () putUserConfigs aave = putState aave $ makeUserHandle aave Core.CreateUserConfigsRedeemer -updateUserConfigs :: (HasBlockchainActions s) => Aave -> OutputValue (AssocMap.Map UserConfigId UserConfig) -> Contract w s Text () +updateUserConfigs :: (HasBlockchainActions s) => Aave -> OutputValue (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -> Contract w s Text () updateUserConfigs aave = updateState aave $ makeUserHandle aave (const Core.UpdateUserConfigsRedeemer) -addUserConfig :: (HasBlockchainActions s) => Aave -> UserConfigId -> UserConfig -> Contract w s Text () +addUserConfig :: (HasBlockchainActions s) => Aave -> (AssetClass, PubKeyHash) -> UserConfig -> Contract w s Text () addUserConfig aave userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (pure ()) (const $ throwError "Add user config failed: config exists") $ AssocMap.lookup userConfigId (ovValue configsOutput) updateUserConfigs aave $ Prelude.fmap (AssocMap.insert userConfigId userConfig) configsOutput -updateUserConfig :: (HasBlockchainActions s) => Aave -> UserConfigId -> UserConfig -> Contract w s Text () +updateUserConfig :: (HasBlockchainActions s) => Aave -> (AssetClass, PubKeyHash) -> UserConfig -> Contract w s Text () updateUserConfig aave userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (throwError "Update failed: user config not found") pure $ From 2de99318cdc0368294f36d1d9176bc497f0f28fa Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 8 Jun 2021 16:02:45 +0700 Subject: [PATCH 078/169] fix aave tokens validator --- .../src/Plutus/Contracts/AToken.hs | 37 ++++++++++--------- .../src/Plutus/Contracts/Endpoints.hs | 8 ++-- .../lending-pool/src/Plutus/State/Update.hs | 6 ++- 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 276d5ff9e..996659d35 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -49,31 +49,34 @@ import PlutusTx.Prelude hiding (Semigroup (..)) import qualified PlutusTx.Semigroup as Semigroup import Prelude (Semigroup (..)) import qualified Prelude +import Ext.Plutus.Ledger.Contexts (scriptInputsAt) {-# INLINABLE validator #-} --- TODO Check amounts are > 0 -validator :: AssetClass -> TokenName -> ScriptContext -> Bool -validator underlyingAsset aTokenName ctx = hasEnoughUnderlyingAsset +validator :: ValidatorHash -> AssetClass -> TokenName -> ScriptContext -> Bool +validator aaveScript underlyingAsset aTokenName ctx = + traceIfFalse "Aave tokens mint forbidden" $ amountMinted /= 0 && amountScriptAsset == amountMinted where txInfo :: TxInfo txInfo = scriptContextTxInfo ctx - aTokenCurrency :: AssetClass aTokenCurrency = assetClass (ownCurrencySymbol ctx) aTokenName + amountAsset :: Value -> Integer + amountAsset = flip assetClassValueOf underlyingAsset amountMinted :: Integer amountMinted = assetClassValueOf (txInfoForge txInfo) aTokenCurrency - -- TODO how to check if value spent comes from pub key when aTokens are minted and comes from aave script when aTokens are burned? - amountAsset :: Integer - amountAsset = assetClassValueOf (valueSpent txInfo) underlyingAsset - - hasEnoughUnderlyingAsset :: Bool - hasEnoughUnderlyingAsset = amountMinted <= amountAsset + amountScriptAsset :: Integer + amountScriptAsset = + let outputValue = foldMap snd $ scriptOutputsAt aaveScript txInfo + inputValue = foldMap snd $ scriptInputsAt aaveScript txInfo + in amountAsset outputValue - amountAsset inputValue -makeLiquidityPolicy :: AssetClass -> MonetaryPolicy -makeLiquidityPolicy asset = Scripts.mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| \a t -> Scripts.wrapMonetaryPolicy $ validator a t||]) +makeLiquidityPolicy :: ValidatorHash -> AssetClass -> MonetaryPolicy +makeLiquidityPolicy aaveScript asset = Scripts.mkMonetaryPolicyScript $ + $$(PlutusTx.compile [|| \s a t -> Scripts.wrapMonetaryPolicy $ validator s a t||]) + `PlutusTx.applyCode` + PlutusTx.liftCode aaveScript `PlutusTx.applyCode` PlutusTx.liftCode asset `PlutusTx.applyCode` @@ -81,8 +84,8 @@ makeLiquidityPolicy asset = Scripts.mkMonetaryPolicyScript $ where aToken = aTokenName asset -makeAToken :: AssetClass -> AssetClass -makeAToken asset = assetClass (scriptCurrencySymbol . makeLiquidityPolicy $ asset) (aTokenName asset) +makeAToken :: ValidatorHash -> AssetClass -> AssetClass +makeAToken aaveScript asset = assetClass (scriptCurrencySymbol $ makeLiquidityPolicy aaveScript asset) (aTokenName asset) {-# INLINABLE aTokenName #-} aTokenName :: AssetClass -> TokenName @@ -91,7 +94,7 @@ aTokenName asset = TokenName $ "a" Semigroup.<> case asset of forgeATokensFrom :: forall w s. (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text (TxUtils.TxPair AaveScript) forgeATokensFrom aave reserve pkh amount = do - let policy = makeLiquidityPolicy (rCurrency reserve) + let policy = makeLiquidityPolicy (Core.aaveHash aave) (rCurrency reserve) aTokenAmount = amount -- / rLiquidityIndex reserve -- TODO: how should we divide? forgeValue = assetClassValue (rAToken reserve) aTokenAmount let payment = assetClassValue (rCurrency reserve) amount @@ -110,7 +113,7 @@ burnATokensFrom aave reserve pkh amount = do let balance = mconcat . fmap (txOutValue . txOutTxOut) . map snd . Map.toList $ utxos aTokenAmount = amount remainder = assetClassValueOf balance asset - aTokenAmount - policy = makeLiquidityPolicy asset + policy = makeLiquidityPolicy (Core.aaveHash aave) asset burnValue = negate $ assetClassValue (rAToken reserve) aTokenAmount spendInputs = (\(ref, tx) -> OutputValue ref tx (Core.WithdrawRedeemer userConfigId)) <$> Map.toList utxos pure $ diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 11c576bd9..c0c58fca3 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -65,12 +65,12 @@ newtype CreateParams = PlutusTx.makeLift ''CreateParams -createReserve :: CreateParams -> Reserve -createReserve CreateParams {..} = +createReserve :: Aave -> CreateParams -> Reserve +createReserve aave CreateParams {..} = Reserve { rCurrency = cpAsset, rAmount = 0, - rAToken = AToken.makeAToken cpAsset, + rAToken = AToken.makeAToken (Core.aaveHash aave) cpAsset, rLiquidityIndex = 1, rCurrentStableBorrowRate = 11 % 10 -- TODO configure borrow rate when lending core will be ready } @@ -88,7 +88,7 @@ start params = do ledgerTx <- TxUtils.submitTxPair aaveTokenTx void $ awaitTxConfirmed $ txId ledgerTx - let reserveMap = AssocMap.fromList $ fmap (\params -> (cpAsset params, createReserve params)) params + let reserveMap = AssocMap.fromList $ fmap (\params -> (cpAsset params, createReserve aave params)) params reservesTx <- State.putReserves aave Core.StartRedeemer reserveMap ledgerTx <- TxUtils.submitTxPair reservesTx void $ awaitTxConfirmed $ txId ledgerTx diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index b3f2d714c..eab4af349 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -45,17 +45,19 @@ import Ext.Plutus.Ledger.Contexts (scriptInputsAt) type OwnerToken = AssetClass --- State token can be only be forged when there is an input and outpu containing an owner token belonging to a script +-- State token can be only be forged when there is an input and output containing an owner token belonging to a script {-# INLINABLE validateStateForging #-} validateStateForging :: ValidatorHash -> OwnerToken -> TokenName -> ScriptContext -> Bool validateStateForging ownerScript ownerToken tokenName ctx = traceIfFalse "State forging not authorized" $ hasOneOwnerToken outputValues && hasOneOwnerToken inputValues && hasOneStateToken forgedValue && hasOneStateToken (mconcat outputValues) where txInfo = scriptContextTxInfo ctx + stateToken = assetClass (ownCurrencySymbol ctx) tokenName + outputValues = snd <$> scriptOutputsAt ownerScript txInfo inputValues = snd <$> scriptInputsAt ownerScript txInfo forgedValue = txInfoForge txInfo - stateToken = assetClass (ownCurrencySymbol ctx) tokenName + hasOneOwnerToken values = assetClassValueOf (mconcat values) ownerToken == 1 hasOneStateToken value = assetClassValueOf value stateToken == 1 From 0112665251fe387ca21f54f96299babf1fc1a834 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 8 Jun 2021 16:03:13 +0700 Subject: [PATCH 079/169] run fmt --- MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs | 2 +- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 4 ++-- MetaLamp/lending-pool/src/Plutus/Contracts/State.hs | 2 +- MetaLamp/lending-pool/src/Plutus/State/Update.hs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs index 996659d35..583e14108 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs @@ -23,6 +23,7 @@ import Data.ByteString (ByteString) import qualified Data.Map as Map import Data.Text (Text) import Data.Void (Void) +import Ext.Plutus.Ledger.Contexts (scriptInputsAt) import Ledger hiding (singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints @@ -49,7 +50,6 @@ import PlutusTx.Prelude hiding (Semigroup (..)) import qualified PlutusTx.Semigroup as Semigroup import Prelude (Semigroup (..)) import qualified Prelude -import Ext.Plutus.Ledger.Contexts (scriptInputsAt) {-# INLINABLE validator #-} validator :: ValidatorHash -> AssetClass -> TokenName -> ScriptContext -> Bool diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index bc5846aaa..577f338ed 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -24,8 +24,8 @@ import qualified Data.Map as Map import Data.Text (Text, pack) import Data.Void (Void) import Ext.Plutus.Ledger.Contexts (findDatumHashByValue, - findValueByDatumHash,valueSpentFrom, - parseDatum) + findValueByDatumHash, + parseDatum, valueSpentFrom) import Ledger hiding (singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 04948c004..2981bf30e 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -36,7 +36,7 @@ import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken import qualified Plutus.Contracts.TxUtils as TxUtils -import Plutus.OutputValue (OutputValue (..),_ovValue) +import Plutus.OutputValue (OutputValue (..), _ovValue) import qualified Plutus.State.Select as Select import Plutus.State.Update (PutStateHandle (..), StateHandle (..)) diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index eab4af349..5bce4d263 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -30,6 +30,7 @@ import qualified Ledger.Scripts as Scripts import Ledger.Typed.Scripts (ScriptType (..)) import qualified Ledger.Typed.Scripts as Scripts +import Ext.Plutus.Ledger.Contexts (scriptInputsAt) import Playground.Contract import Plutus.Contract hiding (when) import qualified Plutus.Contracts.TxUtils as TxUtils @@ -41,7 +42,6 @@ import PlutusTx.Prelude hiding (Semigroup (..), unless) import Prelude (Semigroup (..)) import qualified Prelude -import Ext.Plutus.Ledger.Contexts (scriptInputsAt) type OwnerToken = AssetClass From dbfa0d9cbd314f325c4e39b7e990ee635ebce531 Mon Sep 17 00:00:00 2001 From: megakaban Date: Tue, 8 Jun 2021 16:17:23 +0700 Subject: [PATCH 080/169] Simplify getAaveResponseWith --- MetaLamp/lending-pool/client/src/Business/Aave.purs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MetaLamp/lending-pool/client/src/Business/Aave.purs b/MetaLamp/lending-pool/client/src/Business/Aave.purs index 5a41c05be..7e984f0b2 100644 --- a/MetaLamp/lending-pool/client/src/Business/Aave.purs +++ b/MetaLamp/lending-pool/client/src/Business/Aave.purs @@ -48,9 +48,9 @@ getAaveResponseWith :: forall m a p. ContractId -> p -> m (Either APIError a) -getAaveResponseWith endpoint pick cid param = runExceptT $ do - _ <- lift (callEndpoint endpoint cid param) >>= either throwError pure - lift (pollStatus endpoint pick cid) >>= either throwError pure +getAaveResponseWith endpoint pick cid param = + callEndpoint endpoint cid param >>= + either (pure <<< Left) (const $ pollStatus endpoint pick cid) pollStatus :: forall m a. Contract m => From 8f1e8d6cbf3fa65e33ca2fb2ff30f7fba03ad8e5 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 9 Jun 2021 16:36:19 +0700 Subject: [PATCH 081/169] remove unused code --- MetaLamp/lending-pool/src/Plutus/Contracts/State.hs | 2 +- MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 2981bf30e..0d3102e5f 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -94,7 +94,7 @@ makeReserveHandle :: Aave -> (AssocMap.Map ReserveId Reserve -> AaveRedeemer) -> makeReserveHandle aave toRedeemer = let stateToken = reserveStateToken aave in StateHandle { - stateToken = reserveStateToken aave, + stateToken = stateToken, toDatum = Core.ReservesDatum stateToken, toRedeemer = toRedeemer } diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs index 96210ce78..8637d7b5e 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs @@ -41,8 +41,6 @@ import qualified Prelude type TxPair a = (Constraints.ScriptLookups a, Constraints.TxConstraints (RedeemerType a) (DatumType a)) -type HasTxData a = (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) - submitTxPair :: (AsContractError e, HasWriteTx s, PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => TxPair a -> Contract w s e Tx From b1b8bc25e834efe4187cc4b215fbf6de8a80f468 Mon Sep 17 00:00:00 2001 From: megakaban Date: Wed, 9 Jun 2021 18:47:21 +0700 Subject: [PATCH 082/169] Run formatter --- MetaLamp/lending-pool/client/src/AppAff.purs | 24 +- .../client/src/Business/Aave.purs | 32 +- .../client/src/Capability/Contract.purs | 17 +- .../client/src/Capability/Delay.purs | 4 +- .../client/src/Capability/LogMessages.purs | 4 +- .../client/src/Components/AmountForm.purs | 35 ++- .../client/src/Components/App.purs | 285 ++++++++++-------- MetaLamp/lending-pool/client/src/Main.purs | 4 +- .../client/src/Utils/RemoteDataState.purs | 15 +- .../client/src/View/FundsTable.purs | 26 +- .../client/src/View/RemoteDataState.purs | 11 +- .../client/src/View/ReserveInfo.purs | 7 +- 12 files changed, 262 insertions(+), 202 deletions(-) diff --git a/MetaLamp/lending-pool/client/src/AppAff.purs b/MetaLamp/lending-pool/client/src/AppAff.purs index 7e1b1c052..80170f64a 100644 --- a/MetaLamp/lending-pool/client/src/AppAff.purs +++ b/MetaLamp/lending-pool/client/src/AppAff.purs @@ -1,7 +1,6 @@ module AppAff where import Prelude - import Affjax (Response, defaultRequest) import Affjax.RequestBody (RequestBody, string) import Capability.Contract (class Contract, ContractId(..), Endpoint(..), APIError(..)) @@ -21,16 +20,24 @@ import Foreign.Generic (class Decode, decode, encodeJSON) import Servant.PureScript.Ajax (AjaxError(..), ErrorDescription(..), ajax) import Type.Equality (class TypeEquals, from) -type Env = { host :: String, port :: Int } +type Env + = { host :: String, port :: Int } -newtype AppM a = AppM (ReaderT Env Aff a) +newtype AppM a + = AppM (ReaderT Env Aff a) derive newtype instance functorAppM :: Functor AppM + derive newtype instance applyAppM :: Apply AppM + derive newtype instance applicativeAppM :: Applicative AppM + derive newtype instance bindAppM :: Bind AppM + derive newtype instance monadAppM :: Monad AppM + derive newtype instance monadEffectAppM :: MonadEffect AppM + derive newtype instance monadAffAppM :: MonadAff AppM instance monadAskAppM :: TypeEquals e Env => MonadAsk e AppM where @@ -57,25 +64,26 @@ getBaseURL { host, port } = "http://" <> host <> ":" <> (show port) runAjax :: forall m a. Monad m => ExceptT AjaxError m (Response a) -> m (Either APIError a) runAjax = (map toCustom) <<< runExceptT where - toCustom = bimap (AjaxCallError <<< errorToString) (\r -> r.body) + toCustom = bimap (AjaxCallError <<< errorToString) (\r -> r.body) get :: forall m a. MonadAsk Env m => MonadAff m => Decode a => String -> m (Either APIError a) get path = do url <- asks ((_ <> path) <<< getBaseURL) - let affReq = defaultRequest { method = fromString "GET", url = url } + let + affReq = defaultRequest { method = fromString "GET", url = url } runAjax $ ajax decode affReq post :: forall m a. MonadAsk Env m => MonadAff m => Decode a => String -> RequestBody -> m (Either APIError a) post path body = do url <- asks ((_ <> path) <<< getBaseURL) - let affReq = defaultRequest { method = fromString "POST", url = url, content = Just body } + let + affReq = defaultRequest { method = fromString "POST", url = url, content = Just body } runAjax $ ajax decode affReq instance contractAppM :: Contract AppM where getContracts = get "/api/new/contract/instances" getContractStatus (ContractId cid) = get $ "/api/new/contract/instance/" <> cid <> "/status" - callEndpoint (Endpoint endpoint) (ContractId cid) params = - post ("/api/new/contract/instance/" <> cid <> "/endpoint/" <> endpoint) (string <<< encodeJSON $ params) + callEndpoint (Endpoint endpoint) (ContractId cid) params = post ("/api/new/contract/instance/" <> cid <> "/endpoint/" <> endpoint) (string <<< encodeJSON $ params) instance delayAppM :: Delay AppM where delay = liftAff <<< delay diff --git a/MetaLamp/lending-pool/client/src/Business/Aave.purs b/MetaLamp/lending-pool/client/src/Business/Aave.purs index 7e984f0b2..d7e1046e8 100644 --- a/MetaLamp/lending-pool/client/src/Business/Aave.purs +++ b/MetaLamp/lending-pool/client/src/Business/Aave.purs @@ -1,7 +1,6 @@ module Business.Aave where import Prelude - import Capability.Contract (class Contract, APIError(..), ContractId, ContractUnit(..), Endpoint(..), callEndpoint, getContractStatus, getContracts) import Capability.Delay (class Delay, delay) import Control.Monad.Except (runExcept, runExceptT, throwError) @@ -34,12 +33,13 @@ getAaveContractResponse = map (_ >>= getAaveResponse) <<< getAaveContractStatus getAaveResponse :: ContractInstanceClientState AaveContracts -> Either APIError UserContractState getAaveResponse (ContractInstanceClientState { cicCurrentState: PartiallyDecodedResponse { observableState: RawJson s } }) = do - (res:: Either String UserContractState) <- lmap (AjaxCallError <<< show) <<< runExcept <<< decodeJSON $ s + (res :: Either String UserContractState) <- lmap (AjaxCallError <<< show) <<< runExcept <<< decodeJSON $ s case res of Left e -> Left <<< AjaxCallError $ e Right r -> Right r -getAaveResponseWith :: forall m a p. +getAaveResponseWith :: + forall m a p. Contract m => Delay m => Encode p => @@ -49,25 +49,27 @@ getAaveResponseWith :: forall m a p. p -> m (Either APIError a) getAaveResponseWith endpoint pick cid param = - callEndpoint endpoint cid param >>= - either (pure <<< Left) (const $ pollStatus endpoint pick cid) + callEndpoint endpoint cid param + >>= either (pure <<< Left) (const $ pollStatus endpoint pick cid) -pollStatus :: forall m a. +pollStatus :: + forall m a. Contract m => Delay m => Endpoint -> Prism' UserContractState a -> ContractId -> m (Either APIError a) -pollStatus endpoint pick cid = runExceptT $ do - _ <- lift <<< delay <<< Milliseconds $ 300.0 - res <- lift (getAaveContractResponse cid) >>= either throwError pure - case (preview _Pending res) of - Just _ -> lift (pollStatus endpoint pick cid) >>= either throwError pure - Nothing -> - case (preview pick res) of - Just v -> pure v - Nothing -> throwError $ AjaxCallError $ "Invalid state: " <> (show res) +pollStatus endpoint pick cid = + runExceptT + $ do + _ <- lift <<< delay <<< Milliseconds $ 300.0 + res <- lift (getAaveContractResponse cid) >>= either throwError pure + case (preview _Pending res) of + Just _ -> lift (pollStatus endpoint pick cid) >>= either throwError pure + Nothing -> case (preview pick res) of + Just v -> pure v + Nothing -> throwError $ AjaxCallError $ "Invalid state: " <> (show res) deposit :: forall m. Contract m => Delay m => ContractId -> DepositParams -> m (Either APIError Unit) deposit = getAaveResponseWith (Endpoint "deposit") _Deposited diff --git a/MetaLamp/lending-pool/client/src/Capability/Contract.purs b/MetaLamp/lending-pool/client/src/Capability/Contract.purs index d9c5a74b7..2c35e2310 100644 --- a/MetaLamp/lending-pool/client/src/Capability/Contract.purs +++ b/MetaLamp/lending-pool/client/src/Capability/Contract.purs @@ -1,7 +1,6 @@ module Capability.Contract where import Prelude - import Data.Either (Either) import Data.Generic.Rep (class Generic) import Data.Generic.Rep.Show (genericShow) @@ -10,26 +9,32 @@ import Foreign.Generic (class Decode, class Encode) import Halogen (HalogenM, lift) import Plutus.PAB.Webserver.Types (ContractInstanceClientState) -data APIError = AjaxCallError String +data APIError + = AjaxCallError String derive instance genericAPIError :: Generic APIError _ + instance showAPIError :: Show APIError where show = genericShow -newtype ContractId = ContractId String +newtype ContractId + = ContractId String derive newtype instance showContractId :: Show ContractId -newtype Endpoint = Endpoint String +newtype Endpoint + = Endpoint String derive newtype instance showEndpoint :: Show Endpoint -data ContractUnit = ContractUnit +data ContractUnit + = ContractUnit instance encodeContractUnit :: Encode ContractUnit where encode value = unsafeToForeign [] -class Monad m <= Contract m where +class + Monad m <= Contract m where getContracts :: forall a. Decode a => m (Either APIError (Array (ContractInstanceClientState a))) callEndpoint :: forall a. Encode a => Endpoint -> ContractId -> a -> m (Either APIError Unit) getContractStatus :: forall a. Decode a => ContractId -> m (Either APIError (ContractInstanceClientState a)) diff --git a/MetaLamp/lending-pool/client/src/Capability/Delay.purs b/MetaLamp/lending-pool/client/src/Capability/Delay.purs index d59618865..706e9770d 100644 --- a/MetaLamp/lending-pool/client/src/Capability/Delay.purs +++ b/MetaLamp/lending-pool/client/src/Capability/Delay.purs @@ -1,11 +1,11 @@ module Capability.Delay where import Prelude - import Data.Time.Duration (Milliseconds) import Halogen (HalogenM, lift) -class Monad m <= Delay m where +class + Monad m <= Delay m where delay :: Milliseconds -> m Unit instance delayHalogenM :: Delay m => Delay (HalogenM st act slots msg m) where diff --git a/MetaLamp/lending-pool/client/src/Capability/LogMessages.purs b/MetaLamp/lending-pool/client/src/Capability/LogMessages.purs index 5d5a07bab..dd4495b71 100644 --- a/MetaLamp/lending-pool/client/src/Capability/LogMessages.purs +++ b/MetaLamp/lending-pool/client/src/Capability/LogMessages.purs @@ -1,10 +1,10 @@ module Capability.LogMessages where import Prelude - import Halogen (HalogenM, lift) -class Monad m <= LogMessages m where +class + Monad m <= LogMessages m where logInfo :: String -> m Unit logError :: String -> m Unit diff --git a/MetaLamp/lending-pool/client/src/Components/AmountForm.purs b/MetaLamp/lending-pool/client/src/Components/AmountForm.purs index c04593862..ee9dd24ae 100644 --- a/MetaLamp/lending-pool/client/src/Components/AmountForm.purs +++ b/MetaLamp/lending-pool/client/src/Components/AmountForm.purs @@ -1,7 +1,6 @@ module Components.AmountForm where import Prelude - import Data.Array (head) import Data.BigInteger (BigInteger, fromString) import Data.Maybe (Maybe(..), fromMaybe, maybe) @@ -10,15 +9,23 @@ import Halogen.HTML as HH import Halogen.HTML.Events as HE import Halogen.HTML.Properties as HP -type AmountInfo = { name :: String, amount :: BigInteger } +type AmountInfo + = { name :: String, amount :: BigInteger } -data Output = Submit AmountInfo +data Output + = Submit AmountInfo -data Action = SubmitClick | EnterName String | EnterAmount String | Receive Input +data Action + = SubmitClick + | EnterName String + | EnterAmount String + | Receive Input -type State = { amounts :: Array AmountInfo, name :: Maybe String, amount :: Maybe BigInteger } +type State + = { amounts :: Array AmountInfo, name :: Maybe String, amount :: Maybe BigInteger } -type Input = Array AmountInfo +type Input + = Array AmountInfo initialState :: Input -> State initialState amounts = { amounts, name: _.name <$> head amounts, amount: Nothing } @@ -34,13 +41,15 @@ amountForm = render state = HH.div_ [ HH.select - [HP.value (fromMaybe "" state.name), HE.onValueChange (Just <<< EnterName)] - (map (\({ name }) -> - HH.option [HP.value name, HP.selected (name == (fromMaybe "" state.name))] [HH.text name]) - state.amounts - ), - HH.input [HP.value $ maybe "" show state.amount, HE.onValueInput (Just <<< EnterAmount)], - HH.button [HE.onClick \_ -> Just SubmitClick] [HH.text "Submit"] + [ HP.value (fromMaybe "" state.name), HE.onValueChange (Just <<< EnterName) ] + ( map + ( \({ name }) -> + HH.option [ HP.value name, HP.selected (name == (fromMaybe "" state.name)) ] [ HH.text name ] + ) + state.amounts + ) + , HH.input [ HP.value $ maybe "" show state.amount, HE.onValueInput (Just <<< EnterAmount) ] + , HH.button [ HE.onClick \_ -> Just SubmitClick ] [ HH.text "Submit" ] ] handleAction :: Action -> H.HalogenM State Action () Output m Unit diff --git a/MetaLamp/lending-pool/client/src/Components/App.purs b/MetaLamp/lending-pool/client/src/Components/App.purs index 8a42fb6e9..b2fefe0d6 100644 --- a/MetaLamp/lending-pool/client/src/Components/App.purs +++ b/MetaLamp/lending-pool/client/src/Components/App.purs @@ -1,7 +1,6 @@ module Components.App where import Prelude - import Business.Aave as Aave import Capability.Contract (class Contract, ContractId(..)) import Capability.Delay (class Delay) @@ -36,23 +35,25 @@ import View.ReserveInfo (reserveInfo) import Wallet.Emulator.Wallet (Wallet(..)) import Wallet.Types (ContractInstanceId(..)) -type State = - { contractId :: RemoteData String ContractId, - walletPubKey :: RemoteData String PubKeyHash, - userFunds :: RemoteData String Value, - reserves :: RemoteData String (Map.Map AssetClass Reserve), - lastStatus :: RemoteData String String } +type State + = { contractId :: RemoteData String ContractId + , walletPubKey :: RemoteData String PubKeyHash + , userFunds :: RemoteData String Value + , reserves :: RemoteData String (Map.Map AssetClass Reserve) + , lastStatus :: RemoteData String String + } initialState :: forall input. input -> State initialState _ = - { contractId: NotAsked, - walletPubKey: NotAsked, - userFunds: NotAsked, - reserves: NotAsked, - lastStatus: NotAsked } + { contractId: NotAsked + , walletPubKey: NotAsked + , userFunds: NotAsked + , reserves: NotAsked + , lastStatus: NotAsked + } -data Action = - Init +data Action + = Init | GetContractAt Wallet | GetWalletPubKey | GetUserFunds @@ -65,7 +66,11 @@ data Action = | SubmitAmount SubmitOperation AmountForm.Output -- potentially should be separate actions - just a convenience for now, while they are identical -data SubmitOperation = SubmitDeposit | SubmitWithdraw | SubmitBorrow | SubmitRepay +data SubmitOperation + = SubmitDeposit + | SubmitWithdraw + | SubmitBorrow + | SubmitRepay toContractIdParam :: ContractInstanceId -> ContractId toContractIdParam (ContractInstanceId { unContractInstanceId: JsonUUID uuid }) = ContractId <<< UUID.toString $ uuid @@ -73,131 +78,161 @@ toContractIdParam (ContractInstanceId { unContractInstanceId: JsonUUID uuid }) = handleException :: forall e a m. LogMessages m => Show e => Either e a -> m Unit handleException = either (logError <<< show) (const $ pure unit) -type Slots = ( amountForm :: forall query. H.Slot query AmountForm.Output Int ) +type Slots + = ( amountForm :: forall query. H.Slot query AmountForm.Output Int ) + _amountForm = SProxy :: SProxy "amountForm" -component :: forall input m query output. +component :: + forall input m query output. LogMessages m => Contract m => Delay m => H.Component HH.HTML query input output m component = H.mkComponent - { - initialState, - render, - eval: H.mkEval H.defaultEval { handleAction = handleAction } + { initialState + , render + , eval: H.mkEval H.defaultEval { handleAction = handleAction } } where - handleAction :: Action -> H.HalogenM State Action Slots output m Unit - handleAction = case _ of - Init -> do - handleAction (GetContractAt $ Wallet { getWallet: fromInt 2 }) - handleAction GetWalletPubKey - handleAction GetFunds - GetContractAt wallet -> do - H.modify_ _ { contractId = Loading } - instancesRD <- Aave.getAaveContracts - case instancesRD of - Left e -> H.modify_ _ { contractId = Failure (show e) } - Right instances -> do - let contract = find (\(ContractInstanceClientState i) -> i.cicWallet == wallet) instances - case contract of - Nothing -> H.modify_ _ { contractId = Failure "Contract instance not found" } - Just (ContractInstanceClientState i) -> - H.modify_ _ { contractId = Success (toContractIdParam i.cicContract) } - GetWalletPubKey -> handleException <=< runExceptT $ do - lift $ H.modify_ _ { walletPubKey = Loading } - state <- lift H.get - cid <- RD.maybe (throwError "Failed to get wallet public key") pure $ state.contractId - pkh <- lift $ Aave.ownPubKey cid - lift $ H.modify_ _ { walletPubKey = fromEither <<< lmap show $ pkh } - GetUserFunds -> handleException <=< runExceptT $ do - lift $ H.modify_ _ { userFunds = Loading } - state <- lift H.get - { cid, pkh } <- - RD.maybe (throwError "Failed to get user funds") pure $ - { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - funds <- lift $ Aave.fundsAt cid pkh - lift $ H.modify_ _ { userFunds = fromEither <<< lmap show $ funds } - GetReserves -> handleException <=< runExceptT $ do - lift $ H.modify_ _ { reserves = Loading } - state <- lift H.get - cid <- RD.maybe (throwError "Failed to get reserves") pure $ state.contractId - reserves <- lift $ Aave.reserves cid - lift $ H.modify_ _ { reserves = fromEither <<< lmap show $ reserves } - GetFunds -> do - handleAction GetUserFunds - handleAction GetReserves - - Deposit { amount, asset } -> handleException <=< runExceptT $ do - state <- lift H.get - { cid, pkh } <- - RD.maybe (throwError "Failed to deposit") pure $ - { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - res <- lift $ Aave.deposit cid $ DepositParams { dpAmount: amount, dpAsset: asset, dpOnBehalfOf: pkh } - lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } - Withdraw { amount, asset } -> handleException <=< runExceptT $ do - state <- lift H.get - { cid, pkh } <- - RD.maybe (throwError "Failed to deposit") pure $ - { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - res <- lift $ Aave.withdraw cid $ WithdrawParams { wpAmount: amount, wpAsset: asset, wpUser: pkh } - lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } - Borrow { amount, asset } -> handleException <=< runExceptT $ do - state <- lift H.get - { cid, pkh } <- - RD.maybe (throwError "Failed to deposit") pure $ - { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - res <- lift $ Aave.borrow cid $ BorrowParams { bpAmount: amount, bpAsset: asset, bpOnBehalfOf: pkh } - lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } - Repay { amount, asset } -> handleException <=< runExceptT $ do - state <- lift H.get - { cid, pkh } <- - RD.maybe (throwError "Failed to deposit") pure $ - { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - res <- lift $ Aave.repay cid $ RepayParams { rpAmount: amount, rpAsset: asset, rpOnBehalfOf: pkh } - lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } - - SubmitAmount operation (AmountForm.Submit { name, amount }) -> handleException <=< runExceptT $ do - state <- lift H.get - reserves <- RD.maybe (throwError "Failed to submit") pure $ state.reserves - case find (\(Tuple k _) -> getAssetName k == name) (Map.toTuples reserves) of - Just (Tuple asset _) -> do - case operation of - SubmitDeposit -> lift $ handleAction (Deposit { amount, asset }) - SubmitWithdraw -> lift $ handleAction (Withdraw { amount, asset }) - SubmitBorrow -> lift $ handleAction (Borrow { amount, asset }) - SubmitRepay -> lift $ handleAction (Repay { amount, asset }) - lift $ handleAction GetFunds - Nothing -> throwError "Asset name not found" + handleAction :: Action -> H.HalogenM State Action Slots output m Unit + handleAction = case _ of + Init -> do + handleAction (GetContractAt $ Wallet { getWallet: fromInt 2 }) + handleAction GetWalletPubKey + handleAction GetFunds + GetContractAt wallet -> do + H.modify_ _ { contractId = Loading } + instancesRD <- Aave.getAaveContracts + case instancesRD of + Left e -> H.modify_ _ { contractId = Failure (show e) } + Right instances -> do + let + contract = find (\(ContractInstanceClientState i) -> i.cicWallet == wallet) instances + case contract of + Nothing -> H.modify_ _ { contractId = Failure "Contract instance not found" } + Just (ContractInstanceClientState i) -> H.modify_ _ { contractId = Success (toContractIdParam i.cicContract) } + GetWalletPubKey -> + handleException <=< runExceptT + $ do + lift $ H.modify_ _ { walletPubKey = Loading } + state <- lift H.get + cid <- RD.maybe (throwError "Failed to get wallet public key") pure $ state.contractId + pkh <- lift $ Aave.ownPubKey cid + lift $ H.modify_ _ { walletPubKey = fromEither <<< lmap show $ pkh } + GetUserFunds -> + handleException <=< runExceptT + $ do + lift $ H.modify_ _ { userFunds = Loading } + state <- lift H.get + { cid, pkh } <- + RD.maybe (throwError "Failed to get user funds") pure + $ { cid: _, pkh: _ } + <$> state.contractId + <*> state.walletPubKey + funds <- lift $ Aave.fundsAt cid pkh + lift $ H.modify_ _ { userFunds = fromEither <<< lmap show $ funds } + GetReserves -> + handleException <=< runExceptT + $ do + lift $ H.modify_ _ { reserves = Loading } + state <- lift H.get + cid <- RD.maybe (throwError "Failed to get reserves") pure $ state.contractId + reserves <- lift $ Aave.reserves cid + lift $ H.modify_ _ { reserves = fromEither <<< lmap show $ reserves } + GetFunds -> do + handleAction GetUserFunds + handleAction GetReserves + Deposit { amount, asset } -> + handleException <=< runExceptT + $ do + state <- lift H.get + { cid, pkh } <- + RD.maybe (throwError "Failed to deposit") pure + $ { cid: _, pkh: _ } + <$> state.contractId + <*> state.walletPubKey + res <- lift $ Aave.deposit cid $ DepositParams { dpAmount: amount, dpAsset: asset, dpOnBehalfOf: pkh } + lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } + Withdraw { amount, asset } -> + handleException <=< runExceptT + $ do + state <- lift H.get + { cid, pkh } <- + RD.maybe (throwError "Failed to deposit") pure + $ { cid: _, pkh: _ } + <$> state.contractId + <*> state.walletPubKey + res <- lift $ Aave.withdraw cid $ WithdrawParams { wpAmount: amount, wpAsset: asset, wpUser: pkh } + lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } + Borrow { amount, asset } -> + handleException <=< runExceptT + $ do + state <- lift H.get + { cid, pkh } <- + RD.maybe (throwError "Failed to deposit") pure + $ { cid: _, pkh: _ } + <$> state.contractId + <*> state.walletPubKey + res <- lift $ Aave.borrow cid $ BorrowParams { bpAmount: amount, bpAsset: asset, bpOnBehalfOf: pkh } + lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } + Repay { amount, asset } -> + handleException <=< runExceptT + $ do + state <- lift H.get + { cid, pkh } <- + RD.maybe (throwError "Failed to deposit") pure + $ { cid: _, pkh: _ } + <$> state.contractId + <*> state.walletPubKey + res <- lift $ Aave.repay cid $ RepayParams { rpAmount: amount, rpAsset: asset, rpOnBehalfOf: pkh } + lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } + SubmitAmount operation (AmountForm.Submit { name, amount }) -> + handleException <=< runExceptT + $ do + state <- lift H.get + reserves <- RD.maybe (throwError "Failed to submit") pure $ state.reserves + case find (\(Tuple k _) -> getAssetName k == name) (Map.toTuples reserves) of + Just (Tuple asset _) -> do + case operation of + SubmitDeposit -> lift $ handleAction (Deposit { amount, asset }) + SubmitWithdraw -> lift $ handleAction (Withdraw { amount, asset }) + SubmitBorrow -> lift $ handleAction (Borrow { amount, asset }) + SubmitRepay -> lift $ handleAction (Repay { amount, asset }) + lift $ handleAction GetFunds + Nothing -> throwError "Asset name not found" - render :: State -> H.ComponentHTML Action Slots m - render state = - HH.div_ - [ HH.button [HE.onClick \_ -> Just Init] [HH.text "Start"] - , remoteDataState - (\userFunds -> HH.div_ [HH.h2_ [HH.text "User funds"], fundsTable userFunds]) - state.userFunds - , remoteDataState - (\reserves -> HH.div_ $ - [HH.h2_ [HH.text "Pool funds"]] <> - map (\(Tuple a r) -> reserveInfo a r) reserves - ) - (map Map.toTuples state.reserves) - , remoteDataState - (\amounts -> HH.div_ $ mapWithIndex - (\index (Tuple title operation) -> - HH.h2_ [HH.text title, HH.slot _amountForm index AmountForm.amountForm amounts (Just <<< (SubmitAmount operation))]) - [Tuple "Deposit" SubmitDeposit, Tuple "Withdraw" SubmitWithdraw, Tuple "Borrow" SubmitBorrow, Tuple "Repay" SubmitRepay] - ) - (map reservesToAmounts state.reserves) - ] + render :: State -> H.ComponentHTML Action Slots m + render state = + HH.div_ + [ HH.button [ HE.onClick \_ -> Just Init ] [ HH.text "Start" ] + , remoteDataState + (\userFunds -> HH.div_ [ HH.h2_ [ HH.text "User funds" ], fundsTable userFunds ]) + state.userFunds + , remoteDataState + ( \reserves -> + HH.div_ + $ [ HH.h2_ [ HH.text "Pool funds" ] ] + <> map (\(Tuple a r) -> reserveInfo a r) reserves + ) + (map Map.toTuples state.reserves) + , remoteDataState + ( \amounts -> + HH.div_ + $ mapWithIndex + ( \index (Tuple title operation) -> + HH.h2_ [ HH.text title, HH.slot _amountForm index AmountForm.amountForm amounts (Just <<< (SubmitAmount operation)) ] + ) + [ Tuple "Deposit" SubmitDeposit, Tuple "Withdraw" SubmitWithdraw, Tuple "Borrow" SubmitBorrow, Tuple "Repay" SubmitRepay ] + ) + (map reservesToAmounts state.reserves) + ] reservesToAmounts :: Map.Map AssetClass Reserve -> Array AmountForm.AmountInfo reservesToAmounts = map toInfo <<< Map.toTuples where - toInfo (Tuple k (Reserve { rAmount })) = { name: getAssetName k, amount: rAmount } + toInfo (Tuple k (Reserve { rAmount })) = { name: getAssetName k, amount: rAmount } getAssetName :: AssetClass -> String getAssetName (AssetClass { unAssetClass: JsonTuple (Tuple _ (TokenName { unTokenName: name })) }) = name diff --git a/MetaLamp/lending-pool/client/src/Main.purs b/MetaLamp/lending-pool/client/src/Main.purs index 452bd7852..8265aad06 100644 --- a/MetaLamp/lending-pool/client/src/Main.purs +++ b/MetaLamp/lending-pool/client/src/Main.purs @@ -1,7 +1,6 @@ module Main where import Prelude - import Components.App as App import AppAff (runAppM) import Effect (Effect) @@ -13,7 +12,8 @@ import Halogen.VDom.Driver (runUI) main :: Effect Unit main = runHalogenAff do - let rootComponent = H.hoist (runAppM { host: "localhost", port: 8080 }) App.component + let + rootComponent = H.hoist (runAppM { host: "localhost", port: 8080 }) App.component body <- awaitBody runUI rootComponent unit body diff --git a/MetaLamp/lending-pool/client/src/Utils/RemoteDataState.purs b/MetaLamp/lending-pool/client/src/Utils/RemoteDataState.purs index 659389bfb..2f50684d3 100644 --- a/MetaLamp/lending-pool/client/src/Utils/RemoteDataState.purs +++ b/MetaLamp/lending-pool/client/src/Utils/RemoteDataState.purs @@ -3,15 +3,18 @@ module Utils.RemoteDataState where import Halogen.HTML as HH import Network.RemoteData (RemoteData(..)) -type RemoteDataHandle props act e a = { - onNotAsked :: HH.HTML props act, - onLoading :: HH.HTML props act, - onFailure :: e -> HH.HTML props act, - onSuccess :: a -> HH.HTML props act -} +type RemoteDataHandle props act e a + = { onNotAsked :: HH.HTML props act + , onLoading :: HH.HTML props act + , onFailure :: e -> HH.HTML props act + , onSuccess :: a -> HH.HTML props act + } makeRemoteDataState :: forall props act e a. RemoteDataHandle props act e a -> RemoteData e a -> HH.HTML props act makeRemoteDataState { onNotAsked } NotAsked = onNotAsked + makeRemoteDataState { onLoading } Loading = onLoading + makeRemoteDataState { onFailure } (Failure e) = onFailure e + makeRemoteDataState { onSuccess } (Success s) = onSuccess s diff --git a/MetaLamp/lending-pool/client/src/View/FundsTable.purs b/MetaLamp/lending-pool/client/src/View/FundsTable.purs index 68b7f4fea..0396fffab 100644 --- a/MetaLamp/lending-pool/client/src/View/FundsTable.purs +++ b/MetaLamp/lending-pool/client/src/View/FundsTable.purs @@ -1,7 +1,6 @@ module View.FundsTable where import Prelude - import Data.BigInteger (BigInteger, fromInt) import Data.Tuple (Tuple(..)) import Halogen.HTML as HH @@ -9,16 +8,19 @@ import Plutus.V1.Ledger.Value (TokenName(..), Value(..)) import PlutusTx.AssocMap as Map fundsTable :: forall props act. Value -> HH.HTML props act -fundsTable (Value ({ getValue: m })) = HH.div_ $ do - (Tuple _ amounts) <- Map.toTuples m - (Tuple name amount) <- Map.toTuples amounts - if amount > (fromInt 0) - then pure $ amountTab name amount - else [] +fundsTable (Value ({ getValue: m })) = + HH.div_ + $ do + (Tuple _ amounts) <- Map.toTuples m + (Tuple name amount) <- Map.toTuples amounts + if amount > (fromInt 0) then + pure $ amountTab name amount + else + [] amountTab :: forall props act. TokenName -> BigInteger -> HH.HTML props act -amountTab (TokenName { unTokenName: name }) amount = - HH.div_ $ [HH.text (showName name <> " " <> show amount)] - where - showName "" = "ADA" - showName n = n +amountTab (TokenName { unTokenName: name }) amount = HH.div_ $ [ HH.text (showName name <> " " <> show amount) ] + where + showName "" = "ADA" + + showName n = n diff --git a/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs b/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs index cdf9d14eb..714a2ef1e 100644 --- a/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs +++ b/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs @@ -1,7 +1,6 @@ module View.RemoteDataState where import Prelude - import Halogen.HTML as HH import Network.RemoteData (RemoteData) import Utils.RemoteDataState (makeRemoteDataState) @@ -9,8 +8,8 @@ import Utils.RemoteDataState (makeRemoteDataState) remoteDataState :: forall props act e a. Show e => (a -> HH.HTML props act) -> RemoteData e a -> HH.HTML props act remoteDataState onSuccess = makeRemoteDataState - { onNotAsked: HH.div_ [HH.text ""], - onLoading: HH.div_ [HH.text "Loading..."], - onFailure: \e -> HH.div_ [HH.text $ "Error: " <> show e], - onSuccess - } + { onNotAsked: HH.div_ [ HH.text "" ] + , onLoading: HH.div_ [ HH.text "Loading..." ] + , onFailure: \e -> HH.div_ [ HH.text $ "Error: " <> show e ] + , onSuccess + } diff --git a/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs b/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs index a7e1c1d5d..d937b44a5 100644 --- a/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs +++ b/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs @@ -1,7 +1,6 @@ module View.ReserveInfo where import Prelude - import Data.BigInteger (BigInteger) import Data.Json.JsonTuple (JsonTuple(..)) import Data.Tuple (Tuple(..)) @@ -10,9 +9,7 @@ import Plutus.Contracts.Core (Reserve(..)) import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..)) reserveInfo :: forall props act. AssetClass -> Reserve -> HH.HTML props act -reserveInfo (AssetClass { unAssetClass: JsonTuple (Tuple _ name)}) (Reserve { rAmount }) = - poolTab name rAmount +reserveInfo (AssetClass { unAssetClass: JsonTuple (Tuple _ name) }) (Reserve { rAmount }) = poolTab name rAmount poolTab :: forall props act. TokenName -> BigInteger -> HH.HTML props act -poolTab (TokenName { unTokenName: name }) amount = - HH.div_ $ [HH.h4_ [HH.text (name <> " pool balance")], HH.text $ show amount] +poolTab (TokenName { unTokenName: name }) amount = HH.div_ $ [ HH.h4_ [ HH.text (name <> " pool balance") ], HH.text $ show amount ] From a719484c2601a1fad0c2f570f3f69e9997a3435b Mon Sep 17 00:00:00 2001 From: megakaban Date: Thu, 10 Jun 2021 02:29:46 +0700 Subject: [PATCH 083/169] Abstract contract polling --- MetaLamp/lending-pool/client/src/AppAff.purs | 10 +- .../client/src/Business/Aave.purs | 91 +++++++------------ .../client/src/Capability/Delay.purs | 12 --- .../client/src/Capability/PollContract.purs | 66 ++++++++++++++ .../client/src/Components/App.purs | 33 +++++-- 5 files changed, 128 insertions(+), 84 deletions(-) delete mode 100644 MetaLamp/lending-pool/client/src/Capability/Delay.purs create mode 100644 MetaLamp/lending-pool/client/src/Capability/PollContract.purs diff --git a/MetaLamp/lending-pool/client/src/AppAff.purs b/MetaLamp/lending-pool/client/src/AppAff.purs index 80170f64a..4fbebdf4c 100644 --- a/MetaLamp/lending-pool/client/src/AppAff.purs +++ b/MetaLamp/lending-pool/client/src/AppAff.purs @@ -1,18 +1,19 @@ module AppAff where import Prelude + import Affjax (Response, defaultRequest) import Affjax.RequestBody (RequestBody, string) import Capability.Contract (class Contract, ContractId(..), Endpoint(..), APIError(..)) -import Capability.Delay (class Delay) import Capability.LogMessages (class LogMessages) +import Capability.PollContract (class PollContract) import Control.Monad.Except (ExceptT, runExceptT) import Control.Monad.Reader.Trans (class MonadAsk, ReaderT, asks, runReaderT) import Data.Bifunctor (bimap) import Data.Either (Either) import Data.HTTP.Method (fromString) import Data.Maybe (Maybe(..)) -import Effect.Aff (Aff, delay) +import Effect.Aff (Aff, Milliseconds(..), delay) import Effect.Aff.Class (class MonadAff, liftAff) import Effect.Class (class MonadEffect, liftEffect) import Effect.Console as Console @@ -85,5 +86,6 @@ instance contractAppM :: Contract AppM where getContractStatus (ContractId cid) = get $ "/api/new/contract/instance/" <> cid <> "/status" callEndpoint (Endpoint endpoint) (ContractId cid) params = post ("/api/new/contract/instance/" <> cid <> "/endpoint/" <> endpoint) (string <<< encodeJSON $ params) -instance delayAppM :: Delay AppM where - delay = liftAff <<< delay +instance pollContractAppM :: PollContract AppM where + pollDelay = liftAff <<< delay <<< Milliseconds $ 300.0 + tooManyRetries retryCount = pure $ retryCount > 10 diff --git a/MetaLamp/lending-pool/client/src/Business/Aave.purs b/MetaLamp/lending-pool/client/src/Business/Aave.purs index d7e1046e8..9fdfe8fae 100644 --- a/MetaLamp/lending-pool/client/src/Business/Aave.purs +++ b/MetaLamp/lending-pool/client/src/Business/Aave.purs @@ -1,17 +1,15 @@ module Business.Aave where import Prelude -import Capability.Contract (class Contract, APIError(..), ContractId, ContractUnit(..), Endpoint(..), callEndpoint, getContractStatus, getContracts) -import Capability.Delay (class Delay, delay) -import Control.Monad.Except (runExcept, runExceptT, throwError) -import Control.Monad.Trans.Class (lift) -import Data.Bifunctor (lmap) -import Data.Either (Either(..), either) + +import Capability.Contract (class Contract, ContractId, APIError, ContractUnit(..), Endpoint(..), getContracts) +import Capability.PollContract (class PollContract, LeftPoll(..), PollError, PollResponse, pollEndpoint) +import Control.Monad.Except (runExcept, throwError, withExcept) +import Data.Either (Either, either) import Data.Json.JsonTuple (JsonTuple) import Data.Lens (Prism', preview) -import Data.Maybe (Maybe(..)) +import Data.Maybe (Maybe(..), maybe) import Data.RawJson (RawJson(..)) -import Data.Time.Duration (Milliseconds(..)) import Foreign.Generic (class Encode, decodeJSON) import Plutus.Contracts.Core (Reserve, UserConfig) import Plutus.Contracts.Endpoints (BorrowParams, DepositParams, RepayParams, UserContractState, WithdrawParams, _Borrowed, _Deposited, _FundsAt, _GetPubKey, _Pending, _PoolFunds, _Repaid, _Reserves, _Users, _Withdrawn) @@ -25,75 +23,52 @@ import PlutusTx.AssocMap (Map) getAaveContracts :: forall m. Contract m => m (Either APIError (Array (ContractInstanceClientState AaveContracts))) getAaveContracts = getContracts -getAaveContractStatus :: forall m. Contract m => ContractId -> m (Either APIError (ContractInstanceClientState AaveContracts)) -getAaveContractStatus = getContractStatus - -getAaveContractResponse :: forall m. Contract m => ContractId -> m (Either APIError UserContractState) -getAaveContractResponse = map (_ >>= getAaveResponse) <<< getAaveContractStatus - -getAaveResponse :: ContractInstanceClientState AaveContracts -> Either APIError UserContractState -getAaveResponse (ContractInstanceClientState { cicCurrentState: PartiallyDecodedResponse { observableState: RawJson s } }) = do - (res :: Either String UserContractState) <- lmap (AjaxCallError <<< show) <<< runExcept <<< decodeJSON $ s - case res of - Left e -> Left <<< AjaxCallError $ e - Right r -> Right r - -getAaveResponseWith :: - forall m a p. - Contract m => - Delay m => +getAaveResponseWith :: forall m a p. + PollContract m => Encode p => Endpoint -> Prism' UserContractState a -> ContractId -> p -> - m (Either APIError a) -getAaveResponseWith endpoint pick cid param = - callEndpoint endpoint cid param - >>= either (pure <<< Left) (const $ pollStatus endpoint pick cid) - -pollStatus :: - forall m a. - Contract m => - Delay m => - Endpoint -> - Prism' UserContractState a -> - ContractId -> - m (Either APIError a) -pollStatus endpoint pick cid = - runExceptT - $ do - _ <- lift <<< delay <<< Milliseconds $ 300.0 - res <- lift (getAaveContractResponse cid) >>= either throwError pure - case (preview _Pending res) of - Just _ -> lift (pollStatus endpoint pick cid) >>= either throwError pure - Nothing -> case (preview pick res) of - Just v -> pure v - Nothing -> throwError $ AjaxCallError $ "Invalid state: " <> (show res) - -deposit :: forall m. Contract m => Delay m => ContractId -> DepositParams -> m (Either APIError Unit) + m (Either PollError a) +getAaveResponseWith endpoint pick cid param = pollEndpoint getNext endpoint param cid + where + getNext :: ContractInstanceClientState AaveContracts -> PollResponse a + getNext (ContractInstanceClientState { cicCurrentState: PartiallyDecodedResponse { observableState: RawJson s } }) = + runExcept $ do + (response :: Either String UserContractState) <- withExcept (ResponseError <<< show) (decodeJSON s) + state <- either (throwError <<< ResponseError <<< show) pure response + case (preview _Pending state) of + Just _ -> throwError Continue + Nothing -> + maybe + (throwError <<< ResponseError $ "Invalid state: " <> (show state)) + pure + (preview pick state) + +deposit :: forall m. PollContract m => ContractId -> DepositParams -> m (Either PollError Unit) deposit = getAaveResponseWith (Endpoint "deposit") _Deposited -withdraw :: forall m. Contract m => Delay m => ContractId -> WithdrawParams -> m (Either APIError Unit) +withdraw :: forall m. PollContract m => ContractId -> WithdrawParams -> m (Either PollError Unit) withdraw = getAaveResponseWith (Endpoint "withdraw") _Withdrawn -borrow :: forall m. Contract m => Delay m => ContractId -> BorrowParams -> m (Either APIError Unit) +borrow :: forall m. PollContract m => ContractId -> BorrowParams -> m (Either PollError Unit) borrow = getAaveResponseWith (Endpoint "borrow") _Borrowed -repay :: forall m. Contract m => Delay m => ContractId -> RepayParams -> m (Either APIError Unit) +repay :: forall m. PollContract m => ContractId -> RepayParams -> m (Either PollError Unit) repay = getAaveResponseWith (Endpoint "repay") _Repaid -fundsAt :: forall m. Contract m => Delay m => ContractId -> PubKeyHash -> m (Either APIError Value) +fundsAt :: forall m. PollContract m => ContractId -> PubKeyHash -> m (Either PollError Value) fundsAt = getAaveResponseWith (Endpoint "fundsAt") _FundsAt -poolFunds :: forall m. Contract m => Delay m => ContractId -> m (Either APIError Value) +poolFunds :: forall m. PollContract m => ContractId -> m (Either PollError Value) poolFunds cid = getAaveResponseWith (Endpoint "poolFunds") _PoolFunds cid ContractUnit -reserves :: forall m. Contract m => Delay m => ContractId -> m (Either APIError (Map AssetClass Reserve)) +reserves :: forall m. PollContract m => ContractId -> m (Either PollError (Map AssetClass Reserve)) reserves cid = getAaveResponseWith (Endpoint "reserves") _Reserves cid ContractUnit -users :: forall m. Contract m => Delay m => ContractId -> m (Either APIError (Map (JsonTuple AssetClass PubKeyHash) UserConfig)) +users :: forall m. PollContract m => ContractId -> m (Either PollError (Map (JsonTuple AssetClass PubKeyHash) UserConfig)) users cid = getAaveResponseWith (Endpoint "users") _Users cid ContractUnit -ownPubKey :: forall m. Contract m => Delay m => ContractId -> m (Either APIError PubKeyHash) +ownPubKey :: forall m. PollContract m => ContractId -> m (Either PollError PubKeyHash) ownPubKey cid = getAaveResponseWith (Endpoint "ownPubKey") _GetPubKey cid ContractUnit diff --git a/MetaLamp/lending-pool/client/src/Capability/Delay.purs b/MetaLamp/lending-pool/client/src/Capability/Delay.purs deleted file mode 100644 index 706e9770d..000000000 --- a/MetaLamp/lending-pool/client/src/Capability/Delay.purs +++ /dev/null @@ -1,12 +0,0 @@ -module Capability.Delay where - -import Prelude -import Data.Time.Duration (Milliseconds) -import Halogen (HalogenM, lift) - -class - Monad m <= Delay m where - delay :: Milliseconds -> m Unit - -instance delayHalogenM :: Delay m => Delay (HalogenM st act slots msg m) where - delay = delay >>> lift diff --git a/MetaLamp/lending-pool/client/src/Capability/PollContract.purs b/MetaLamp/lending-pool/client/src/Capability/PollContract.purs new file mode 100644 index 000000000..513b67fc9 --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Capability/PollContract.purs @@ -0,0 +1,66 @@ +module Capability.PollContract where + +import Prelude + +import Capability.Contract (class Contract, APIError(..), ContractId, Endpoint, callEndpoint, getContractStatus) +import Control.Monad.Except (runExceptT, throwError) +import Data.Either (Either(..), either) +import Data.Generic.Rep (class Generic) +import Data.Generic.Rep.Show (genericShow) +import Foreign.Generic (class Decode, class Encode) +import Halogen (HalogenM, lift) +import Plutus.PAB.Webserver.Types (ContractInstanceClientState) + +class Contract m <= PollContract m where + pollDelay :: m Unit + tooManyRetries :: Int -> m Boolean + +instance pollContractHalogenM :: PollContract m => PollContract (HalogenM st act slots msg m) where + pollDelay = lift pollDelay + tooManyRetries = lift <<< tooManyRetries + +data PollError = TooManyRetries | PollAPIError String | PollResponseError String + +derive instance genericPollError :: Generic PollError _ + +instance showPollError :: Show PollError where + show = genericShow + +data LeftPoll = Continue | ResponseError String + +type PollResponse a = Either LeftPoll a + +pollStatus :: forall m a c. + PollContract m => + Decode c => + (ContractInstanceClientState c -> PollResponse a) -> + Endpoint -> + ContractId -> + m (Either PollError a) +pollStatus = worker 0 + where + worker retryCount getNext endpoint cid = runExceptT $ do + limitExceeded <- lift $ tooManyRetries retryCount + when limitExceeded $ throwError TooManyRetries + _ <- lift pollDelay + status <- lift (getContractStatus cid) >>= either (throwError <<< toPollError) pure + case getNext status of + Left Continue -> lift (worker (retryCount + 1) getNext endpoint cid) >>= either throwError pure + Left (ResponseError e) -> throwError <<< PollResponseError $ e + Right s -> pure s + +pollEndpoint :: forall m a c p. + PollContract m => + Encode p => + Decode c => + (ContractInstanceClientState c -> PollResponse a) -> + Endpoint -> + p -> + ContractId -> + m (Either PollError a) +pollEndpoint getNext endpoint param cid = + callEndpoint endpoint cid param >>= + either (pure <<< Left <<< toPollError) (const $ pollStatus getNext endpoint cid) + +toPollError :: APIError -> PollError +toPollError (AjaxCallError e) = PollAPIError e diff --git a/MetaLamp/lending-pool/client/src/Components/App.purs b/MetaLamp/lending-pool/client/src/Components/App.purs index b2fefe0d6..698ff8968 100644 --- a/MetaLamp/lending-pool/client/src/Components/App.purs +++ b/MetaLamp/lending-pool/client/src/Components/App.purs @@ -1,10 +1,11 @@ module Components.App where import Prelude + import Business.Aave as Aave -import Capability.Contract (class Contract, ContractId(..)) -import Capability.Delay (class Delay) -import Capability.LogMessages (class LogMessages, logError, logInfo) +import Capability.Contract (ContractId(..)) +import Capability.LogMessages (class LogMessages, logError) +import Capability.PollContract (class PollContract) import Components.AmountForm as AmountForm import Control.Monad.Except (lift, runExceptT, throwError) import Data.Array (mapWithIndex) @@ -12,6 +13,8 @@ import Data.Bifunctor (bimap, lmap) import Data.BigInteger (BigInteger, fromInt) import Data.Either (Either(..), either) import Data.Foldable (find) +import Data.Generic.Rep (class Generic) +import Data.Generic.Rep.Show (genericShow) import Data.Json.JsonTuple (JsonTuple(..)) import Data.Json.JsonUUID (JsonUUID(..)) import Data.Maybe (Maybe(..)) @@ -72,6 +75,11 @@ data SubmitOperation | SubmitBorrow | SubmitRepay +derive instance genericSubmitOperation :: Generic SubmitOperation _ + +instance showSubmitOperation :: Show SubmitOperation where + show = genericShow + toContractIdParam :: ContractInstanceId -> ContractId toContractIdParam (ContractInstanceId { unContractInstanceId: JsonUUID uuid }) = ContractId <<< UUID.toString $ uuid @@ -86,8 +94,7 @@ _amountForm = SProxy :: SProxy "amountForm" component :: forall input m query output. LogMessages m => - Contract m => - Delay m => + PollContract m => H.Component HH.HTML query input output m component = H.mkComponent @@ -104,8 +111,8 @@ component = handleAction GetFunds GetContractAt wallet -> do H.modify_ _ { contractId = Loading } - instancesRD <- Aave.getAaveContracts - case instancesRD of + eInstances <- Aave.getAaveContracts + case eInstances of Left e -> H.modify_ _ { contractId = Failure (show e) } Right instances -> do let @@ -147,6 +154,7 @@ component = Deposit { amount, asset } -> handleException <=< runExceptT $ do + lift $ H.modify_ _ { lastStatus = Loading } state <- lift H.get { cid, pkh } <- RD.maybe (throwError "Failed to deposit") pure @@ -158,9 +166,10 @@ component = Withdraw { amount, asset } -> handleException <=< runExceptT $ do + lift $ H.modify_ _ { lastStatus = Loading } state <- lift H.get { cid, pkh } <- - RD.maybe (throwError "Failed to deposit") pure + RD.maybe (throwError "Failed to withdraw") pure $ { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey @@ -169,9 +178,10 @@ component = Borrow { amount, asset } -> handleException <=< runExceptT $ do + lift $ H.modify_ _ { lastStatus = Loading } state <- lift H.get { cid, pkh } <- - RD.maybe (throwError "Failed to deposit") pure + RD.maybe (throwError "Failed to borrow") pure $ { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey @@ -180,9 +190,10 @@ component = Repay { amount, asset } -> handleException <=< runExceptT $ do + lift $ H.modify_ _ { lastStatus = Loading } state <- lift H.get { cid, pkh } <- - RD.maybe (throwError "Failed to deposit") pure + RD.maybe (throwError "Failed to repay") pure $ { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey @@ -200,6 +211,8 @@ component = SubmitWithdraw -> lift $ handleAction (Withdraw { amount, asset }) SubmitBorrow -> lift $ handleAction (Borrow { amount, asset }) SubmitRepay -> lift $ handleAction (Repay { amount, asset }) + lastStatus <- lift $ H.gets _.lastStatus + _ <- RD.maybe (throwError $ show operation <> " has failed: " <> show lastStatus) pure $ lastStatus lift $ handleAction GetFunds Nothing -> throwError "Asset name not found" From ca32682f6819e54bc317709efa4816245a64e289 Mon Sep 17 00:00:00 2001 From: megakaban Date: Thu, 10 Jun 2021 02:29:46 +0700 Subject: [PATCH 084/169] Improve remoteData/error handling --- MetaLamp/lending-pool/client/src/AppAff.purs | 3 +- .../client/src/Business/Aave.purs | 29 ++-- .../client/src/Capability/PollContract.purs | 46 +++-- .../client/src/Components/App.purs | 163 +++++++++++++----- .../client/src/Utils/WithRemoteData.purs | 31 ++++ 5 files changed, 195 insertions(+), 77 deletions(-) create mode 100644 MetaLamp/lending-pool/client/src/Utils/WithRemoteData.purs diff --git a/MetaLamp/lending-pool/client/src/AppAff.purs b/MetaLamp/lending-pool/client/src/AppAff.purs index 4fbebdf4c..bcf9bb8f6 100644 --- a/MetaLamp/lending-pool/client/src/AppAff.purs +++ b/MetaLamp/lending-pool/client/src/AppAff.purs @@ -1,7 +1,6 @@ module AppAff where import Prelude - import Affjax (Response, defaultRequest) import Affjax.RequestBody (RequestBody, string) import Capability.Contract (class Contract, ContractId(..), Endpoint(..), APIError(..)) @@ -53,7 +52,7 @@ instance logMessagesAppM :: LogMessages AppM where errorToString :: AjaxError -> String errorToString (AjaxError e) = case e.description of - ResponseError _ _ -> "Response error" + ResponseError _ r -> "Response error: " <> r ResponseFormatError s -> "Parsing error: " <> s DecodingError s -> "Decoding error: " <> s ConnectionError s -> "Connection error: " <> s diff --git a/MetaLamp/lending-pool/client/src/Business/Aave.purs b/MetaLamp/lending-pool/client/src/Business/Aave.purs index 9fdfe8fae..3bfced0c1 100644 --- a/MetaLamp/lending-pool/client/src/Business/Aave.purs +++ b/MetaLamp/lending-pool/client/src/Business/Aave.purs @@ -1,7 +1,6 @@ module Business.Aave where import Prelude - import Capability.Contract (class Contract, ContractId, APIError, ContractUnit(..), Endpoint(..), getContracts) import Capability.PollContract (class PollContract, LeftPoll(..), PollError, PollResponse, pollEndpoint) import Control.Monad.Except (runExcept, throwError, withExcept) @@ -23,7 +22,8 @@ import PlutusTx.AssocMap (Map) getAaveContracts :: forall m. Contract m => m (Either APIError (Array (ContractInstanceClientState AaveContracts))) getAaveContracts = getContracts -getAaveResponseWith :: forall m a p. +getAaveResponseWith :: + forall m a p. PollContract m => Encode p => Endpoint -> @@ -33,18 +33,19 @@ getAaveResponseWith :: forall m a p. m (Either PollError a) getAaveResponseWith endpoint pick cid param = pollEndpoint getNext endpoint param cid where - getNext :: ContractInstanceClientState AaveContracts -> PollResponse a - getNext (ContractInstanceClientState { cicCurrentState: PartiallyDecodedResponse { observableState: RawJson s } }) = - runExcept $ do - (response :: Either String UserContractState) <- withExcept (ResponseError <<< show) (decodeJSON s) - state <- either (throwError <<< ResponseError <<< show) pure response - case (preview _Pending state) of - Just _ -> throwError Continue - Nothing -> - maybe - (throwError <<< ResponseError $ "Invalid state: " <> (show state)) - pure - (preview pick state) + getNext :: ContractInstanceClientState AaveContracts -> PollResponse a + getNext (ContractInstanceClientState { cicCurrentState: PartiallyDecodedResponse { observableState: RawJson s } }) = + runExcept + $ do + (response :: Either String UserContractState) <- withExcept (ResponseError <<< show) (decodeJSON s) + state <- either (throwError <<< ResponseError <<< show) pure response + case (preview _Pending state) of + Just _ -> throwError Continue + Nothing -> + maybe + (throwError <<< ResponseError $ "Invalid state: " <> (show state)) + pure + (preview pick state) deposit :: forall m. PollContract m => ContractId -> DepositParams -> m (Either PollError Unit) deposit = getAaveResponseWith (Endpoint "deposit") _Deposited diff --git a/MetaLamp/lending-pool/client/src/Capability/PollContract.purs b/MetaLamp/lending-pool/client/src/Capability/PollContract.purs index 513b67fc9..00e5aad0b 100644 --- a/MetaLamp/lending-pool/client/src/Capability/PollContract.purs +++ b/MetaLamp/lending-pool/client/src/Capability/PollContract.purs @@ -1,7 +1,6 @@ module Capability.PollContract where import Prelude - import Capability.Contract (class Contract, APIError(..), ContractId, Endpoint, callEndpoint, getContractStatus) import Control.Monad.Except (runExceptT, throwError) import Data.Either (Either(..), either) @@ -11,7 +10,8 @@ import Foreign.Generic (class Decode, class Encode) import Halogen (HalogenM, lift) import Plutus.PAB.Webserver.Types (ContractInstanceClientState) -class Contract m <= PollContract m where +class + Contract m <= PollContract m where pollDelay :: m Unit tooManyRetries :: Int -> m Boolean @@ -19,18 +19,25 @@ instance pollContractHalogenM :: PollContract m => PollContract (HalogenM st act pollDelay = lift pollDelay tooManyRetries = lift <<< tooManyRetries -data PollError = TooManyRetries | PollAPIError String | PollResponseError String +data PollError + = TooManyRetries + | PollAPIError String + | PollResponseError String derive instance genericPollError :: Generic PollError _ instance showPollError :: Show PollError where show = genericShow -data LeftPoll = Continue | ResponseError String +data LeftPoll + = Continue + | ResponseError String -type PollResponse a = Either LeftPoll a +type PollResponse a + = Either LeftPoll a -pollStatus :: forall m a c. +pollStatus :: + forall m a c. PollContract m => Decode c => (ContractInstanceClientState c -> PollResponse a) -> @@ -39,17 +46,20 @@ pollStatus :: forall m a c. m (Either PollError a) pollStatus = worker 0 where - worker retryCount getNext endpoint cid = runExceptT $ do - limitExceeded <- lift $ tooManyRetries retryCount - when limitExceeded $ throwError TooManyRetries - _ <- lift pollDelay - status <- lift (getContractStatus cid) >>= either (throwError <<< toPollError) pure - case getNext status of - Left Continue -> lift (worker (retryCount + 1) getNext endpoint cid) >>= either throwError pure - Left (ResponseError e) -> throwError <<< PollResponseError $ e - Right s -> pure s + worker retryCount getNext endpoint cid = + runExceptT + $ do + limitExceeded <- lift $ tooManyRetries retryCount + when limitExceeded $ throwError TooManyRetries + _ <- lift pollDelay + status <- lift (getContractStatus cid) >>= either (throwError <<< toPollError) pure + case getNext status of + Left Continue -> lift (worker (retryCount + 1) getNext endpoint cid) >>= either throwError pure + Left (ResponseError e) -> throwError <<< PollResponseError $ e + Right s -> pure s -pollEndpoint :: forall m a c p. +pollEndpoint :: + forall m a c p. PollContract m => Encode p => Decode c => @@ -59,8 +69,8 @@ pollEndpoint :: forall m a c p. ContractId -> m (Either PollError a) pollEndpoint getNext endpoint param cid = - callEndpoint endpoint cid param >>= - either (pure <<< Left <<< toPollError) (const $ pollStatus getNext endpoint cid) + callEndpoint endpoint cid param + >>= either (pure <<< Left <<< toPollError) (const $ pollStatus getNext endpoint cid) toPollError :: APIError -> PollError toPollError (AjaxCallError e) = PollAPIError e diff --git a/MetaLamp/lending-pool/client/src/Components/App.purs b/MetaLamp/lending-pool/client/src/Components/App.purs index 698ff8968..7be425955 100644 --- a/MetaLamp/lending-pool/client/src/Components/App.purs +++ b/MetaLamp/lending-pool/client/src/Components/App.purs @@ -1,7 +1,6 @@ module Components.App where import Prelude - import Business.Aave as Aave import Capability.Contract (ContractId(..)) import Capability.LogMessages (class LogMessages, logError) @@ -17,7 +16,9 @@ import Data.Generic.Rep (class Generic) import Data.Generic.Rep.Show (genericShow) import Data.Json.JsonTuple (JsonTuple(..)) import Data.Json.JsonUUID (JsonUUID(..)) -import Data.Maybe (Maybe(..)) +import Data.Lens (Lens') +import Data.Lens.Record (prop) +import Data.Maybe (Maybe(..), maybe) import Data.Symbol (SProxy(..)) import Data.Tuple (Tuple(..)) import Data.UUID (toString) as UUID @@ -32,6 +33,7 @@ import Plutus.PAB.Webserver.Types (ContractInstanceClientState(..)) import Plutus.V1.Ledger.Crypto (PubKeyHash) import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..), Value) import PlutusTx.AssocMap as Map +import Utils.WithRemoteData (withRemoteData') import View.FundsTable (fundsTable) import View.RemoteDataState (remoteDataState) import View.ReserveInfo (reserveInfo) @@ -43,16 +45,48 @@ type State , walletPubKey :: RemoteData String PubKeyHash , userFunds :: RemoteData String Value , reserves :: RemoteData String (Map.Map AssetClass Reserve) - , lastStatus :: RemoteData String String + , deposit :: RemoteData String Unit + , withdraw :: RemoteData String Unit + , borrow :: RemoteData String Unit + , repay :: RemoteData String Unit + , lastError :: Maybe String } +_contractId :: Lens' State (RemoteData String ContractId) +_contractId = prop (SProxy :: SProxy "contractId") + +_walletPubKey :: Lens' State (RemoteData String PubKeyHash) +_walletPubKey = prop (SProxy :: SProxy "walletPubKey") + +_userFunds :: Lens' State (RemoteData String Value) +_userFunds = prop (SProxy :: SProxy "userFunds") + +_reserves :: Lens' State (RemoteData String (Map.Map AssetClass Reserve)) +_reserves = prop (SProxy :: SProxy "reserves") + +_deposit :: Lens' State (RemoteData String Unit) +_deposit = prop (SProxy :: SProxy "deposit") + +_withdraw :: Lens' State (RemoteData String Unit) +_withdraw = prop (SProxy :: SProxy "withdraw") + +_borrow :: Lens' State (RemoteData String Unit) +_borrow = prop (SProxy :: SProxy "borrow") + +_repay :: Lens' State (RemoteData String Unit) +_repay = prop (SProxy :: SProxy "repay") + initialState :: forall input. input -> State initialState _ = { contractId: NotAsked , walletPubKey: NotAsked , userFunds: NotAsked , reserves: NotAsked - , lastStatus: NotAsked + , withdraw: NotAsked + , deposit: NotAsked + , borrow: NotAsked + , repay: NotAsked + , lastError: Nothing } data Action @@ -103,102 +137,127 @@ component = , eval: H.mkEval H.defaultEval { handleAction = handleAction } } where + withRemoteData :: + forall e a action slots. + Show e => + (Lens' State (RemoteData e a)) -> + H.HalogenM State action slots output m (RemoteData e a) -> + H.HalogenM State action slots output m Unit + withRemoteData = + withRemoteData' + $ { before: H.modify_ _ { lastError = Nothing } + , after: + case _ of + Failure e -> do + logError $ "Remote data failure: " <> show e + H.modify_ _ { lastError = Just <<< show $ e } + _ -> pure unit + } + handleAction :: Action -> H.HalogenM State Action Slots output m Unit handleAction = case _ of Init -> do handleAction (GetContractAt $ Wallet { getWallet: fromInt 2 }) handleAction GetWalletPubKey handleAction GetFunds - GetContractAt wallet -> do - H.modify_ _ { contractId = Loading } - eInstances <- Aave.getAaveContracts - case eInstances of - Left e -> H.modify_ _ { contractId = Failure (show e) } - Right instances -> do - let - contract = find (\(ContractInstanceClientState i) -> i.cicWallet == wallet) instances - case contract of - Nothing -> H.modify_ _ { contractId = Failure "Contract instance not found" } - Just (ContractInstanceClientState i) -> H.modify_ _ { contractId = Success (toContractIdParam i.cicContract) } + GetContractAt wallet -> + withRemoteData _contractId + $ do + eInstances <- Aave.getAaveContracts + case eInstances of + Left e -> pure <<< Failure <<< show $ e + Right instances -> do + let + contract = find (\(ContractInstanceClientState i) -> i.cicWallet == wallet) instances + case contract of + Nothing -> pure <<< Failure $ "Contract instance not found" + Just (ContractInstanceClientState i) -> pure <<< Success <<< toContractIdParam $ i.cicContract GetWalletPubKey -> handleException <=< runExceptT $ do - lift $ H.modify_ _ { walletPubKey = Loading } state <- lift H.get cid <- RD.maybe (throwError "Failed to get wallet public key") pure $ state.contractId - pkh <- lift $ Aave.ownPubKey cid - lift $ H.modify_ _ { walletPubKey = fromEither <<< lmap show $ pkh } + lift $ withRemoteData _walletPubKey + $ fromEither + <<< lmap show + <$> Aave.ownPubKey cid GetUserFunds -> handleException <=< runExceptT $ do - lift $ H.modify_ _ { userFunds = Loading } state <- lift H.get { cid, pkh } <- RD.maybe (throwError "Failed to get user funds") pure $ { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - funds <- lift $ Aave.fundsAt cid pkh - lift $ H.modify_ _ { userFunds = fromEither <<< lmap show $ funds } + lift $ withRemoteData _userFunds + $ fromEither + <<< lmap show + <$> Aave.fundsAt cid pkh GetReserves -> handleException <=< runExceptT $ do - lift $ H.modify_ _ { reserves = Loading } state <- lift H.get cid <- RD.maybe (throwError "Failed to get reserves") pure $ state.contractId - reserves <- lift $ Aave.reserves cid - lift $ H.modify_ _ { reserves = fromEither <<< lmap show $ reserves } + lift $ withRemoteData _reserves + $ fromEither + <<< lmap show + <$> Aave.reserves cid GetFunds -> do handleAction GetUserFunds handleAction GetReserves Deposit { amount, asset } -> handleException <=< runExceptT $ do - lift $ H.modify_ _ { lastStatus = Loading } state <- lift H.get { cid, pkh } <- RD.maybe (throwError "Failed to deposit") pure $ { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - res <- lift $ Aave.deposit cid $ DepositParams { dpAmount: amount, dpAsset: asset, dpOnBehalfOf: pkh } - lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } + lift $ withRemoteData _deposit + $ fromEither + <<< bimap show (const unit) + <$> (Aave.deposit cid $ DepositParams { dpAmount: amount, dpAsset: asset, dpOnBehalfOf: pkh }) Withdraw { amount, asset } -> handleException <=< runExceptT $ do - lift $ H.modify_ _ { lastStatus = Loading } state <- lift H.get { cid, pkh } <- RD.maybe (throwError "Failed to withdraw") pure $ { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - res <- lift $ Aave.withdraw cid $ WithdrawParams { wpAmount: amount, wpAsset: asset, wpUser: pkh } - lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } + lift $ withRemoteData _withdraw + $ fromEither + <<< bimap show (const unit) + <$> (Aave.withdraw cid $ WithdrawParams { wpAmount: amount, wpAsset: asset, wpUser: pkh }) Borrow { amount, asset } -> handleException <=< runExceptT $ do - lift $ H.modify_ _ { lastStatus = Loading } state <- lift H.get { cid, pkh } <- RD.maybe (throwError "Failed to borrow") pure $ { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - res <- lift $ Aave.borrow cid $ BorrowParams { bpAmount: amount, bpAsset: asset, bpOnBehalfOf: pkh } - lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } + lift $ withRemoteData _withdraw + $ fromEither + <<< bimap show (const unit) + <$> (Aave.borrow cid $ BorrowParams { bpAmount: amount, bpAsset: asset, bpOnBehalfOf: pkh }) Repay { amount, asset } -> handleException <=< runExceptT $ do - lift $ H.modify_ _ { lastStatus = Loading } state <- lift H.get { cid, pkh } <- RD.maybe (throwError "Failed to repay") pure $ { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - res <- lift $ Aave.repay cid $ RepayParams { rpAmount: amount, rpAsset: asset, rpOnBehalfOf: pkh } - lift $ H.modify_ _ { lastStatus = fromEither <<< bimap show show $ res } + lift $ withRemoteData _withdraw + $ fromEither + <<< bimap show (const unit) + <$> (Aave.repay cid $ RepayParams { rpAmount: amount, rpAsset: asset, rpOnBehalfOf: pkh }) SubmitAmount operation (AmountForm.Submit { name, amount }) -> handleException <=< runExceptT $ do @@ -207,19 +266,37 @@ component = case find (\(Tuple k _) -> getAssetName k == name) (Map.toTuples reserves) of Just (Tuple asset _) -> do case operation of - SubmitDeposit -> lift $ handleAction (Deposit { amount, asset }) - SubmitWithdraw -> lift $ handleAction (Withdraw { amount, asset }) - SubmitBorrow -> lift $ handleAction (Borrow { amount, asset }) - SubmitRepay -> lift $ handleAction (Repay { amount, asset }) - lastStatus <- lift $ H.gets _.lastStatus - _ <- RD.maybe (throwError $ show operation <> " has failed: " <> show lastStatus) pure $ lastStatus - lift $ handleAction GetFunds + SubmitDeposit -> + lift + $ do + handleAction (Deposit { amount, asset }) + (H.gets _.deposit) + >>= RD.maybe (pure unit) (const <<< handleAction $ GetFunds) + SubmitWithdraw -> + lift + $ do + handleAction (Withdraw { amount, asset }) + (H.gets _.withdraw) + >>= RD.maybe (pure unit) (const <<< handleAction $ GetFunds) + SubmitBorrow -> + lift + $ do + handleAction (Borrow { amount, asset }) + (H.gets _.borrow) + >>= RD.maybe (pure unit) (const <<< handleAction $ GetFunds) + SubmitRepay -> + lift + $ do + handleAction (Repay { amount, asset }) + (H.gets _.repay) + >>= RD.maybe (pure unit) (const <<< handleAction $ GetFunds) Nothing -> throwError "Asset name not found" render :: State -> H.ComponentHTML Action Slots m render state = HH.div_ [ HH.button [ HE.onClick \_ -> Just Init ] [ HH.text "Start" ] + , maybe (HH.div_ []) (\e -> HH.h2_ [ HH.text $ "Error: " <> e ]) state.lastError , remoteDataState (\userFunds -> HH.div_ [ HH.h2_ [ HH.text "User funds" ], fundsTable userFunds ]) state.userFunds diff --git a/MetaLamp/lending-pool/client/src/Utils/WithRemoteData.purs b/MetaLamp/lending-pool/client/src/Utils/WithRemoteData.purs new file mode 100644 index 000000000..1fd9cb991 --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Utils/WithRemoteData.purs @@ -0,0 +1,31 @@ +module Utils.WithRemoteData where + +import Prelude +import Data.Lens (Lens', set) +import Halogen as H +import Network.RemoteData (RemoteData(..)) + +withRemoteData :: + forall e a s action slots output m. + (Lens' s (RemoteData e a)) -> + H.HalogenM s action slots output m (RemoteData e a) -> + H.HalogenM s action slots output m Unit +withRemoteData = + withRemoteData' + $ { before: pure unit, after: (const <<< pure $ unit) } + +withRemoteData' :: + forall e a s action slots output m. + { before :: H.HalogenM s action slots output m Unit + , after :: RemoteData e a -> H.HalogenM s action slots output m Unit + } -> + (Lens' s (RemoteData e a)) -> + H.HalogenM s action slots output m (RemoteData e a) -> + H.HalogenM s action slots output m Unit +withRemoteData' { before, after } l action = do + state <- H.get + H.put $ set l Loading state + before + result <- action + H.put $ set l result state + after result From 05006b5c6c5cf5e60e2cdefb56cf81695e459fed Mon Sep 17 00:00:00 2001 From: megakaban Date: Thu, 10 Jun 2021 16:54:52 +0700 Subject: [PATCH 085/169] Redo remoteData handling --- .../client/src/Components/App.purs | 176 ++++++++---------- .../client/src/Utils/RemoteDataState.purs | 20 -- .../client/src/Utils/WithRemoteData.purs | 33 +--- .../client/src/View/RemoteDataState.purs | 15 +- 4 files changed, 91 insertions(+), 153 deletions(-) delete mode 100644 MetaLamp/lending-pool/client/src/Utils/RemoteDataState.purs diff --git a/MetaLamp/lending-pool/client/src/Components/App.purs b/MetaLamp/lending-pool/client/src/Components/App.purs index 7be425955..1de67c54a 100644 --- a/MetaLamp/lending-pool/client/src/Components/App.purs +++ b/MetaLamp/lending-pool/client/src/Components/App.purs @@ -8,9 +8,8 @@ import Capability.PollContract (class PollContract) import Components.AmountForm as AmountForm import Control.Monad.Except (lift, runExceptT, throwError) import Data.Array (mapWithIndex) -import Data.Bifunctor (bimap, lmap) import Data.BigInteger (BigInteger, fromInt) -import Data.Either (Either(..), either) +import Data.Either (Either, either) import Data.Foldable (find) import Data.Generic.Rep (class Generic) import Data.Generic.Rep.Show (genericShow) @@ -19,13 +18,14 @@ import Data.Json.JsonUUID (JsonUUID(..)) import Data.Lens (Lens') import Data.Lens.Record (prop) import Data.Maybe (Maybe(..), maybe) +import Data.Newtype (unwrap) import Data.Symbol (SProxy(..)) import Data.Tuple (Tuple(..)) import Data.UUID (toString) as UUID import Halogen as H import Halogen.HTML as HH import Halogen.HTML.Events as HE -import Network.RemoteData (RemoteData(..), fromEither) +import Network.RemoteData (RemoteData(..)) import Network.RemoteData as RD import Plutus.Contracts.Core (Reserve(..)) import Plutus.Contracts.Endpoints (BorrowParams(..), DepositParams(..), RepayParams(..), WithdrawParams(..)) @@ -33,7 +33,7 @@ import Plutus.PAB.Webserver.Types (ContractInstanceClientState(..)) import Plutus.V1.Ledger.Crypto (PubKeyHash) import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..), Value) import PlutusTx.AssocMap as Map -import Utils.WithRemoteData (withRemoteData') +import Utils.WithRemoteData (runRDWith) import View.FundsTable (fundsTable) import View.RemoteDataState (remoteDataState) import View.ReserveInfo (reserveInfo) @@ -49,7 +49,7 @@ type State , withdraw :: RemoteData String Unit , borrow :: RemoteData String Unit , repay :: RemoteData String Unit - , lastError :: Maybe String + , submit :: RemoteData String Unit } _contractId :: Lens' State (RemoteData String ContractId) @@ -76,6 +76,9 @@ _borrow = prop (SProxy :: SProxy "borrow") _repay :: Lens' State (RemoteData String Unit) _repay = prop (SProxy :: SProxy "repay") +_submit :: Lens' State (RemoteData String Unit) +_submit = prop (SProxy :: SProxy "submit") + initialState :: forall input. input -> State initialState _ = { contractId: NotAsked @@ -86,7 +89,7 @@ initialState _ = , deposit: NotAsked , borrow: NotAsked , repay: NotAsked - , lastError: Nothing + , submit: NotAsked } data Action @@ -137,22 +140,17 @@ component = , eval: H.mkEval H.defaultEval { handleAction = handleAction } } where - withRemoteData :: - forall e a action slots. + runRD :: + forall e a. Show e => (Lens' State (RemoteData e a)) -> - H.HalogenM State action slots output m (RemoteData e a) -> - H.HalogenM State action slots output m Unit - withRemoteData = - withRemoteData' - $ { before: H.modify_ _ { lastError = Nothing } - , after: - case _ of - Failure e -> do - logError $ "Remote data failure: " <> show e - H.modify_ _ { lastError = Just <<< show $ e } - _ -> pure unit - } + H.HalogenM State Action Slots output m (Either e a) -> + H.HalogenM State Action Slots output m Unit + runRD selector action = + (runRDWith selector $ action) + >>= case _ of + Failure e -> logError <<< show $ e + _ -> pure unit handleAction :: Action -> H.HalogenM State Action Slots output m Unit handleAction = case _ of @@ -161,142 +159,113 @@ component = handleAction GetWalletPubKey handleAction GetFunds GetContractAt wallet -> - withRemoteData _contractId + runRD _contractId <<< runExceptT $ do - eInstances <- Aave.getAaveContracts - case eInstances of - Left e -> pure <<< Failure <<< show $ e - Right instances -> do - let - contract = find (\(ContractInstanceClientState i) -> i.cicWallet == wallet) instances - case contract of - Nothing -> pure <<< Failure $ "Contract instance not found" - Just (ContractInstanceClientState i) -> pure <<< Success <<< toContractIdParam $ i.cicContract + instances <- lift Aave.getAaveContracts >>= either (throwError <<< show) pure + let + contract = find (\(ContractInstanceClientState i) -> i.cicWallet == wallet) instances + maybe + (throwError "Contract instance not found") + (pure <<< toContractIdParam <<< _.cicContract <<< unwrap) + contract GetWalletPubKey -> - handleException <=< runExceptT + runRD _walletPubKey <<< runExceptT $ do state <- lift H.get - cid <- RD.maybe (throwError "Failed to get wallet public key") pure $ state.contractId - lift $ withRemoteData _walletPubKey - $ fromEither - <<< lmap show - <$> Aave.ownPubKey cid + cid <- RD.maybe (throwError "contractId is missing") pure state.contractId + lift (Aave.ownPubKey cid) >>= either (throwError <<< show) pure GetUserFunds -> - handleException <=< runExceptT + runRD _userFunds <<< runExceptT $ do state <- lift H.get { cid, pkh } <- - RD.maybe (throwError "Failed to get user funds") pure + RD.maybe (throwError "contractId or publicKey are missing") pure $ { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - lift $ withRemoteData _userFunds - $ fromEither - <<< lmap show - <$> Aave.fundsAt cid pkh + lift (Aave.fundsAt cid pkh) >>= either (throwError <<< show) pure GetReserves -> - handleException <=< runExceptT + runRD _reserves <<< runExceptT $ do state <- lift H.get - cid <- RD.maybe (throwError "Failed to get reserves") pure $ state.contractId - lift $ withRemoteData _reserves - $ fromEither - <<< lmap show - <$> Aave.reserves cid + cid <- RD.maybe (throwError "contractId or publicKey are missing") pure $ state.contractId + lift (Aave.reserves cid) >>= either (throwError <<< show) pure GetFunds -> do handleAction GetUserFunds handleAction GetReserves Deposit { amount, asset } -> - handleException <=< runExceptT + runRD _deposit <<< runExceptT $ do state <- lift H.get { cid, pkh } <- - RD.maybe (throwError "Failed to deposit") pure + RD.maybe (throwError "contractId or publicKey are missing") pure $ { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - lift $ withRemoteData _deposit - $ fromEither - <<< bimap show (const unit) - <$> (Aave.deposit cid $ DepositParams { dpAmount: amount, dpAsset: asset, dpOnBehalfOf: pkh }) + lift (Aave.deposit cid $ DepositParams { dpAmount: amount, dpAsset: asset, dpOnBehalfOf: pkh }) + >>= either (throwError <<< show) (const <<< pure $ unit) Withdraw { amount, asset } -> - handleException <=< runExceptT + runRD _deposit <<< runExceptT $ do state <- lift H.get { cid, pkh } <- - RD.maybe (throwError "Failed to withdraw") pure + RD.maybe (throwError "contractId or publicKey are missing") pure $ { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - lift $ withRemoteData _withdraw - $ fromEither - <<< bimap show (const unit) - <$> (Aave.withdraw cid $ WithdrawParams { wpAmount: amount, wpAsset: asset, wpUser: pkh }) + lift (Aave.withdraw cid $ WithdrawParams { wpAmount: amount, wpAsset: asset, wpUser: pkh }) + >>= either (throwError <<< show) (const <<< pure $ unit) Borrow { amount, asset } -> - handleException <=< runExceptT + runRD _deposit <<< runExceptT $ do state <- lift H.get { cid, pkh } <- - RD.maybe (throwError "Failed to borrow") pure + RD.maybe (throwError "contractId or publicKey are missing") pure $ { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - lift $ withRemoteData _withdraw - $ fromEither - <<< bimap show (const unit) - <$> (Aave.borrow cid $ BorrowParams { bpAmount: amount, bpAsset: asset, bpOnBehalfOf: pkh }) + lift (Aave.borrow cid $ BorrowParams { bpAmount: amount, bpAsset: asset, bpOnBehalfOf: pkh }) + >>= either (throwError <<< show) (const <<< pure $ unit) Repay { amount, asset } -> - handleException <=< runExceptT + runRD _deposit <<< runExceptT $ do state <- lift H.get { cid, pkh } <- - RD.maybe (throwError "Failed to repay") pure + RD.maybe (throwError "contractId or publicKey are missing") pure $ { cid: _, pkh: _ } <$> state.contractId <*> state.walletPubKey - lift $ withRemoteData _withdraw - $ fromEither - <<< bimap show (const unit) - <$> (Aave.repay cid $ RepayParams { rpAmount: amount, rpAsset: asset, rpOnBehalfOf: pkh }) + lift (Aave.repay cid $ RepayParams { rpAmount: amount, rpAsset: asset, rpOnBehalfOf: pkh }) + >>= either (throwError <<< show) (const <<< pure $ unit) SubmitAmount operation (AmountForm.Submit { name, amount }) -> - handleException <=< runExceptT + runRD _submit <<< runExceptT $ do state <- lift H.get - reserves <- RD.maybe (throwError "Failed to submit") pure $ state.reserves + reserves <- RD.maybe (throwError "reserves are missing") pure $ state.reserves case find (\(Tuple k _) -> getAssetName k == name) (Map.toTuples reserves) of - Just (Tuple asset _) -> do - case operation of - SubmitDeposit -> - lift - $ do - handleAction (Deposit { amount, asset }) - (H.gets _.deposit) - >>= RD.maybe (pure unit) (const <<< handleAction $ GetFunds) - SubmitWithdraw -> - lift - $ do - handleAction (Withdraw { amount, asset }) - (H.gets _.withdraw) - >>= RD.maybe (pure unit) (const <<< handleAction $ GetFunds) - SubmitBorrow -> - lift - $ do - handleAction (Borrow { amount, asset }) - (H.gets _.borrow) - >>= RD.maybe (pure unit) (const <<< handleAction $ GetFunds) - SubmitRepay -> - lift - $ do - handleAction (Repay { amount, asset }) - (H.gets _.repay) - >>= RD.maybe (pure unit) (const <<< handleAction $ GetFunds) + Just (Tuple asset _) -> case operation of + SubmitDeposit -> do + lift $ handleAction (Deposit { amount, asset }) + lift (H.gets _.deposit) + >>= RD.maybe (throwError "Submit deposit failed") (const <<< lift <<< handleAction $ GetFunds) + SubmitWithdraw -> do + lift $ handleAction (Withdraw { amount, asset }) + lift (H.gets _.withdraw) + >>= RD.maybe (throwError "Submit withdraw failed") (const <<< lift <<< handleAction $ GetFunds) + SubmitBorrow -> do + lift $ handleAction (Borrow { amount, asset }) + lift (H.gets _.borrow) + >>= RD.maybe (throwError "Submit borrow failed") (const <<< lift <<< handleAction $ GetFunds) + SubmitRepay -> do + lift $ handleAction (Repay { amount, asset }) + lift (H.gets _.repay) + >>= RD.maybe (throwError "Submit repay failed") (const <<< lift <<< handleAction $ GetFunds) Nothing -> throwError "Asset name not found" render :: State -> H.ComponentHTML Action Slots m render state = HH.div_ [ HH.button [ HE.onClick \_ -> Just Init ] [ HH.text "Start" ] - , maybe (HH.div_ []) (\e -> HH.h2_ [ HH.text $ "Error: " <> e ]) state.lastError , remoteDataState (\userFunds -> HH.div_ [ HH.h2_ [ HH.text "User funds" ], fundsTable userFunds ]) state.userFunds @@ -307,6 +276,11 @@ component = <> map (\(Tuple a r) -> reserveInfo a r) reserves ) (map Map.toTuples state.reserves) + , case state.submit of + NotAsked -> HH.div_ [] + Loading -> HH.div_ [] + Failure e -> HH.h2_ [ HH.text $ "Error: " <> show e ] + Success _ -> HH.div_ [] , remoteDataState ( \amounts -> HH.div_ diff --git a/MetaLamp/lending-pool/client/src/Utils/RemoteDataState.purs b/MetaLamp/lending-pool/client/src/Utils/RemoteDataState.purs deleted file mode 100644 index 2f50684d3..000000000 --- a/MetaLamp/lending-pool/client/src/Utils/RemoteDataState.purs +++ /dev/null @@ -1,20 +0,0 @@ -module Utils.RemoteDataState where - -import Halogen.HTML as HH -import Network.RemoteData (RemoteData(..)) - -type RemoteDataHandle props act e a - = { onNotAsked :: HH.HTML props act - , onLoading :: HH.HTML props act - , onFailure :: e -> HH.HTML props act - , onSuccess :: a -> HH.HTML props act - } - -makeRemoteDataState :: forall props act e a. RemoteDataHandle props act e a -> RemoteData e a -> HH.HTML props act -makeRemoteDataState { onNotAsked } NotAsked = onNotAsked - -makeRemoteDataState { onLoading } Loading = onLoading - -makeRemoteDataState { onFailure } (Failure e) = onFailure e - -makeRemoteDataState { onSuccess } (Success s) = onSuccess s diff --git a/MetaLamp/lending-pool/client/src/Utils/WithRemoteData.purs b/MetaLamp/lending-pool/client/src/Utils/WithRemoteData.purs index 1fd9cb991..40769eb29 100644 --- a/MetaLamp/lending-pool/client/src/Utils/WithRemoteData.purs +++ b/MetaLamp/lending-pool/client/src/Utils/WithRemoteData.purs @@ -1,31 +1,18 @@ module Utils.WithRemoteData where import Prelude -import Data.Lens (Lens', set) +import Data.Either (Either, either) +import Data.Lens (Lens', over) import Halogen as H import Network.RemoteData (RemoteData(..)) -withRemoteData :: +runRDWith :: forall e a s action slots output m. (Lens' s (RemoteData e a)) -> - H.HalogenM s action slots output m (RemoteData e a) -> - H.HalogenM s action slots output m Unit -withRemoteData = - withRemoteData' - $ { before: pure unit, after: (const <<< pure $ unit) } - -withRemoteData' :: - forall e a s action slots output m. - { before :: H.HalogenM s action slots output m Unit - , after :: RemoteData e a -> H.HalogenM s action slots output m Unit - } -> - (Lens' s (RemoteData e a)) -> - H.HalogenM s action slots output m (RemoteData e a) -> - H.HalogenM s action slots output m Unit -withRemoteData' { before, after } l action = do - state <- H.get - H.put $ set l Loading state - before - result <- action - H.put $ set l result state - after result + H.HalogenM s action slots output m (Either e a) -> + H.HalogenM s action slots output m (RemoteData e a) +runRDWith l action = do + H.modify_ $ over l (const Loading) + result <- either Failure Success <$> action + H.modify_ $ over l (const result) + pure result diff --git a/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs b/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs index 714a2ef1e..a59444fee 100644 --- a/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs +++ b/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs @@ -2,14 +2,11 @@ module View.RemoteDataState where import Prelude import Halogen.HTML as HH -import Network.RemoteData (RemoteData) -import Utils.RemoteDataState (makeRemoteDataState) +import Network.RemoteData (RemoteData(..)) remoteDataState :: forall props act e a. Show e => (a -> HH.HTML props act) -> RemoteData e a -> HH.HTML props act -remoteDataState onSuccess = - makeRemoteDataState - { onNotAsked: HH.div_ [ HH.text "" ] - , onLoading: HH.div_ [ HH.text "Loading..." ] - , onFailure: \e -> HH.div_ [ HH.text $ "Error: " <> show e ] - , onSuccess - } +remoteDataState onSuccess = case _ of + NotAsked -> HH.div_ [ HH.text "" ] + Loading -> HH.div_ [ HH.text "Loading..." ] + Failure e -> HH.div_ [ HH.text $ "Error: " <> show e ] + Success a -> onSuccess a From 90f51f26863cf63051a827a1c62730d7ce547e45 Mon Sep 17 00:00:00 2001 From: megakaban Date: Thu, 10 Jun 2021 21:43:22 +0700 Subject: [PATCH 086/169] Display pool users --- .../client/src/Components/App.purs | 83 +++++++++++++++---- .../client/src/View/ReserveInfo.purs | 11 ++- .../client/src/View/UsersTable.purs | 26 ++++++ .../lending-pool/client/src/View/Utils.purs | 8 ++ 4 files changed, 106 insertions(+), 22 deletions(-) create mode 100644 MetaLamp/lending-pool/client/src/View/UsersTable.purs create mode 100644 MetaLamp/lending-pool/client/src/View/Utils.purs diff --git a/MetaLamp/lending-pool/client/src/Components/App.purs b/MetaLamp/lending-pool/client/src/Components/App.purs index 1de67c54a..4ce9134a9 100644 --- a/MetaLamp/lending-pool/client/src/Components/App.purs +++ b/MetaLamp/lending-pool/client/src/Components/App.purs @@ -7,7 +7,8 @@ import Capability.LogMessages (class LogMessages, logError) import Capability.PollContract (class PollContract) import Components.AmountForm as AmountForm import Control.Monad.Except (lift, runExceptT, throwError) -import Data.Array (mapWithIndex) +import Data.Array (groupBy, mapWithIndex) +import Data.Array.NonEmpty as NEA import Data.BigInteger (BigInteger, fromInt) import Data.Either (Either, either) import Data.Foldable (find) @@ -27,7 +28,7 @@ import Halogen.HTML as HH import Halogen.HTML.Events as HE import Network.RemoteData (RemoteData(..)) import Network.RemoteData as RD -import Plutus.Contracts.Core (Reserve(..)) +import Plutus.Contracts.Core (Reserve(..), UserConfig) import Plutus.Contracts.Endpoints (BorrowParams(..), DepositParams(..), RepayParams(..), WithdrawParams(..)) import Plutus.PAB.Webserver.Types (ContractInstanceClientState(..)) import Plutus.V1.Ledger.Crypto (PubKeyHash) @@ -37,6 +38,7 @@ import Utils.WithRemoteData (runRDWith) import View.FundsTable (fundsTable) import View.RemoteDataState (remoteDataState) import View.ReserveInfo (reserveInfo) +import View.UsersTable (poolUsers) import Wallet.Emulator.Wallet (Wallet(..)) import Wallet.Types (ContractInstanceId(..)) @@ -44,6 +46,7 @@ type State = { contractId :: RemoteData String ContractId , walletPubKey :: RemoteData String PubKeyHash , userFunds :: RemoteData String Value + , users :: RemoteData String (Map.Map (JsonTuple AssetClass PubKeyHash) UserConfig) , reserves :: RemoteData String (Map.Map AssetClass Reserve) , deposit :: RemoteData String Unit , withdraw :: RemoteData String Unit @@ -61,6 +64,9 @@ _walletPubKey = prop (SProxy :: SProxy "walletPubKey") _userFunds :: Lens' State (RemoteData String Value) _userFunds = prop (SProxy :: SProxy "userFunds") +_users :: Lens' State (RemoteData String (Map.Map (JsonTuple AssetClass PubKeyHash) UserConfig)) +_users = prop (SProxy :: SProxy "users") + _reserves :: Lens' State (RemoteData String (Map.Map AssetClass Reserve)) _reserves = prop (SProxy :: SProxy "reserves") @@ -84,6 +90,7 @@ initialState _ = { contractId: NotAsked , walletPubKey: NotAsked , userFunds: NotAsked + , users: NotAsked , reserves: NotAsked , withdraw: NotAsked , deposit: NotAsked @@ -97,8 +104,9 @@ data Action | GetContractAt Wallet | GetWalletPubKey | GetUserFunds + | GetUserConfigs | GetReserves - | GetFunds + | GetUpdates | Deposit { amount :: BigInteger, asset :: AssetClass } | Withdraw { amount :: BigInteger, asset :: AssetClass } | Borrow { amount :: BigInteger, asset :: AssetClass } @@ -157,7 +165,7 @@ component = Init -> do handleAction (GetContractAt $ Wallet { getWallet: fromInt 2 }) handleAction GetWalletPubKey - handleAction GetFunds + handleAction GetUpdates GetContractAt wallet -> runRD _contractId <<< runExceptT $ do @@ -184,15 +192,22 @@ component = <$> state.contractId <*> state.walletPubKey lift (Aave.fundsAt cid pkh) >>= either (throwError <<< show) pure + GetUserConfigs -> + runRD _users <<< runExceptT + $ do + state <- lift H.get + cid <- RD.maybe (throwError "contractId is missing") pure state.contractId + lift (Aave.users cid) >>= either (throwError <<< show) pure GetReserves -> runRD _reserves <<< runExceptT $ do state <- lift H.get cid <- RD.maybe (throwError "contractId or publicKey are missing") pure $ state.contractId lift (Aave.reserves cid) >>= either (throwError <<< show) pure - GetFunds -> do + GetUpdates -> do handleAction GetUserFunds handleAction GetReserves + handleAction GetUserConfigs Deposit { amount, asset } -> runRD _deposit <<< runExceptT $ do @@ -205,7 +220,7 @@ component = lift (Aave.deposit cid $ DepositParams { dpAmount: amount, dpAsset: asset, dpOnBehalfOf: pkh }) >>= either (throwError <<< show) (const <<< pure $ unit) Withdraw { amount, asset } -> - runRD _deposit <<< runExceptT + runRD _withdraw <<< runExceptT $ do state <- lift H.get { cid, pkh } <- @@ -216,7 +231,7 @@ component = lift (Aave.withdraw cid $ WithdrawParams { wpAmount: amount, wpAsset: asset, wpUser: pkh }) >>= either (throwError <<< show) (const <<< pure $ unit) Borrow { amount, asset } -> - runRD _deposit <<< runExceptT + runRD _borrow <<< runExceptT $ do state <- lift H.get { cid, pkh } <- @@ -227,7 +242,7 @@ component = lift (Aave.borrow cid $ BorrowParams { bpAmount: amount, bpAsset: asset, bpOnBehalfOf: pkh }) >>= either (throwError <<< show) (const <<< pure $ unit) Repay { amount, asset } -> - runRD _deposit <<< runExceptT + runRD _repay <<< runExceptT $ do state <- lift H.get { cid, pkh } <- @@ -246,20 +261,32 @@ component = Just (Tuple asset _) -> case operation of SubmitDeposit -> do lift $ handleAction (Deposit { amount, asset }) - lift (H.gets _.deposit) - >>= RD.maybe (throwError "Submit deposit failed") (const <<< lift <<< handleAction $ GetFunds) + { deposit } <- lift H.get + RD.maybe + (throwError $ "Submit deposit failed: " <> show deposit) + (const <<< lift <<< handleAction $ GetUpdates) + deposit SubmitWithdraw -> do lift $ handleAction (Withdraw { amount, asset }) - lift (H.gets _.withdraw) - >>= RD.maybe (throwError "Submit withdraw failed") (const <<< lift <<< handleAction $ GetFunds) + { withdraw } <- lift H.get + RD.maybe + (throwError $ "Submit withdraw failed: " <> show withdraw) + (const <<< lift <<< handleAction $ GetUpdates) + withdraw SubmitBorrow -> do lift $ handleAction (Borrow { amount, asset }) - lift (H.gets _.borrow) - >>= RD.maybe (throwError "Submit borrow failed") (const <<< lift <<< handleAction $ GetFunds) + { borrow } <- lift H.get + RD.maybe + (throwError $ "Submit borrow failed: " <> show borrow) + (const <<< lift <<< handleAction $ GetUpdates) + borrow SubmitRepay -> do lift $ handleAction (Repay { amount, asset }) - lift (H.gets _.repay) - >>= RD.maybe (throwError "Submit repay failed") (const <<< lift <<< handleAction $ GetFunds) + { repay } <- lift H.get + RD.maybe + (throwError $ "Submit repay failed: " <> show repay) + (const <<< lift <<< handleAction $ GetUpdates) + repay Nothing -> throwError "Asset name not found" render :: State -> H.ComponentHTML Action Slots m @@ -276,6 +303,30 @@ component = <> map (\(Tuple a r) -> reserveInfo a r) reserves ) (map Map.toTuples state.reserves) + , remoteDataState + ( \userMap -> + let + getAsset (Tuple (JsonTuple (Tuple asset _)) _) = asset + + getName (Tuple (JsonTuple (Tuple _ pkh)) _) = show pkh + + getUser (Tuple _ user) = user + + usersByAsset = groupBy (\a b -> getAsset a == getAsset b) <<< Map.toTuples $ userMap + + html = + map + ( \users -> + poolUsers + (getAsset <<< NEA.head $ users) + (map (\user -> Tuple (getName user) (getUser user)) $ users) + ) + usersByAsset + in + HH.div_ + $ [ HH.h2_ [ HH.text "Users:" ], HH.div_ html ] + ) + state.users , case state.submit of NotAsked -> HH.div_ [] Loading -> HH.div_ [] diff --git a/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs b/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs index d937b44a5..c60a78003 100644 --- a/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs +++ b/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs @@ -2,14 +2,13 @@ module View.ReserveInfo where import Prelude import Data.BigInteger (BigInteger) -import Data.Json.JsonTuple (JsonTuple(..)) -import Data.Tuple (Tuple(..)) import Halogen.HTML as HH import Plutus.Contracts.Core (Reserve(..)) -import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..)) +import Plutus.V1.Ledger.Value (AssetClass) +import View.Utils (assetName) reserveInfo :: forall props act. AssetClass -> Reserve -> HH.HTML props act -reserveInfo (AssetClass { unAssetClass: JsonTuple (Tuple _ name) }) (Reserve { rAmount }) = poolTab name rAmount +reserveInfo asset (Reserve { rAmount }) = poolTab asset rAmount -poolTab :: forall props act. TokenName -> BigInteger -> HH.HTML props act -poolTab (TokenName { unTokenName: name }) amount = HH.div_ $ [ HH.h4_ [ HH.text (name <> " pool balance") ], HH.text $ show amount ] +poolTab :: forall props act. AssetClass -> BigInteger -> HH.HTML props act +poolTab asset amount = HH.div_ $ [ HH.h4_ [ HH.text (assetName asset <> " pool balance") ], HH.text $ show amount ] diff --git a/MetaLamp/lending-pool/client/src/View/UsersTable.purs b/MetaLamp/lending-pool/client/src/View/UsersTable.purs new file mode 100644 index 000000000..89de6af40 --- /dev/null +++ b/MetaLamp/lending-pool/client/src/View/UsersTable.purs @@ -0,0 +1,26 @@ +module View.UsersTable where + +import Prelude +import Data.Array.NonEmpty (NonEmptyArray, toArray) +import Data.BigInteger (fromInt) +import Data.Maybe (fromMaybe) +import Data.Tuple (Tuple(..)) +import Halogen.HTML as HH +import Plutus.Contracts.Core (UserConfig(..)) +import Plutus.V1.Ledger.Value (AssetClass) +import View.Utils (assetName) + +poolUsers :: forall props act. AssetClass -> NonEmptyArray (Tuple String UserConfig) -> HH.HTML props act +poolUsers asset users = + HH.div_ + [ HH.h3_ [ HH.text $ assetName asset <> " pool:" ] + , HH.div_ <<< toArray <<< map userInfo $ users + ] + +userInfo :: forall props act. Tuple String UserConfig -> HH.HTML props act +userInfo (Tuple userId (UserConfig { ucDebt, ucUsingAsCollateral })) = + HH.div_ + [ HH.div_ [ HH.text $ "User " <> userId ] + , HH.div_ [ HH.text $ "Debt: " <> (show <<< fromMaybe (fromInt 0) $ ucDebt) ] + , HH.div_ [ HH.text $ "Using as collateral: " <> (show ucUsingAsCollateral) ] + ] diff --git a/MetaLamp/lending-pool/client/src/View/Utils.purs b/MetaLamp/lending-pool/client/src/View/Utils.purs new file mode 100644 index 000000000..0c8b1ac4f --- /dev/null +++ b/MetaLamp/lending-pool/client/src/View/Utils.purs @@ -0,0 +1,8 @@ +module View.Utils where + +import Data.Json.JsonTuple (JsonTuple(..)) +import Data.Tuple (Tuple(..)) +import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..)) + +assetName :: AssetClass -> String +assetName (AssetClass { unAssetClass: JsonTuple (Tuple _ (TokenName { unTokenName: name })) }) = name From deee075ef20462ad49b0dfc22d0b2de664adb67e Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 10 Jun 2021 14:02:05 +0700 Subject: [PATCH 087/169] fix debt change in borrow --- .../src/Plutus/Contracts/Endpoints.hs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 8e2c72d4d..d1cf151fd 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -230,13 +230,15 @@ borrow aave BorrowParams {..} = do userConfigs <- ovValue <$> State.findAaveUserConfigs aave userConfigsTx <- case AssocMap.lookup userConfigId userConfigs of - Nothing -> - State.addUserConfig - aave (Core.BorrowRedeemer userConfigId) - userConfigId - UserConfig { ucUsingAsCollateral = False, ucDebt = Just bpAmount } - Just userConfig -> - State.updateUserConfig aave (Core.BorrowRedeemer userConfigId) userConfigId $ userConfig { ucDebt = (+ bpAmount) <$> ucDebt userConfig } + Nothing -> + State.addUserConfig + aave + (Core.BorrowRedeemer userConfigId) + userConfigId + UserConfig {ucUsingAsCollateral = False, ucDebt = Just bpAmount} + Just userConfig -> + State.updateUserConfig aave (Core.BorrowRedeemer userConfigId) userConfigId $ + userConfig {ucDebt = Just $ maybe bpAmount (+ bpAmount) $ ucDebt userConfig} reservesTx <- State.updateReserve aave (Core.BorrowRedeemer userConfigId) bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) From 0f41a2719ba6b5d3c35c60d345f8f4794a1a28d7 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 11 Jun 2021 17:00:10 +0700 Subject: [PATCH 088/169] fix repay validator --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 368e68cf9..92f283b28 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -260,8 +260,9 @@ validateRepay aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(r checkRedeemerConfig :: UserConfig -> UserConfig -> Bool checkRedeemerConfig oldState newState = let debtChange = fromMaybe 0 $ (-) <$> ucDebt oldState <*> ucDebt newState + newDebt = fromMaybe 0 $ ucDebt newState reimbursementAmount = assetClassValueOf actorSpentValue reserveId - assetClassValueOf actorRemainderValue reserveId - in debtChange == reimbursementAmount && debtChange > 0 && reimbursementAmount > 0 && + in debtChange == reimbursementAmount && debtChange > 0 && reimbursementAmount > 0 && newDebt >= 0 && ucUsingAsCollateral oldState == ucUsingAsCollateral newState validateRepay aave (ReservesDatum stateToken reserves) ctx userConfigId = From 134d517d9da145a36172d8f7870e175b0999f9ea Mon Sep 17 00:00:00 2001 From: megakaban Date: Fri, 11 Jun 2021 18:53:09 +0700 Subject: [PATCH 089/169] Update platform, fix errors --- MetaLamp/lending-pool/cabal.project | 9 +++- .../client/scripts/fetch-plutus-purs.sh | 2 +- MetaLamp/lending-pool/client/src/AppAff.purs | 2 +- MetaLamp/lending-pool/generate-purs/Main.hs | 52 ++----------------- .../src/Ext/Plutus/Ledger/Contexts.hs | 2 +- .../lending-pool/src/Plutus/Contracts/Core.hs | 12 ++--- .../src/Plutus/Contracts/Endpoints.hs | 7 +-- .../src/Plutus/Contracts/TxUtils.hs | 15 +++--- .../lending-pool/src/Plutus/State/Update.hs | 11 ++-- 9 files changed, 34 insertions(+), 78 deletions(-) diff --git a/MetaLamp/lending-pool/cabal.project b/MetaLamp/lending-pool/cabal.project index 6f99740fc..964bef10c 100644 --- a/MetaLamp/lending-pool/cabal.project +++ b/MetaLamp/lending-pool/cabal.project @@ -22,11 +22,11 @@ source-repository-package plutus-tx plutus-tx-plugin plutus-pab - plutus-ledger-api plutus-use-cases prettyprinter-configurable quickcheck-dynamic - tag: 58bf9ed626d498c140c69a859a508da03843d097 + word-array + tag: 5cdd2c3d708bf4c33514681dee096da6463273b7 -- The following sections are copied from the 'plutus' repository cabal.project at the revision -- given above. @@ -143,3 +143,8 @@ source-repository-package type: git location: https://github.com/input-output-hk/goblins tag: cde90a2b27f79187ca8310b6549331e59595e7ba + +source-repository-package + type: git + location: https://github.com/Quid2/flat.git + tag: 95e5d7488451e43062ca84d5376b3adcc465f1cd diff --git a/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh b/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh index 69ac31ab9..745d22fa7 100755 --- a/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh +++ b/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh @@ -6,4 +6,4 @@ git remote add origin -f https://github.com/input-output-hk/plutus git config core.sparseCheckout true echo 'web-common-plutus/*' >> .git/info/sparse-checkout echo 'web-common/*' >> .git/info/sparse-checkout -git pull origin 58bf9ed626d498c140c69a859a508da03843d097 +git pull origin 5cdd2c3d708bf4c33514681dee096da6463273b7 diff --git a/MetaLamp/lending-pool/client/src/AppAff.purs b/MetaLamp/lending-pool/client/src/AppAff.purs index bcf9bb8f6..885b6d883 100644 --- a/MetaLamp/lending-pool/client/src/AppAff.purs +++ b/MetaLamp/lending-pool/client/src/AppAff.purs @@ -86,5 +86,5 @@ instance contractAppM :: Contract AppM where callEndpoint (Endpoint endpoint) (ContractId cid) params = post ("/api/new/contract/instance/" <> cid <> "/endpoint/" <> endpoint) (string <<< encodeJSON $ params) instance pollContractAppM :: PollContract AppM where - pollDelay = liftAff <<< delay <<< Milliseconds $ 300.0 + pollDelay = liftAff <<< delay <<< Milliseconds $ 1000.0 tooManyRetries retryCount = pure $ retryCount > 10 diff --git a/MetaLamp/lending-pool/generate-purs/Main.hs b/MetaLamp/lending-pool/generate-purs/Main.hs index d60ddcc44..a0e3927bd 100644 --- a/MetaLamp/lending-pool/generate-purs/Main.hs +++ b/MetaLamp/lending-pool/generate-purs/Main.hs @@ -17,10 +17,7 @@ import Cardano.Metadata.Types (AnnotatedSignature, import Cardano.Wallet.Types (WalletInfo) import Control.Applicative ((<|>)) import Control.Lens (set, view, (&)) -import Control.Monad (void) import Control.Monad.Freer.Extras.Log (LogLevel, LogMessage) -import qualified Data.Aeson.Encode.Pretty as JSON -import qualified Data.ByteString.Lazy as BSL import Data.Proxy (Proxy (Proxy)) import qualified Data.Text as Text import Language.PureScript.Bridge (BridgePart, Language (Haskell), SumType, @@ -32,7 +29,7 @@ import Language.PureScript.Bridge.CodeGenSwitches (ForeignOptions (For import Language.PureScript.Bridge.TypeParameters (A) import Ledger.Constraints.OffChain (UnbalancedTx) import qualified PSGenerator.Common -import Plutus.Contract.Checkpoint (CheckpointKey, CheckpointStore) +import Plutus.Contract.Checkpoint (CheckpointKey, CheckpointStore, CheckpointStoreItem) import Plutus.Contract.Effects.AwaitSlot (WaitingForSlot) import Plutus.Contract.Effects.AwaitTxConfirmed (TxConfirmed) import Plutus.Contract.Effects.ExposeEndpoint (ActiveEndpoint, EndpointValue) @@ -41,17 +38,10 @@ import Plutus.Contract.Effects.OwnPubKey (OwnPubKeyRequest) import Plutus.Contract.Effects.UtxoAt (UtxoAtAddress) import Plutus.Contract.Effects.WriteTx (WriteTxResponse) import Plutus.Contract.Resumable (Responses) -import Plutus.Contract.State (ContractRequest, State) -import Plutus.Contracts.Currency (SimpleMPS (..)) import Plutus.PAB.Effects.Contract.ContractExe (ContractExe) -import Plutus.PAB.Effects.Contract.ContractTest (TestContracts (Currency, GameStateMachine)) -import Plutus.PAB.Events (PABEvent) -import Plutus.PAB.Events.Contract (ContractInstanceId (..), ContractPABRequest, - ContractResponse) +import Plutus.PAB.Events.Contract (ContractPABRequest, ContractPABResponse) import Plutus.PAB.Events.ContractInstanceState (PartiallyDecodedResponse) -import qualified Plutus.PAB.Simulator as Simulator import qualified Plutus.PAB.Webserver.API as API -import qualified Plutus.PAB.Webserver.Handler as Webserver import Plutus.PAB.Webserver.Types (ChainReport, CombinedWSStreamToClient, CombinedWSStreamToServer, ContractActivationArgs, ContractInstanceClientState, ContractReport, @@ -61,7 +51,6 @@ import Servant ((:<|>)) import Servant.PureScript (HasBridge, Settings, _generateSubscriberAPI, apiModuleName, defaultBridge, defaultSettings, languageBridge, writeAPIModuleWithSettings) -import System.FilePath (()) import Wallet.Effects (AddressChangeRequest (..), AddressChangeResponse (..)) import Wallet.Emulator.Wallet (Wallet (..)) import AaveTypes (aaveTypes, ratioBridge) @@ -103,21 +92,19 @@ instance HasBridge MyBridge where myTypes :: [SumType 'Haskell] myTypes = + aaveTypes <> PSGenerator.Common.ledgerTypes <> PSGenerator.Common.playgroundTypes <> PSGenerator.Common.walletTypes <> - aaveTypes <> [ (equal <*> (genericShow <*> mkSumType)) (Proxy @ContractExe) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @TestContracts) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(FullReport A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @ChainReport) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractReport A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractSignatureResponse A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(PartiallyDecodedResponse A)) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractRequest A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @ContractPABRequest) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @ContractResponse) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @ContractPABResponse) , (equal <*> (genericShow <*> mkSumType)) (Proxy @UnbalancedTx) -- Contract request / response types @@ -128,9 +115,9 @@ myTypes = , (equal <*> (genericShow <*> mkSumType)) (Proxy @UtxoAtAddress) , (equal <*> (genericShow <*> mkSumType)) (Proxy @WriteTxResponse) , (equal <*> (genericShow <*> mkSumType)) (Proxy @WaitingForSlot) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @(State A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @CheckpointStore) , (order <*> (genericShow <*> mkSumType)) (Proxy @CheckpointKey) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(CheckpointStoreItem A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(Responses A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @AddressChangeRequest) , (equal <*> (genericShow <*> mkSumType)) (Proxy @AddressChangeResponse) @@ -149,7 +136,6 @@ myTypes = , (equal <*> (genericShow <*> mkSumType)) (Proxy @(AnnotatedSignature A)) -- * Web API types - , (equal <*> (genericShow <*> mkSumType)) (Proxy @(PABEvent A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractActivationArgs A)) , (genericShow <*> mkSumType) (Proxy @(ContractInstanceClientState A)) , (genericShow <*> mkSumType) (Proxy @InstanceStatusToClient) @@ -165,45 +151,17 @@ mySettings = defaultWallet :: Wallet defaultWallet = Wallet 1 - ------------------------------------------------------------- -writeTestData :: FilePath -> IO () -writeTestData outputDir = do - (fullReport, currencySchema) <- - fmap (either (error . show) id) $ Simulator.runSimulation $ do - currencyInstance1 <- Simulator.activateContract defaultWallet Currency - void $ Simulator.activateContract defaultWallet Currency - void $ Simulator.activateContract defaultWallet GameStateMachine - void $ Simulator.waitForEndpoint currencyInstance1 "Create native token" - void $ Simulator.callEndpointOnInstance currencyInstance1 "Create native token" SimpleMPS {tokenName = "TestCurrency", amount = 10000000000} - void $ Simulator.waitUntilFinished currencyInstance1 - report :: FullReport TestContracts <- Webserver.getFullReport - schema :: ContractSignatureResponse TestContracts <- Webserver.contractSchema (Text.pack $ show $ unContractInstanceId currencyInstance1) - pure (report, schema) - BSL.writeFile - (outputDir "full_report_response.json") - (JSON.encodePretty fullReport) - BSL.writeFile - (outputDir "contract_schema_response.json") - (JSON.encodePretty currencySchema) - ------------------------------------------------------------ generateTo :: FilePath -> IO () generateTo outputDir = do exists <- doesDirectoryExist outputDir when exists $ removeDirectoryRecursive outputDir - writeAPIModuleWithSettings - mySettings - outputDir - myBridgeProxy - (Proxy @(API.API ContractExe :<|> API.NewAPI ContractExe Text.Text :<|> (API.WalletProxy Text.Text))) writePSTypesWith (genForeign (ForeignOptions {unwrapSingleConstructors = True})) outputDir (buildBridge myBridge) myTypes - writeTestData outputDir main :: IO () main = generateTo "client/generated" diff --git a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs index 7c109af29..e823adb6a 100644 --- a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs +++ b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs @@ -14,7 +14,7 @@ import Ledger (Address (Address), import Plutus.V1.Ledger.Credential (Credential (PubKeyCredential, ScriptCredential)) import qualified PlutusTx import PlutusTx.Prelude (Eq ((==)), Maybe (..), - Monad ((>>=)), find, fst, + find, fst, (>>=), mapMaybe, mconcat, snd, ($), (.), (<$>)) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 92f283b28..de881c370 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -30,7 +30,7 @@ import Ledger hiding (singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints import Ledger.Constraints.TxConstraints as Constraints -import qualified Ledger.Scripts as Scripts +import qualified Ledger.Scripts as UntypedScripts import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract import Plutus.Contract hiding (when) @@ -42,8 +42,6 @@ import PlutusTx.Prelude hiding (Semigroup (..), import Prelude (Semigroup (..)) import qualified Prelude -deriving anyclass instance ToSchema AssetClass - newtype Aave = Aave { aaveProtocolInst :: AssetClass } deriving stock (Prelude.Eq, Show, Generic) @@ -113,7 +111,7 @@ pickReserves (ReservesDatum stateToken configs) = Just (stateToken, configs) pickReserves _ = Nothing data AaveScript -instance Scripts.ScriptType AaveScript where +instance Scripts.ValidatorTypes AaveScript where type instance RedeemerType AaveScript = AaveRedeemer type instance DatumType AaveScript = AaveDatum @@ -365,8 +363,8 @@ checkReservesConsistency oldState newState = aaveProtocolName :: TokenName aaveProtocolName = "Aave" -aaveInstance :: Aave -> Scripts.ScriptInstance AaveScript -aaveInstance aave = Scripts.validator @AaveScript +aaveInstance :: Aave -> Scripts.TypedValidator AaveScript +aaveInstance aave = Scripts.mkTypedValidator @AaveScript ($$(PlutusTx.compile [|| makeAaveValidator ||]) `PlutusTx.applyCode` PlutusTx.liftCode aave) $$(PlutusTx.compile [|| wrap ||]) @@ -377,7 +375,7 @@ aaveValidator :: Aave -> Validator aaveValidator = Scripts.validatorScript . aaveInstance aaveHash :: Aave -> Ledger.ValidatorHash -aaveHash = Scripts.validatorHash . aaveValidator +aaveHash = UntypedScripts.validatorHash . aaveValidator aaveAddress :: Aave -> Ledger.Address aaveAddress = Ledger.scriptAddress . aaveValidator diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index d1cf151fd..28344ae1d 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -53,7 +53,7 @@ import qualified PlutusTx.AssocMap as AssocMap import PlutusTx.Prelude hiding (Monoid (..), Semigroup (..), mconcat, unless) -import Prelude (Monoid (..), Semigroup (..)) +import Prelude (Monoid (..), Semigroup (..), show, subtract) import qualified Prelude import Text.Printf (printf) @@ -96,7 +96,7 @@ start params = do ledgerTx <- TxUtils.submitTxPair userConfigsTx void $ awaitTxConfirmed $ txId ledgerTx - logInfo @String $ printf "started Aave %s at address %s" (show aave) (show $ Core.aaveAddress aave) + logInfo @Prelude.String $ printf "started Aave %s at address %s" (show aave) (show $ Core.aaveAddress aave) pure aave ownerEndpoint :: [CreateParams] -> Contract (Last (Either Text Aave)) BlockchainActions Void () @@ -291,9 +291,6 @@ type AaveUserSchema = .\/ Endpoint "users" () .\/ Endpoint "ownPubKey" () -instance (Prelude.Eq k, Prelude.Eq v) => Prelude.Eq (AssocMap.Map k v) where - a == b = (AssocMap.toList a) Prelude.== (AssocMap.toList b) - data UserContractState = Pending | Created diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs index 8637d7b5e..a0a380b5a 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs @@ -19,8 +19,7 @@ import qualified Ledger.Constraints as Constraints import qualified Ledger.Constraints.OnChain as Constraints import qualified Ledger.Constraints.TxConstraints as Constraints import Ledger.Typed.Scripts (MonetaryPolicy, - ScriptInstance, - ScriptType (..)) + TypedValidator, RedeemerType, DatumType) import qualified Ledger.Typed.Scripts as Scripts import Plutus.Contract import Plutus.Contracts.Core (Aave, Reserve (..)) @@ -44,7 +43,7 @@ type TxPair a = (Constraints.ScriptLookups a, Constraints.TxConstraints (Redeeme submitTxPair :: (AsContractError e, HasWriteTx s, PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => TxPair a -> Contract w s e Tx -submitTxPair = uncurry submitTxConstraintsWith +submitTxPair = Prelude.uncurry submitTxConstraintsWith mustForgeValue :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => MonetaryPolicy @@ -56,18 +55,18 @@ mustForgeValue policy value = (lookups, tx) tx = Constraints.mustForgeValue value mustPayToScript :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => - ScriptInstance a + TypedValidator a -> PubKeyHash -> DatumType a -> Value -> TxPair a mustPayToScript script pkh datum value = (lookups, tx) where - lookups = Constraints.ownPubKeyHash pkh <> Constraints.scriptInstanceLookups script + lookups = Constraints.ownPubKeyHash pkh <> Constraints.typedValidatorLookups script tx = Constraints.mustPayToTheScript datum value mustSpendScriptOutputs :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => - ScriptInstance a + TypedValidator a -> [OutputValue (RedeemerType a)] -> TxPair a mustSpendScriptOutputs script inputs = (lookups, tx) @@ -78,7 +77,7 @@ mustSpendScriptOutputs script inputs = (lookups, tx) fmap (\(OutputValue ref _ redeemer) -> Constraints.mustSpendScriptOutput ref (Redeemer $ PlutusTx.toData redeemer)) inputs mustSpendFromScript :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => - ScriptInstance a + TypedValidator a -> [OutputValue (RedeemerType a)] -> PubKeyHash -> Value @@ -89,7 +88,7 @@ mustSpendFromScript script inputs pkh value = (lookups, tx) <> mustSpendScriptOu tx = Constraints.mustPayToPubKey pkh value mustRoundTripToScript :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => - ScriptInstance a + TypedValidator a -> [OutputValue (RedeemerType a)] -> DatumType a -> PubKeyHash diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index 5bce4d263..007d7413a 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -26,10 +26,9 @@ import Ledger hiding (getDatum, singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints import Ledger.Constraints.TxConstraints as Constraints -import qualified Ledger.Scripts as Scripts -import Ledger.Typed.Scripts (ScriptType (..)) +import qualified Ledger.Scripts as UntypedScripts import qualified Ledger.Typed.Scripts as Scripts - +import Ledger.Typed.Scripts (RedeemerType, DatumType) import Ext.Plutus.Ledger.Contexts (scriptInputsAt) import Playground.Contract import Plutus.Contract hiding (when) @@ -75,7 +74,7 @@ makeStateToken :: ValidatorHash -> OwnerToken -> TokenName -> AssetClass makeStateToken ownerScript ownerToken tokenName = assetClass (makeStateCurrency ownerScript ownerToken tokenName) tokenName data PutStateHandle scriptType = PutStateHandle { - script :: Scripts.ScriptInstance scriptType, + script :: Scripts.TypedValidator scriptType, ownerToken :: AssetClass, ownerTokenOutput :: OutputValue (DatumType scriptType) } @@ -96,7 +95,7 @@ putState PutStateHandle {..} StateHandle{..} newState = do pkh <- pubKeyHash <$> ownPubKey let (_, stateTokenName) = unAssetClass stateToken pure $ - TxUtils.mustForgeValue (makeStatePolicy (Scripts.scriptHash script) ownerToken stateTokenName) (assetClassValue stateToken 1) + TxUtils.mustForgeValue (makeStatePolicy (Scripts.validatorHash script) ownerToken stateTokenName) (assetClassValue stateToken 1) <> TxUtils.mustPayToScript script pkh (toDatum newState) (assetClassValue stateToken 1) <> TxUtils.mustRoundTripToScript script @@ -107,7 +106,7 @@ putState PutStateHandle {..} StateHandle{..} newState = do updateState :: (HasBlockchainActions s, IsData (DatumType scriptType), IsData (RedeemerType scriptType)) => - Scripts.ScriptInstance scriptType -> + Scripts.TypedValidator scriptType -> StateHandle scriptType a -> OutputValue a -> Contract w s Text (TxUtils.TxPair scriptType) From 596ad394e564ae0a2795e43465cb9e885ef5ec0f Mon Sep 17 00:00:00 2001 From: stanislav-az Date: Mon, 14 Jun 2021 20:14:01 +0700 Subject: [PATCH 090/169] fix funds outputs spending --- .../src/Ext/Plutus/Ledger/Contexts.hs | 29 ++++++++++--------- .../lending-pool/src/Plutus/Contracts/Core.hs | 28 +++++++++--------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs index e823adb6a..e84fa48e4 100644 --- a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs +++ b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs @@ -13,32 +13,34 @@ import Ledger (Address (Address), ValidatorHash, Value, findDatum) import Plutus.V1.Ledger.Credential (Credential (PubKeyCredential, ScriptCredential)) import qualified PlutusTx -import PlutusTx.Prelude (Eq ((==)), Maybe (..), - find, fst, (>>=), +import PlutusTx.Prelude (Eq ((==)), Maybe (..), find, fst,filter,otherwise, mapMaybe, mconcat, snd, ($), (.), - (<$>)) + (<$>), (>>=)) -{-# INLINABLE findDatumHashByValue #-} --- | Find the hash of a datum, if it is part of the pending transaction's --- outputs -findDatumHashByValue :: Value -> [(DatumHash, Value)] -> Maybe DatumHash -findDatumHashByValue val outs = fst <$> find f outs +{-# INLINABLE findOnlyOneDatumHashByValue #-} +-- | Find the hash of a datum, if it is part of the script's outputs. +-- Assume search failed if more than one correspondence is found. +findOnlyOneDatumHashByValue :: Value -> [(DatumHash, Value)] -> Maybe DatumHash +findOnlyOneDatumHashByValue val outs = fst <$> case filter f outs of + [res] -> Just res + _ -> Nothing where f (_, val') = val' == val {-# INLINABLE findValueByDatumHash #-} --- | Find the hash of a datum, if it is part of the pending transaction's --- outputs -findValueByDatumHash :: DatumHash -> [(DatumHash, Value)] -> Maybe Value -findValueByDatumHash dh outs = snd <$> find f outs +-- | Concat value of the script's outputs that have the specified hash of a datum +findValueByDatumHash :: DatumHash -> [(DatumHash, Value)] -> Value +findValueByDatumHash dh outs = mconcat $ mapMaybe f outs where - f (dh', _) = dh' == dh + f (dh', val) | dh' == dh = Just val + | otherwise = Nothing {-# INLINABLE parseDatum #-} parseDatum :: PlutusTx.IsData a => TxInfo -> DatumHash -> Maybe a parseDatum txInfo dh = findDatum dh txInfo >>= (PlutusTx.fromData . getDatum) {-# INLINABLE valueSpentFrom #-} +-- | Concat value of the inputs belonging to the provided public key inside the pending transaction's inputs valueSpentFrom :: TxInfo -> PubKeyHash -> Value valueSpentFrom txInfo pk = let flt TxOut {txOutAddress = Address (PubKeyCredential pk') _, txOutValue} @@ -47,6 +49,7 @@ valueSpentFrom txInfo pk = in mconcat $ mapMaybe flt (txInInfoResolved <$> txInfoInputs txInfo) {-# INLINABLE scriptInputsAt #-} +-- | Finds all inputs belonging to a specific script inside the pending transaction's inputs scriptInputsAt :: ValidatorHash -> TxInfo -> [(DatumHash, Value)] scriptInputsAt h p = let flt TxOut{txOutDatumHash=Just ds, txOutAddress=Address (ScriptCredential s) _, txOutValue} | s == h = Just (ds, txOutValue) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index de881c370..7e8f2f1f1 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -23,8 +23,8 @@ import qualified Data.ByteString as BS import qualified Data.Map as Map import Data.Text (Text, pack) import Data.Void (Void) -import Ext.Plutus.Ledger.Contexts (findDatumHashByValue, - findValueByDatumHash, +import Ext.Plutus.Ledger.Contexts (findOnlyOneDatumHashByValue, + findValueByDatumHash,scriptInputsAt, parseDatum, valueSpentFrom) import Ledger hiding (singleton) import Ledger.Constraints as Constraints @@ -150,7 +150,7 @@ validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId txInfo = scriptContextTxInfo ctx (scriptsHash, scriptsDatumHash) = ownHashes ctx userConfigsOutputDatumHash = - findDatumHashByValue (assetClassValue stateToken 1) $ scriptOutputsAt scriptsHash txInfo + findOnlyOneDatumHashByValue (assetClassValue stateToken 1) $ scriptOutputsAt scriptsHash txInfo userConfigsOutputDatum :: Maybe (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) userConfigsOutputDatum = @@ -197,7 +197,7 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( (scriptsHash, scriptsDatumHash) = ownHashes ctx scriptOutputs = scriptOutputsAt scriptsHash txInfo userConfigsOutputDatumHash = - findDatumHashByValue (assetClassValue stateToken 1) scriptOutputs + findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs userConfigsOutputDatum :: Maybe (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) userConfigsOutputDatum = @@ -238,7 +238,7 @@ validateRepay aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(r (scriptsHash, scriptsDatumHash) = ownHashes ctx scriptOutputs = scriptOutputsAt scriptsHash txInfo userConfigsOutputDatumHash = - findDatumHashByValue (assetClassValue stateToken 1) scriptOutputs + findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs userConfigsOutputDatum :: Maybe (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) userConfigsOutputDatum = @@ -269,21 +269,21 @@ validateRepay aave (ReservesDatum stateToken reserves) ctx userConfigId = validateRepay _ _ _ _ = trace "validateRepay: Lending Pool Datum management is not allowed" False checkNegativeFundsTransformation :: ScriptContext -> (AssetClass, PubKeyHash) -> Bool -checkNegativeFundsTransformation ctx (reserveId, actor) = maybe False checkFundsState $ (,) <$> scriptSpentValue <*> scriptRemainderValue +checkNegativeFundsTransformation ctx (reserveId, actor) = isValidFundsChange where txInfo = scriptContextTxInfo ctx (scriptsHash, scriptsDatumHash) = ownHashes ctx scriptOutputs = scriptOutputsAt scriptsHash txInfo - scriptSpentValue = txOutValue . txInInfoResolved <$> findOwnInput ctx + scriptSpentValue = findValueByDatumHash scriptsDatumHash $ scriptInputsAt scriptsHash txInfo scriptRemainderValue = findValueByDatumHash scriptsDatumHash scriptOutputs actorSpentValue = valueSpentFrom txInfo actor actorRemainderValue = valuePaidTo txInfo actor - checkFundsState :: (Value, Value) -> Bool - checkFundsState (oldFunds, newFunds) = + isValidFundsChange :: Bool + isValidFundsChange = let paidAmout = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId - fundsChange = assetClassValueOf oldFunds reserveId - assetClassValueOf newFunds reserveId + fundsChange = assetClassValueOf scriptSpentValue reserveId - assetClassValueOf scriptRemainderValue reserveId in fundsChange == paidAmout && fundsChange > 0 && paidAmout > 0 checkNegativeReservesTransformation :: AssetClass @@ -299,14 +299,14 @@ checkNegativeReservesTransformation stateToken reserves ctx (reserveId, _) = scriptOutputs = scriptOutputsAt scriptsHash txInfo reservesOutputDatumHash = - findDatumHashByValue (assetClassValue stateToken 1) scriptOutputs + findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs reservesOutputDatum :: Maybe (AssetClass, AssocMap.Map AssetClass Reserve) reservesOutputDatum = reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves remainderDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo - remainderValue = remainderDatumHash >>= (`findValueByDatumHash` scriptOutputs) + remainderValue = (`findValueByDatumHash` scriptOutputs) <$> remainderDatumHash checkreserves :: (AssetClass, AssocMap.Map AssetClass Reserve) -> Bool checkreserves (newStateToken, newReserves) = @@ -332,14 +332,14 @@ checkPositiveReservesTransformation stateToken reserves ctx (reserveId, _) = may scriptOutputs = scriptOutputsAt scriptsHash txInfo reservesOutputDatumHash = - findDatumHashByValue (assetClassValue stateToken 1) scriptOutputs + findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs reservesOutputDatum :: Maybe (AssetClass, AssocMap.Map AssetClass Reserve) reservesOutputDatum = reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves investmentDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo - investmentValue = investmentDatumHash >>= (`findValueByDatumHash` scriptOutputs) + investmentValue = (`findValueByDatumHash` scriptOutputs) <$> investmentDatumHash checkreserves :: (AssetClass, AssocMap.Map AssetClass Reserve) -> Bool checkreserves (newStateToken, newReserves) = From 2d465c3dd356f0016877455b1eedec68acda0651 Mon Sep 17 00:00:00 2001 From: stanislav-az Date: Mon, 14 Jun 2021 20:17:25 +0700 Subject: [PATCH 091/169] increase retries count --- MetaLamp/lending-pool/client/src/AppAff.purs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/client/src/AppAff.purs b/MetaLamp/lending-pool/client/src/AppAff.purs index 885b6d883..ed0fba455 100644 --- a/MetaLamp/lending-pool/client/src/AppAff.purs +++ b/MetaLamp/lending-pool/client/src/AppAff.purs @@ -87,4 +87,4 @@ instance contractAppM :: Contract AppM where instance pollContractAppM :: PollContract AppM where pollDelay = liftAff <<< delay <<< Milliseconds $ 1000.0 - tooManyRetries retryCount = pure $ retryCount > 10 + tooManyRetries retryCount = pure $ retryCount > 20 From 18ff76408fb7393dbb0d2cd011038ab533e66e46 Mon Sep 17 00:00:00 2001 From: stanislav-az Date: Mon, 14 Jun 2021 20:25:08 +0700 Subject: [PATCH 092/169] fmt haskell --- .../lending-pool/generate-purs/AaveTypes.hs | 29 ++++--- MetaLamp/lending-pool/generate-purs/Main.hs | 77 +++++++++++++------ MetaLamp/lending-pool/pab-simulation/Main.hs | 2 +- .../src/Ext/Plutus/Ledger/Contexts.hs | 9 ++- .../lending-pool/src/Plutus/Contracts/Core.hs | 5 +- .../src/Plutus/Contracts/Endpoints.hs | 3 +- .../src/Plutus/Contracts/TxUtils.hs | 4 +- .../lending-pool/src/Plutus/State/Update.hs | 4 +- 8 files changed, 88 insertions(+), 45 deletions(-) diff --git a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs index 6349f8414..71cf07fa1 100644 --- a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs +++ b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs @@ -11,19 +11,28 @@ module AaveTypes where -import Language.PureScript.Bridge (BridgePart, Language (Haskell), SumType, - TypeInfo (TypeInfo), buildBridge, equal, genericShow, - haskType, mkSumType, order, typeModule, typeName, - writePSTypesWith, (^==), PSType, psTypeParameters) -import Data.Proxy (Proxy (Proxy)) -import qualified Plutus.Contracts.Core as Aave -import qualified Plutus.Contracts.Endpoints as Aave -import Plutus.PAB.Simulation (AaveContracts(..)) -import Language.PureScript.Bridge.TypeParameters (A) import Control.Monad.Reader (MonadReader) +import Data.Proxy (Proxy (Proxy)) +import Language.PureScript.Bridge (BridgePart, + Language (Haskell), + PSType, SumType, + TypeInfo (TypeInfo), + buildBridge, equal, + genericShow, + haskType, mkSumType, + order, + psTypeParameters, + typeModule, + typeName, + writePSTypesWith, + (^==)) import Language.PureScript.Bridge.Builder (BridgeData) +import Language.PureScript.Bridge.TypeParameters (A) import qualified PSGenerator.Common -import Plutus.V1.Ledger.Value (AssetClass) +import qualified Plutus.Contracts.Core as Aave +import qualified Plutus.Contracts.Endpoints as Aave +import Plutus.PAB.Simulation (AaveContracts (..)) +import Plutus.V1.Ledger.Value (AssetClass) ratioBridge :: BridgePart ratioBridge = do diff --git a/MetaLamp/lending-pool/generate-purs/Main.hs b/MetaLamp/lending-pool/generate-purs/Main.hs index a0e3927bd..8797fa049 100644 --- a/MetaLamp/lending-pool/generate-purs/Main.hs +++ b/MetaLamp/lending-pool/generate-purs/Main.hs @@ -1,5 +1,6 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} @@ -8,55 +9,85 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -{-# LANGUAGE EmptyDataDecls #-} module Main where -import Cardano.Metadata.Types (AnnotatedSignature, HashFunction, Property, PropertyKey, - Subject, SubjectProperties) +import AaveTypes (aaveTypes, + ratioBridge) +import Cardano.Metadata.Types (AnnotatedSignature, + HashFunction, + Property, + PropertyKey, + Subject, + SubjectProperties) import Cardano.Wallet.Types (WalletInfo) import Control.Applicative ((<|>)) import Control.Lens (set, view, (&)) -import Control.Monad.Freer.Extras.Log (LogLevel, LogMessage) +import Control.Monad (when) +import Control.Monad.Freer.Extras.Log (LogLevel, + LogMessage) import Data.Proxy (Proxy (Proxy)) import qualified Data.Text as Text -import Language.PureScript.Bridge (BridgePart, Language (Haskell), SumType, - TypeInfo (TypeInfo), buildBridge, equal, genericShow, - haskType, mkSumType, order, typeModule, typeName, - writePSTypesWith, (^==)) -import Language.PureScript.Bridge.CodeGenSwitches (ForeignOptions (ForeignOptions), genForeign, +import Language.PureScript.Bridge (BridgePart, + Language (Haskell), + SumType, + TypeInfo (TypeInfo), + buildBridge, equal, + genericShow, + haskType, + mkSumType, order, + typeModule, + typeName, + writePSTypesWith, + (^==)) +import Language.PureScript.Bridge.CodeGenSwitches (ForeignOptions (ForeignOptions), + genForeign, unwrapSingleConstructors) import Language.PureScript.Bridge.TypeParameters (A) import Ledger.Constraints.OffChain (UnbalancedTx) import qualified PSGenerator.Common -import Plutus.Contract.Checkpoint (CheckpointKey, CheckpointStore, CheckpointStoreItem) +import Plutus.Contract.Checkpoint (CheckpointKey, + CheckpointStore, + CheckpointStoreItem) import Plutus.Contract.Effects.AwaitSlot (WaitingForSlot) import Plutus.Contract.Effects.AwaitTxConfirmed (TxConfirmed) -import Plutus.Contract.Effects.ExposeEndpoint (ActiveEndpoint, EndpointValue) +import Plutus.Contract.Effects.ExposeEndpoint (ActiveEndpoint, + EndpointValue) import Plutus.Contract.Effects.Instance (OwnIdRequest) import Plutus.Contract.Effects.OwnPubKey (OwnPubKeyRequest) import Plutus.Contract.Effects.UtxoAt (UtxoAtAddress) import Plutus.Contract.Effects.WriteTx (WriteTxResponse) import Plutus.Contract.Resumable (Responses) import Plutus.PAB.Effects.Contract.ContractExe (ContractExe) -import Plutus.PAB.Events.Contract (ContractPABRequest, ContractPABResponse) +import Plutus.PAB.Events.Contract (ContractPABRequest, + ContractPABResponse) import Plutus.PAB.Events.ContractInstanceState (PartiallyDecodedResponse) import qualified Plutus.PAB.Webserver.API as API -import Plutus.PAB.Webserver.Types (ChainReport, CombinedWSStreamToClient, - CombinedWSStreamToServer, ContractActivationArgs, - ContractInstanceClientState, ContractReport, - ContractSignatureResponse, FullReport, +import Plutus.PAB.Webserver.Types (ChainReport, + CombinedWSStreamToClient, + CombinedWSStreamToServer, + ContractActivationArgs, + ContractInstanceClientState, + ContractReport, + ContractSignatureResponse, + FullReport, InstanceStatusToClient) +import Plutus.V1.Ledger.Value (AssetClass, + TokenName (..)) import Servant ((:<|>)) -import Servant.PureScript (HasBridge, Settings, _generateSubscriberAPI, apiModuleName, - defaultBridge, defaultSettings, languageBridge, +import Servant.PureScript (HasBridge, + Settings, + _generateSubscriberAPI, + apiModuleName, + defaultBridge, + defaultSettings, + languageBridge, writeAPIModuleWithSettings) -import Wallet.Effects (AddressChangeRequest (..), AddressChangeResponse (..)) +import System.Directory (doesDirectoryExist, + removeDirectoryRecursive) +import Wallet.Effects (AddressChangeRequest (..), + AddressChangeResponse (..)) import Wallet.Emulator.Wallet (Wallet (..)) -import AaveTypes (aaveTypes, ratioBridge) -import System.Directory (removeDirectoryRecursive, doesDirectoryExist) -import Plutus.V1.Ledger.Value (AssetClass, TokenName (..)) -import Control.Monad (when) myBridge :: BridgePart myBridge = diff --git a/MetaLamp/lending-pool/pab-simulation/Main.hs b/MetaLamp/lending-pool/pab-simulation/Main.hs index b65076421..f32dd951d 100644 --- a/MetaLamp/lending-pool/pab-simulation/Main.hs +++ b/MetaLamp/lending-pool/pab-simulation/Main.hs @@ -1,4 +1,4 @@ -import Plutus.PAB.Simulation (runLendingPoolSimulation) +import Plutus.PAB.Simulation (runLendingPoolSimulation) main :: IO () main = runLendingPoolSimulation diff --git a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs index e84fa48e4..721d46993 100644 --- a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs +++ b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs @@ -13,9 +13,10 @@ import Ledger (Address (Address), ValidatorHash, Value, findDatum) import Plutus.V1.Ledger.Credential (Credential (PubKeyCredential, ScriptCredential)) import qualified PlutusTx -import PlutusTx.Prelude (Eq ((==)), Maybe (..), find, fst,filter,otherwise, - mapMaybe, mconcat, snd, ($), (.), - (<$>), (>>=)) +import PlutusTx.Prelude (Eq ((==)), Maybe (..), filter, + find, fst, mapMaybe, mconcat, + otherwise, snd, ($), (.), (<$>), + (>>=)) {-# INLINABLE findOnlyOneDatumHashByValue #-} -- | Find the hash of a datum, if it is part of the script's outputs. @@ -23,7 +24,7 @@ import PlutusTx.Prelude (Eq ((==)), Maybe (..), find, fst,f findOnlyOneDatumHashByValue :: Value -> [(DatumHash, Value)] -> Maybe DatumHash findOnlyOneDatumHashByValue val outs = fst <$> case filter f outs of [res] -> Just res - _ -> Nothing + _ -> Nothing where f (_, val') = val' == val diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 7e8f2f1f1..76367fe3d 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -24,8 +24,9 @@ import qualified Data.Map as Map import Data.Text (Text, pack) import Data.Void (Void) import Ext.Plutus.Ledger.Contexts (findOnlyOneDatumHashByValue, - findValueByDatumHash,scriptInputsAt, - parseDatum, valueSpentFrom) + findValueByDatumHash, + parseDatum, scriptInputsAt, + valueSpentFrom) import Ledger hiding (singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 28344ae1d..f499b4040 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -53,7 +53,8 @@ import qualified PlutusTx.AssocMap as AssocMap import PlutusTx.Prelude hiding (Monoid (..), Semigroup (..), mconcat, unless) -import Prelude (Monoid (..), Semigroup (..), show, subtract) +import Prelude (Monoid (..), Semigroup (..), + show, subtract) import qualified Prelude import Text.Printf (printf) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs index a0a380b5a..8438dc0fe 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs @@ -18,8 +18,8 @@ import Ledger hiding (singleton) import qualified Ledger.Constraints as Constraints import qualified Ledger.Constraints.OnChain as Constraints import qualified Ledger.Constraints.TxConstraints as Constraints -import Ledger.Typed.Scripts (MonetaryPolicy, - TypedValidator, RedeemerType, DatumType) +import Ledger.Typed.Scripts (DatumType, MonetaryPolicy, + RedeemerType, TypedValidator) import qualified Ledger.Typed.Scripts as Scripts import Plutus.Contract import Plutus.Contracts.Core (Aave, Reserve (..)) diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index 007d7413a..aba847325 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -22,14 +22,14 @@ import qualified Data.Map as Map import Data.Text (Text, pack) import qualified Data.Text as Text import Data.Void (Void) +import Ext.Plutus.Ledger.Contexts (scriptInputsAt) import Ledger hiding (getDatum, singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints import Ledger.Constraints.TxConstraints as Constraints import qualified Ledger.Scripts as UntypedScripts +import Ledger.Typed.Scripts (DatumType, RedeemerType) import qualified Ledger.Typed.Scripts as Scripts -import Ledger.Typed.Scripts (RedeemerType, DatumType) -import Ext.Plutus.Ledger.Contexts (scriptInputsAt) import Playground.Contract import Plutus.Contract hiding (when) import qualified Plutus.Contracts.TxUtils as TxUtils From fb0ee9293fa95b9005631e15a2df299da4a4e326 Mon Sep 17 00:00:00 2001 From: stanislav-az Date: Mon, 14 Jun 2021 23:13:47 +0700 Subject: [PATCH 093/169] add todos --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 6 ++++++ MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs | 1 + 2 files changed, 7 insertions(+) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 76367fe3d..bcbb17d96 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -126,6 +126,8 @@ makeAaveValidator :: Aave -> ScriptContext -> Bool makeAaveValidator aave datum StartRedeemer ctx = trace "StartRedeemer" $ validateStart aave datum ctx +-- TODO ? further validators should check that ReservesDatum & UserConfigsDatum transormation happens one time +-- & ReserveFundsDatum transormation happens at least one time makeAaveValidator aave datum (DepositRedeemer userConfigId) ctx = trace "DepositRedeemer" $ validateDeposit aave datum ctx userConfigId makeAaveValidator aave datum (WithdrawRedeemer userConfigId) ctx = trace "WithdrawRedeemer" $ validateWithdraw aave datum ctx userConfigId makeAaveValidator aave datum (BorrowRedeemer userConfigId) ctx = trace "BorrowRedeemer" $ validateBorrow aave datum ctx userConfigId @@ -178,6 +180,7 @@ validateDeposit aave (ReservesDatum stateToken reserves) ctx userConfigId = validateDeposit _ _ _ _ = trace "validateDeposit: Lending Pool Datum management is not allowed" False +-- TODO withdraw should check if there is enough collateral remains deposited so that health factor is >= 1.05 validateWithdraw :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool validateWithdraw aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId = -- TODO add implementation for this case @@ -383,3 +386,6 @@ aaveAddress = Ledger.scriptAddress . aaveValidator aave :: CurrencySymbol -> Aave aave protocol = Aave (assetClass protocol aaveProtocolName) + +oneAdaInLovelace :: Integer +oneAdaInLovelace = 1000000 diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index f499b4040..45edb4531 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -280,6 +280,7 @@ repay aave RepayParams {..} = do _ <- awaitTxConfirmed $ txId ledgerTx pure () +-- TODO add flipUserUseReserveAsCollateral type AaveUserSchema = BlockchainActions .\/ Endpoint "deposit" DepositParams From de02d6d062c2b62859e9f1f2f6d4cb6ef9c29a8e Mon Sep 17 00:00:00 2001 From: megakaban Date: Tue, 15 Jun 2021 06:38:59 +0700 Subject: [PATCH 094/169] Rough cut --- .../client/scripts/start-chrome.sh | 2 +- .../{Components => Component}/AmountForm.purs | 6 +- .../client/src/Component/Contract.purs | 221 +++++++++++ .../client/src/Component/MainPage.purs | 190 ++++++++++ .../client/src/Component/Utils.purs | 22 ++ .../client/src/Components/App.purs | 353 ------------------ MetaLamp/lending-pool/client/src/Main.purs | 2 +- 7 files changed, 438 insertions(+), 358 deletions(-) rename MetaLamp/lending-pool/client/src/{Components => Component}/AmountForm.purs (93%) create mode 100644 MetaLamp/lending-pool/client/src/Component/Contract.purs create mode 100644 MetaLamp/lending-pool/client/src/Component/MainPage.purs create mode 100644 MetaLamp/lending-pool/client/src/Component/Utils.purs delete mode 100644 MetaLamp/lending-pool/client/src/Components/App.purs diff --git a/MetaLamp/lending-pool/client/scripts/start-chrome.sh b/MetaLamp/lending-pool/client/scripts/start-chrome.sh index 15694ecd5..776df5378 100755 --- a/MetaLamp/lending-pool/client/scripts/start-chrome.sh +++ b/MetaLamp/lending-pool/client/scripts/start-chrome.sh @@ -1 +1 @@ -google-chrome --disable-web-security --user-data-dir=/chrome-temp \ No newline at end of file +chromium --disable-web-security --user-data-dir=/chrome-temp \ No newline at end of file diff --git a/MetaLamp/lending-pool/client/src/Components/AmountForm.purs b/MetaLamp/lending-pool/client/src/Component/AmountForm.purs similarity index 93% rename from MetaLamp/lending-pool/client/src/Components/AmountForm.purs rename to MetaLamp/lending-pool/client/src/Component/AmountForm.purs index ee9dd24ae..fca6c50e3 100644 --- a/MetaLamp/lending-pool/client/src/Components/AmountForm.purs +++ b/MetaLamp/lending-pool/client/src/Component/AmountForm.purs @@ -1,4 +1,4 @@ -module Components.AmountForm where +module Component.AmountForm where import Prelude import Data.Array (head) @@ -30,8 +30,8 @@ type Input initialState :: Input -> State initialState amounts = { amounts, name: _.name <$> head amounts, amount: Nothing } -amountForm :: forall query m. H.Component HH.HTML query Input Output m -amountForm = +component :: forall query m. H.Component HH.HTML query Input Output m +component = H.mkComponent { initialState: initialState , render diff --git a/MetaLamp/lending-pool/client/src/Component/Contract.purs b/MetaLamp/lending-pool/client/src/Component/Contract.purs new file mode 100644 index 000000000..e8e84acfb --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Component/Contract.purs @@ -0,0 +1,221 @@ +module Component.Contract where + +import Prelude +import Business.Aave as Aave +import Capability.Contract (ContractId) +import Capability.LogMessages (class LogMessages) +import Capability.PollContract (class PollContract) +import Component.AmountForm as AmountForm +import Component.Utils (runRD) +import Control.Monad.Except (lift, runExceptT, throwError) +import Data.Array (mapWithIndex) +import Data.BigInteger (BigInteger) +import Data.Either (either) +import Data.Foldable (find) +import Data.Generic.Rep (class Generic) +import Data.Generic.Rep.Show (genericShow) +import Data.Json.JsonTuple (JsonTuple(..)) +import Data.Lens (Lens') +import Data.Lens.Record (prop) +import Data.Maybe (Maybe(..)) +import Data.Symbol (SProxy(..)) +import Data.Tuple (Tuple(..)) +import Halogen as H +import Halogen.HTML as HH +import Network.RemoteData (RemoteData(..)) +import Network.RemoteData as RD +import Plutus.Contracts.Endpoints (BorrowParams(..), DepositParams(..), RepayParams(..), WithdrawParams(..)) +import Plutus.V1.Ledger.Crypto (PubKeyHash) +import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..), Value) +import View.FundsTable (fundsTable) +import View.RemoteDataState (remoteDataState) + +type State + = { contractId :: ContractId + , walletPubKey :: PubKeyHash + , reserves :: Array { amount :: BigInteger, asset :: AssetClass } + , userFunds :: RemoteData String Value + , deposit :: RemoteData String Unit + , withdraw :: RemoteData String Unit + , borrow :: RemoteData String Unit + , repay :: RemoteData String Unit + , submit :: RemoteData String Unit + } + +_userFunds :: Lens' State (RemoteData String Value) +_userFunds = prop (SProxy :: SProxy "userFunds") + +_deposit :: Lens' State (RemoteData String Unit) +_deposit = prop (SProxy :: SProxy "deposit") + +_withdraw :: Lens' State (RemoteData String Unit) +_withdraw = prop (SProxy :: SProxy "withdraw") + +_borrow :: Lens' State (RemoteData String Unit) +_borrow = prop (SProxy :: SProxy "borrow") + +_repay :: Lens' State (RemoteData String Unit) +_repay = prop (SProxy :: SProxy "repay") + +_submit :: Lens' State (RemoteData String Unit) +_submit = prop (SProxy :: SProxy "submit") + +type Input + = { contractId :: ContractId + , walletPubKey :: PubKeyHash + , reserves :: Array { amount :: BigInteger, asset :: AssetClass } + } + +data Output + = SubmitSuccess + +initialState :: Input -> State +initialState { contractId, walletPubKey, reserves } = + { contractId + , walletPubKey + , reserves + , userFunds: NotAsked + , withdraw: NotAsked + , deposit: NotAsked + , borrow: NotAsked + , repay: NotAsked + , submit: NotAsked + } + +data Action + = Init + | GetUserFunds + | GetUpdates + | Deposit { amount :: BigInteger, asset :: AssetClass } + | Withdraw { amount :: BigInteger, asset :: AssetClass } + | Borrow { amount :: BigInteger, asset :: AssetClass } + | Repay { amount :: BigInteger, asset :: AssetClass } + | OnSubmitAmount SubmitOperation AmountForm.Output + +-- potentially should be separate actions - just a convenience for now, while they are identical +data SubmitOperation + = SubmitDeposit + | SubmitWithdraw + | SubmitBorrow + | SubmitRepay + +derive instance genericSubmitOperation :: Generic SubmitOperation _ + +instance showSubmitOperation :: Show SubmitOperation where + show = genericShow + +type Slots + = ( amountForm :: forall query. H.Slot query AmountForm.Output Int ) + +_amountForm = SProxy :: SProxy "amountForm" + +component :: + forall m query. + LogMessages m => + PollContract m => + H.Component HH.HTML query Input Output m +component = + H.mkComponent + { initialState + , render + , eval: H.mkEval H.defaultEval { handleAction = handleAction, initialize = Just Init } + } + where + handleAction :: Action -> H.HalogenM State Action Slots Output m Unit + handleAction = case _ of + Init -> handleAction GetUserFunds + GetUserFunds -> + runRD _userFunds <<< runExceptT + $ do + { contractId, walletPubKey } <- lift H.get + lift (Aave.fundsAt contractId walletPubKey) >>= either (throwError <<< show) pure + GetUpdates -> do + handleAction GetUserFunds + H.raise SubmitSuccess + Deposit { amount, asset } -> + runRD _deposit <<< runExceptT + $ do + { contractId, walletPubKey } <- lift H.get + lift (Aave.deposit contractId $ DepositParams { dpAmount: amount, dpAsset: asset, dpOnBehalfOf: walletPubKey }) + >>= either (throwError <<< show) (const <<< lift <<< handleAction $ GetUpdates) + Withdraw { amount, asset } -> + runRD _withdraw <<< runExceptT + $ do + { contractId, walletPubKey } <- lift H.get + lift (Aave.withdraw contractId $ WithdrawParams { wpAmount: amount, wpAsset: asset, wpUser: walletPubKey }) + >>= either (throwError <<< show) (const <<< lift <<< handleAction $ GetUpdates) + Borrow { amount, asset } -> + runRD _borrow <<< runExceptT + $ do + { contractId, walletPubKey } <- lift H.get + lift (Aave.borrow contractId $ BorrowParams { bpAmount: amount, bpAsset: asset, bpOnBehalfOf: walletPubKey }) + >>= either (throwError <<< show) (const <<< lift <<< handleAction $ GetUpdates) + Repay { amount, asset } -> + runRD _repay <<< runExceptT + $ do + { contractId, walletPubKey } <- lift H.get + lift (Aave.repay contractId $ RepayParams { rpAmount: amount, rpAsset: asset, rpOnBehalfOf: walletPubKey }) + >>= either (throwError <<< show) (const <<< lift <<< handleAction $ GetUpdates) + OnSubmitAmount operation (AmountForm.Submit { name, amount }) -> + runRD _submit <<< runExceptT + $ do + { reserves } <- lift H.get + case find (\r -> getAssetName r.asset == name) reserves of + Just ({ asset }) -> case operation of + SubmitDeposit -> do + lift $ handleAction (Deposit { amount, asset }) + { deposit } <- lift H.get + RD.maybe + (throwError $ "Submit deposit failed: " <> show deposit) + (const <<< pure $ unit) + deposit + SubmitWithdraw -> do + lift $ handleAction (Withdraw { amount, asset }) + { withdraw } <- lift H.get + RD.maybe + (throwError $ "Submit withdraw failed: " <> show withdraw) + (const <<< pure $ unit) + withdraw + SubmitBorrow -> do + lift $ handleAction (Borrow { amount, asset }) + { borrow } <- lift H.get + RD.maybe + (throwError $ "Submit borrow failed: " <> show borrow) + (const <<< pure $ unit) + borrow + SubmitRepay -> do + lift $ handleAction (Repay { amount, asset }) + { repay } <- lift H.get + RD.maybe + (throwError $ "Submit repay failed: " <> show repay) + (const <<< pure $ unit) + repay + Nothing -> throwError "Asset name not found" + + render :: State -> H.ComponentHTML Action Slots m + render state = + HH.div_ + [ remoteDataState + (\userFunds -> HH.div_ [ HH.h2_ [ HH.text "User funds" ], fundsTable userFunds ]) + state.userFunds + , case state.submit of + NotAsked -> HH.div_ [] + Loading -> HH.div_ [] + Failure e -> HH.h2_ [ HH.text $ "Error: " <> show e ] + Success _ -> HH.div_ [] + , HH.div_ + $ mapWithIndex + ( \index (Tuple title operation) -> + HH.h2_ + [ HH.text title + , HH.slot _amountForm index AmountForm.component (reservesToAmounts state.reserves) (Just <<< (OnSubmitAmount operation)) + ] + ) + [ Tuple "Deposit" SubmitDeposit, Tuple "Withdraw" SubmitWithdraw, Tuple "Borrow" SubmitBorrow, Tuple "Repay" SubmitRepay ] + ] + +reservesToAmounts :: Array { amount :: BigInteger, asset :: AssetClass } -> Array AmountForm.AmountInfo +reservesToAmounts = map (\{ asset, amount } -> { name: getAssetName asset, amount }) + +getAssetName :: AssetClass -> String +getAssetName (AssetClass { unAssetClass: JsonTuple (Tuple _ (TokenName { unTokenName: name })) }) = name diff --git a/MetaLamp/lending-pool/client/src/Component/MainPage.purs b/MetaLamp/lending-pool/client/src/Component/MainPage.purs new file mode 100644 index 000000000..0fb07d50b --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Component/MainPage.purs @@ -0,0 +1,190 @@ +module Component.MainPage where + +import Prelude +import Business.Aave as Aave +import Capability.Contract (ContractId(..)) +import Capability.LogMessages (class LogMessages) +import Capability.PollContract (class PollContract) +import Component.Contract as Contract +import Component.Contract as ContractComponent +import Component.Utils (runRD) +import Control.Monad.Except (lift, runExceptT, throwError) +import Control.Parallel (parTraverse) +import Data.Array (groupBy, head, mapWithIndex, zip) +import Data.Array.NonEmpty as NEA +import Data.BigInteger (BigInteger) +import Data.Either (either) +import Data.Json.JsonTuple (JsonTuple(..)) +import Data.Json.JsonUUID (JsonUUID(..)) +import Data.Lens (Lens') +import Data.Lens.Record (prop) +import Data.Maybe (Maybe(..)) +import Data.Symbol (SProxy(..)) +import Data.Tuple (Tuple(..)) +import Data.UUID (toString) as UUID +import Halogen as H +import Halogen.HTML as HH +import Network.RemoteData (RemoteData(..)) +import Network.RemoteData as RD +import Network.RemoteData as RemoteData +import Plutus.Contracts.Core (Reserve(..), UserConfig) +import Plutus.PAB.Simulation (AaveContracts) +import Plutus.PAB.Webserver.Types (ContractInstanceClientState(..)) +import Plutus.V1.Ledger.Crypto (PubKeyHash) +import Plutus.V1.Ledger.Value (AssetClass) +import PlutusTx.AssocMap as Map +import View.RemoteDataState (remoteDataState) +import View.ReserveInfo (reserveInfo) +import View.UsersTable (poolUsers) +import Wallet.Types (ContractInstanceId(..)) + +type State + = { contracts :: RemoteData String (Array (ContractInstanceClientState AaveContracts)) + , pubKeys :: RemoteData String (Array PubKeyHash) + , users :: RemoteData String (Map.Map (JsonTuple AssetClass PubKeyHash) UserConfig) + , reserves :: RemoteData String (Map.Map AssetClass Reserve) + } + +_contracts :: Lens' State (RemoteData String (Array (ContractInstanceClientState AaveContracts))) +_contracts = prop (SProxy :: SProxy "contracts") + +_pubKeys :: Lens' State (RemoteData String (Array PubKeyHash)) +_pubKeys = prop (SProxy :: SProxy "pubKeys") + +_users :: Lens' State (RemoteData String (Map.Map (JsonTuple AssetClass PubKeyHash) UserConfig)) +_users = prop (SProxy :: SProxy "users") + +_reserves :: Lens' State (RemoteData String (Map.Map AssetClass Reserve)) +_reserves = prop (SProxy :: SProxy "reserves") + +data Action + = Init + | GetContracts + | GetPubKeys + | GetUserConfigs + | GetReserves + | OnSubmitSuccess ContractComponent.Output + +type Slots + = ( contract :: forall query. H.Slot query ContractComponent.Output Int ) + +_contract = SProxy :: SProxy "contract" + +initialState :: forall input. input -> State +initialState _ = { contracts: NotAsked, pubKeys: NotAsked, users: NotAsked, reserves: NotAsked } + +component :: + forall m query input output. + LogMessages m => + PollContract m => + H.Component HH.HTML query input output m +component = + H.mkComponent + { initialState + , render + , eval: H.mkEval H.defaultEval { handleAction = handleAction, initialize = Just Init } + } + where + handleAction :: Action -> H.HalogenM State Action Slots output m Unit + handleAction = case _ of + Init -> do + handleAction GetContracts + handleAction GetPubKeys + handleAction GetReserves + handleAction GetUserConfigs + OnSubmitSuccess _ -> do + handleAction GetReserves + handleAction GetUserConfigs + GetContracts -> + runRD _contracts <<< runExceptT + $ lift Aave.getAaveContracts + >>= either (throwError <<< show) pure + GetPubKeys -> + runRD _pubKeys <<< runExceptT + $ do + state <- lift H.get + contracts <- RemoteData.maybe (throwError "No contracts found") pure state.contracts + parTraverse + ( \(ContractInstanceClientState { cicContract }) -> + lift (Aave.ownPubKey (toContractIdParam cicContract)) >>= either (throwError <<< show) pure + ) + contracts + GetUserConfigs -> + runRD _users <<< runExceptT + $ do + state <- lift H.get + contracts <- + RD.maybe (throwError "contracts are missing") pure + $ state.contracts + case head contracts of + Nothing -> throwError "No contract" + Just (ContractInstanceClientState { cicContract }) -> lift (Aave.users (toContractIdParam cicContract)) >>= either (throwError <<< show) pure + GetReserves -> + runRD _reserves <<< runExceptT + $ do + state <- lift H.get + contracts <- + RD.maybe (throwError "contracts are missing") pure + $ state.contracts + case head contracts of + Nothing -> throwError "No contract" + Just (ContractInstanceClientState { cicContract }) -> lift (Aave.reserves (toContractIdParam cicContract)) >>= either (throwError <<< show) pure + + render :: State -> H.ComponentHTML Action Slots m + render state = + HH.div_ + [ remoteDataState + ( \reserves -> + HH.div_ + $ [ HH.h2_ [ HH.text "Pool funds" ] ] + <> map (\(Tuple a r) -> reserveInfo a r) reserves + ) + (map Map.toTuples state.reserves) + , remoteDataState + ( \userMap -> + let + getAsset (Tuple (JsonTuple (Tuple asset _)) _) = asset + + getName (Tuple (JsonTuple (Tuple _ pkh)) _) = show pkh + + getUser (Tuple _ user) = user + + usersByAsset = groupBy (\a b -> getAsset a == getAsset b) <<< Map.toTuples $ userMap + + html = + map + ( \users -> + poolUsers + (getAsset <<< NEA.head $ users) + (map (\user -> Tuple (getName user) (getUser user)) $ users) + ) + usersByAsset + in + HH.div_ + $ [ HH.h2_ [ HH.text "Users:" ], HH.div_ html ] + ) + state.users + , remoteDataState + ( \{ contracts, pubKeys, reserves } -> + HH.div_ + $ mapWithIndex + ( \index (Tuple (ContractInstanceClientState { cicContract }) walletPubKey) -> + HH.slot + _contract + index + Contract.component + ({ contractId: toContractIdParam cicContract, walletPubKey, reserves: toReserveInfo reserves }) + (Just <<< OnSubmitSuccess) + ) + (zip contracts pubKeys) + ) + ({ contracts: _, pubKeys: _, reserves: _ } <$> state.contracts <*> state.pubKeys <*> state.reserves) + ] + +toContractIdParam :: ContractInstanceId -> ContractId +toContractIdParam (ContractInstanceId { unContractInstanceId: JsonUUID uuid }) = ContractId <<< UUID.toString $ uuid + +toReserveInfo :: Map.Map AssetClass Reserve -> Array { amount :: BigInteger, asset :: AssetClass } +toReserveInfo = map toInfo <<< Map.toTuples + where + toInfo (Tuple asset (Reserve { rAmount })) = { asset, amount: rAmount } diff --git a/MetaLamp/lending-pool/client/src/Component/Utils.purs b/MetaLamp/lending-pool/client/src/Component/Utils.purs new file mode 100644 index 000000000..a4a36ce49 --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Component/Utils.purs @@ -0,0 +1,22 @@ +module Component.Utils where + +import Prelude +import Capability.LogMessages (class LogMessages, logError) +import Data.Either (Either) +import Data.Lens (Lens') +import Halogen as H +import Network.RemoteData (RemoteData(..)) +import Utils.WithRemoteData (runRDWith) + +runRD :: + forall e a s action slots output m. + LogMessages m => + Show e => + (Lens' s (RemoteData e a)) -> + H.HalogenM s action slots output m (Either e a) -> + H.HalogenM s action slots output m Unit +runRD selector action = + (runRDWith selector $ action) + >>= case _ of + Failure e -> logError <<< show $ e + _ -> pure unit diff --git a/MetaLamp/lending-pool/client/src/Components/App.purs b/MetaLamp/lending-pool/client/src/Components/App.purs deleted file mode 100644 index 4ce9134a9..000000000 --- a/MetaLamp/lending-pool/client/src/Components/App.purs +++ /dev/null @@ -1,353 +0,0 @@ -module Components.App where - -import Prelude -import Business.Aave as Aave -import Capability.Contract (ContractId(..)) -import Capability.LogMessages (class LogMessages, logError) -import Capability.PollContract (class PollContract) -import Components.AmountForm as AmountForm -import Control.Monad.Except (lift, runExceptT, throwError) -import Data.Array (groupBy, mapWithIndex) -import Data.Array.NonEmpty as NEA -import Data.BigInteger (BigInteger, fromInt) -import Data.Either (Either, either) -import Data.Foldable (find) -import Data.Generic.Rep (class Generic) -import Data.Generic.Rep.Show (genericShow) -import Data.Json.JsonTuple (JsonTuple(..)) -import Data.Json.JsonUUID (JsonUUID(..)) -import Data.Lens (Lens') -import Data.Lens.Record (prop) -import Data.Maybe (Maybe(..), maybe) -import Data.Newtype (unwrap) -import Data.Symbol (SProxy(..)) -import Data.Tuple (Tuple(..)) -import Data.UUID (toString) as UUID -import Halogen as H -import Halogen.HTML as HH -import Halogen.HTML.Events as HE -import Network.RemoteData (RemoteData(..)) -import Network.RemoteData as RD -import Plutus.Contracts.Core (Reserve(..), UserConfig) -import Plutus.Contracts.Endpoints (BorrowParams(..), DepositParams(..), RepayParams(..), WithdrawParams(..)) -import Plutus.PAB.Webserver.Types (ContractInstanceClientState(..)) -import Plutus.V1.Ledger.Crypto (PubKeyHash) -import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..), Value) -import PlutusTx.AssocMap as Map -import Utils.WithRemoteData (runRDWith) -import View.FundsTable (fundsTable) -import View.RemoteDataState (remoteDataState) -import View.ReserveInfo (reserveInfo) -import View.UsersTable (poolUsers) -import Wallet.Emulator.Wallet (Wallet(..)) -import Wallet.Types (ContractInstanceId(..)) - -type State - = { contractId :: RemoteData String ContractId - , walletPubKey :: RemoteData String PubKeyHash - , userFunds :: RemoteData String Value - , users :: RemoteData String (Map.Map (JsonTuple AssetClass PubKeyHash) UserConfig) - , reserves :: RemoteData String (Map.Map AssetClass Reserve) - , deposit :: RemoteData String Unit - , withdraw :: RemoteData String Unit - , borrow :: RemoteData String Unit - , repay :: RemoteData String Unit - , submit :: RemoteData String Unit - } - -_contractId :: Lens' State (RemoteData String ContractId) -_contractId = prop (SProxy :: SProxy "contractId") - -_walletPubKey :: Lens' State (RemoteData String PubKeyHash) -_walletPubKey = prop (SProxy :: SProxy "walletPubKey") - -_userFunds :: Lens' State (RemoteData String Value) -_userFunds = prop (SProxy :: SProxy "userFunds") - -_users :: Lens' State (RemoteData String (Map.Map (JsonTuple AssetClass PubKeyHash) UserConfig)) -_users = prop (SProxy :: SProxy "users") - -_reserves :: Lens' State (RemoteData String (Map.Map AssetClass Reserve)) -_reserves = prop (SProxy :: SProxy "reserves") - -_deposit :: Lens' State (RemoteData String Unit) -_deposit = prop (SProxy :: SProxy "deposit") - -_withdraw :: Lens' State (RemoteData String Unit) -_withdraw = prop (SProxy :: SProxy "withdraw") - -_borrow :: Lens' State (RemoteData String Unit) -_borrow = prop (SProxy :: SProxy "borrow") - -_repay :: Lens' State (RemoteData String Unit) -_repay = prop (SProxy :: SProxy "repay") - -_submit :: Lens' State (RemoteData String Unit) -_submit = prop (SProxy :: SProxy "submit") - -initialState :: forall input. input -> State -initialState _ = - { contractId: NotAsked - , walletPubKey: NotAsked - , userFunds: NotAsked - , users: NotAsked - , reserves: NotAsked - , withdraw: NotAsked - , deposit: NotAsked - , borrow: NotAsked - , repay: NotAsked - , submit: NotAsked - } - -data Action - = Init - | GetContractAt Wallet - | GetWalletPubKey - | GetUserFunds - | GetUserConfigs - | GetReserves - | GetUpdates - | Deposit { amount :: BigInteger, asset :: AssetClass } - | Withdraw { amount :: BigInteger, asset :: AssetClass } - | Borrow { amount :: BigInteger, asset :: AssetClass } - | Repay { amount :: BigInteger, asset :: AssetClass } - | SubmitAmount SubmitOperation AmountForm.Output - --- potentially should be separate actions - just a convenience for now, while they are identical -data SubmitOperation - = SubmitDeposit - | SubmitWithdraw - | SubmitBorrow - | SubmitRepay - -derive instance genericSubmitOperation :: Generic SubmitOperation _ - -instance showSubmitOperation :: Show SubmitOperation where - show = genericShow - -toContractIdParam :: ContractInstanceId -> ContractId -toContractIdParam (ContractInstanceId { unContractInstanceId: JsonUUID uuid }) = ContractId <<< UUID.toString $ uuid - -handleException :: forall e a m. LogMessages m => Show e => Either e a -> m Unit -handleException = either (logError <<< show) (const $ pure unit) - -type Slots - = ( amountForm :: forall query. H.Slot query AmountForm.Output Int ) - -_amountForm = SProxy :: SProxy "amountForm" - -component :: - forall input m query output. - LogMessages m => - PollContract m => - H.Component HH.HTML query input output m -component = - H.mkComponent - { initialState - , render - , eval: H.mkEval H.defaultEval { handleAction = handleAction } - } - where - runRD :: - forall e a. - Show e => - (Lens' State (RemoteData e a)) -> - H.HalogenM State Action Slots output m (Either e a) -> - H.HalogenM State Action Slots output m Unit - runRD selector action = - (runRDWith selector $ action) - >>= case _ of - Failure e -> logError <<< show $ e - _ -> pure unit - - handleAction :: Action -> H.HalogenM State Action Slots output m Unit - handleAction = case _ of - Init -> do - handleAction (GetContractAt $ Wallet { getWallet: fromInt 2 }) - handleAction GetWalletPubKey - handleAction GetUpdates - GetContractAt wallet -> - runRD _contractId <<< runExceptT - $ do - instances <- lift Aave.getAaveContracts >>= either (throwError <<< show) pure - let - contract = find (\(ContractInstanceClientState i) -> i.cicWallet == wallet) instances - maybe - (throwError "Contract instance not found") - (pure <<< toContractIdParam <<< _.cicContract <<< unwrap) - contract - GetWalletPubKey -> - runRD _walletPubKey <<< runExceptT - $ do - state <- lift H.get - cid <- RD.maybe (throwError "contractId is missing") pure state.contractId - lift (Aave.ownPubKey cid) >>= either (throwError <<< show) pure - GetUserFunds -> - runRD _userFunds <<< runExceptT - $ do - state <- lift H.get - { cid, pkh } <- - RD.maybe (throwError "contractId or publicKey are missing") pure - $ { cid: _, pkh: _ } - <$> state.contractId - <*> state.walletPubKey - lift (Aave.fundsAt cid pkh) >>= either (throwError <<< show) pure - GetUserConfigs -> - runRD _users <<< runExceptT - $ do - state <- lift H.get - cid <- RD.maybe (throwError "contractId is missing") pure state.contractId - lift (Aave.users cid) >>= either (throwError <<< show) pure - GetReserves -> - runRD _reserves <<< runExceptT - $ do - state <- lift H.get - cid <- RD.maybe (throwError "contractId or publicKey are missing") pure $ state.contractId - lift (Aave.reserves cid) >>= either (throwError <<< show) pure - GetUpdates -> do - handleAction GetUserFunds - handleAction GetReserves - handleAction GetUserConfigs - Deposit { amount, asset } -> - runRD _deposit <<< runExceptT - $ do - state <- lift H.get - { cid, pkh } <- - RD.maybe (throwError "contractId or publicKey are missing") pure - $ { cid: _, pkh: _ } - <$> state.contractId - <*> state.walletPubKey - lift (Aave.deposit cid $ DepositParams { dpAmount: amount, dpAsset: asset, dpOnBehalfOf: pkh }) - >>= either (throwError <<< show) (const <<< pure $ unit) - Withdraw { amount, asset } -> - runRD _withdraw <<< runExceptT - $ do - state <- lift H.get - { cid, pkh } <- - RD.maybe (throwError "contractId or publicKey are missing") pure - $ { cid: _, pkh: _ } - <$> state.contractId - <*> state.walletPubKey - lift (Aave.withdraw cid $ WithdrawParams { wpAmount: amount, wpAsset: asset, wpUser: pkh }) - >>= either (throwError <<< show) (const <<< pure $ unit) - Borrow { amount, asset } -> - runRD _borrow <<< runExceptT - $ do - state <- lift H.get - { cid, pkh } <- - RD.maybe (throwError "contractId or publicKey are missing") pure - $ { cid: _, pkh: _ } - <$> state.contractId - <*> state.walletPubKey - lift (Aave.borrow cid $ BorrowParams { bpAmount: amount, bpAsset: asset, bpOnBehalfOf: pkh }) - >>= either (throwError <<< show) (const <<< pure $ unit) - Repay { amount, asset } -> - runRD _repay <<< runExceptT - $ do - state <- lift H.get - { cid, pkh } <- - RD.maybe (throwError "contractId or publicKey are missing") pure - $ { cid: _, pkh: _ } - <$> state.contractId - <*> state.walletPubKey - lift (Aave.repay cid $ RepayParams { rpAmount: amount, rpAsset: asset, rpOnBehalfOf: pkh }) - >>= either (throwError <<< show) (const <<< pure $ unit) - SubmitAmount operation (AmountForm.Submit { name, amount }) -> - runRD _submit <<< runExceptT - $ do - state <- lift H.get - reserves <- RD.maybe (throwError "reserves are missing") pure $ state.reserves - case find (\(Tuple k _) -> getAssetName k == name) (Map.toTuples reserves) of - Just (Tuple asset _) -> case operation of - SubmitDeposit -> do - lift $ handleAction (Deposit { amount, asset }) - { deposit } <- lift H.get - RD.maybe - (throwError $ "Submit deposit failed: " <> show deposit) - (const <<< lift <<< handleAction $ GetUpdates) - deposit - SubmitWithdraw -> do - lift $ handleAction (Withdraw { amount, asset }) - { withdraw } <- lift H.get - RD.maybe - (throwError $ "Submit withdraw failed: " <> show withdraw) - (const <<< lift <<< handleAction $ GetUpdates) - withdraw - SubmitBorrow -> do - lift $ handleAction (Borrow { amount, asset }) - { borrow } <- lift H.get - RD.maybe - (throwError $ "Submit borrow failed: " <> show borrow) - (const <<< lift <<< handleAction $ GetUpdates) - borrow - SubmitRepay -> do - lift $ handleAction (Repay { amount, asset }) - { repay } <- lift H.get - RD.maybe - (throwError $ "Submit repay failed: " <> show repay) - (const <<< lift <<< handleAction $ GetUpdates) - repay - Nothing -> throwError "Asset name not found" - - render :: State -> H.ComponentHTML Action Slots m - render state = - HH.div_ - [ HH.button [ HE.onClick \_ -> Just Init ] [ HH.text "Start" ] - , remoteDataState - (\userFunds -> HH.div_ [ HH.h2_ [ HH.text "User funds" ], fundsTable userFunds ]) - state.userFunds - , remoteDataState - ( \reserves -> - HH.div_ - $ [ HH.h2_ [ HH.text "Pool funds" ] ] - <> map (\(Tuple a r) -> reserveInfo a r) reserves - ) - (map Map.toTuples state.reserves) - , remoteDataState - ( \userMap -> - let - getAsset (Tuple (JsonTuple (Tuple asset _)) _) = asset - - getName (Tuple (JsonTuple (Tuple _ pkh)) _) = show pkh - - getUser (Tuple _ user) = user - - usersByAsset = groupBy (\a b -> getAsset a == getAsset b) <<< Map.toTuples $ userMap - - html = - map - ( \users -> - poolUsers - (getAsset <<< NEA.head $ users) - (map (\user -> Tuple (getName user) (getUser user)) $ users) - ) - usersByAsset - in - HH.div_ - $ [ HH.h2_ [ HH.text "Users:" ], HH.div_ html ] - ) - state.users - , case state.submit of - NotAsked -> HH.div_ [] - Loading -> HH.div_ [] - Failure e -> HH.h2_ [ HH.text $ "Error: " <> show e ] - Success _ -> HH.div_ [] - , remoteDataState - ( \amounts -> - HH.div_ - $ mapWithIndex - ( \index (Tuple title operation) -> - HH.h2_ [ HH.text title, HH.slot _amountForm index AmountForm.amountForm amounts (Just <<< (SubmitAmount operation)) ] - ) - [ Tuple "Deposit" SubmitDeposit, Tuple "Withdraw" SubmitWithdraw, Tuple "Borrow" SubmitBorrow, Tuple "Repay" SubmitRepay ] - ) - (map reservesToAmounts state.reserves) - ] - -reservesToAmounts :: Map.Map AssetClass Reserve -> Array AmountForm.AmountInfo -reservesToAmounts = map toInfo <<< Map.toTuples - where - toInfo (Tuple k (Reserve { rAmount })) = { name: getAssetName k, amount: rAmount } - -getAssetName :: AssetClass -> String -getAssetName (AssetClass { unAssetClass: JsonTuple (Tuple _ (TokenName { unTokenName: name })) }) = name diff --git a/MetaLamp/lending-pool/client/src/Main.purs b/MetaLamp/lending-pool/client/src/Main.purs index 8265aad06..1b3ce2ac2 100644 --- a/MetaLamp/lending-pool/client/src/Main.purs +++ b/MetaLamp/lending-pool/client/src/Main.purs @@ -1,7 +1,7 @@ module Main where import Prelude -import Components.App as App +import Component.MainPage as App import AppAff (runAppM) import Effect (Effect) import Effect.Unsafe (unsafePerformEffect) From 780a327aa43f26e1c8ea6342e145753756f5d0bd Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 15 Jun 2021 19:45:43 +0700 Subject: [PATCH 095/169] refactor datum --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 13 ++++++++++++- .../lending-pool/src/Plutus/Contracts/Endpoints.hs | 3 ++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index bcbb17d96..99b05d8e5 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -88,13 +88,16 @@ PlutusTx.unstableMakeIsData ''AaveRedeemer PlutusTx.makeLift ''AaveRedeemer -- TODO: solve purescript generation issue with type synonyms +type UserConfigId = (AssetClass, PubKeyHash) type LendingPoolOperator = PubKeyHash +type Oracles = AssocMap.Map AssetClass Integer -- Shows how many lovelaces should be paid for a specific asset data AaveDatum = LendingPoolDatum LendingPoolOperator | ReservesDatum AssetClass (AssocMap.Map AssetClass Reserve) - | UserConfigsDatum AssetClass (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) | ReserveFundsDatum + | UserConfigsDatum AssetClass (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) + | UserFundsDatum PubKeyHash deriving stock (Show) PlutusTx.unstableMakeIsData ''AaveDatum @@ -111,6 +114,14 @@ pickReserves :: AaveDatum -> Maybe (AssetClass, AssocMap.Map AssetClass Reserve) pickReserves (ReservesDatum stateToken configs) = Just (stateToken, configs) pickReserves _ = Nothing +-- TODO calculate these params in new module: +-- totalCollateralInLovelace :: AssocMap.Map AssetClass Integer -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig -> Either String Integer +-- totalCollateralInLovelace oracles userConfigs = 0 +-- totalDebtInLovelace = 0 +-- doesCollateralCoverNewBorrow = amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace +-- where +-- userCollateralBalanceLovelace = totalCollateralInLovelace + data AaveScript instance Scripts.ValidatorTypes AaveScript where type instance RedeemerType AaveScript = AaveRedeemer diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 45edb4531..00f401506 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -280,7 +280,8 @@ repay aave RepayParams {..} = do _ <- awaitTxConfirmed $ txId ledgerTx pure () --- TODO add flipUserUseReserveAsCollateral +-- TODO add provideCollateral +-- TODO add revokeCollateral type AaveUserSchema = BlockchainActions .\/ Endpoint "deposit" DepositParams From 8c698653baddbbe2cd4240f847cf31e27181e308 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 15 Jun 2021 21:52:52 +0700 Subject: [PATCH 096/169] wip refactor user config --- .../lending-pool/src/Plutus/Contracts/Core.hs | 22 +++++++++++++------ .../src/Plutus/Contracts/Endpoints.hs | 9 ++++---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 99b05d8e5..fb7bed15e 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -65,10 +65,20 @@ data Reserve = Reserve PlutusTx.unstableMakeIsData ''Reserve PlutusTx.makeLift ''Reserve -data UserConfig = UserConfig +-- TODO (?) only aTokens pledged as collateral should accumulate interest +-- data UserConfig = UserConfig +-- { ucDebt :: [IncentivizedAmount] +-- , ucCollateralizedInvestment :: [IncentivizedAmount] +-- } +-- data IncentivizedAmount = IncentivizedAmount +-- { iaAmount :: Integer +-- , iaRate :: Rational +-- , iaSlot :: Slot +-- } + +newtype UserConfig = UserConfig { - ucUsingAsCollateral :: Bool, - ucDebt :: Maybe Integer + ucDebt :: Integer } deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) @@ -97,7 +107,7 @@ data AaveDatum = | ReservesDatum AssetClass (AssocMap.Map AssetClass Reserve) | ReserveFundsDatum | UserConfigsDatum AssetClass (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) - | UserFundsDatum PubKeyHash + | UserCollateralFundsDatum PubKeyHash deriving stock (Show) PlutusTx.unstableMakeIsData ''AaveDatum @@ -157,6 +167,7 @@ validateStart aave (LendingPoolDatum operator) ctx = outs -> isJust $ AssocMap.lookup scriptsDatumHash $ AssocMap.fromList outs validateStart aave _ ctx = trace "validateStart: Lending Pool Datum management is not allowed" False +-- TODO prohibit depositing asset which is not repaid validateDeposit :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId = traceIfFalse "validateDeposit: User Configs Datum change is not valid" isValidUserConfigsTransformation @@ -183,7 +194,6 @@ validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId checkRedeemerConfig :: Maybe UserConfig -> UserConfig -> Bool checkRedeemerConfig oldState newState = - ucUsingAsCollateral newState && maybe True ((ucDebt newState ==) . ucDebt) oldState validateDeposit aave (ReservesDatum stateToken reserves) ctx userConfigId = @@ -235,7 +245,6 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( debtAmount = maybe 0 (flip (-) oldDebt) (ucDebt newState) disbursementAmount = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId in debtAmount == disbursementAmount && debtAmount > 0 && disbursementAmount > 0 && - maybe (not $ ucUsingAsCollateral newState) ((ucUsingAsCollateral newState ==) . ucUsingAsCollateral) oldState validateBorrow aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateBorrow: Reserves Datum change is not valid" $ checkNegativeReservesTransformation stateToken reserves ctx userConfigId @@ -276,7 +285,6 @@ validateRepay aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(r newDebt = fromMaybe 0 $ ucDebt newState reimbursementAmount = assetClassValueOf actorSpentValue reserveId - assetClassValueOf actorRemainderValue reserveId in debtChange == reimbursementAmount && debtChange > 0 && reimbursementAmount > 0 && newDebt >= 0 && - ucUsingAsCollateral oldState == ucUsingAsCollateral newState validateRepay aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateRepay: Reserves Datum change is not valid" $ checkPositiveReservesTransformation stateToken reserves ctx userConfigId diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 00f401506..8048d9572 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -152,8 +152,7 @@ deposit aave DepositParams {..} = do forgeTx <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount let userConfigId = (rCurrency reserve, dpOnBehalfOf) - wasZeroBalance <- (== 0) <$> balanceAt dpOnBehalfOf (rAToken reserve) - userConfigsTx <- if wasZeroBalance then do + userConfigsTx <- do userConfigs <- ovValue <$> State.findAaveUserConfigs aave case AssocMap.lookup userConfigId userConfigs of Nothing -> @@ -161,10 +160,9 @@ deposit aave DepositParams {..} = do aave (Core.DepositRedeemer userConfigId) userConfigId - UserConfig { ucUsingAsCollateral = True, ucDebt = Nothing } + UserConfig { ucDebt = 0 } Just userConfig -> - State.updateUserConfig aave (Core.DepositRedeemer userConfigId) userConfigId $ userConfig { ucUsingAsCollateral = True } - else pure mempty + pure mempty reservesTx <- State.updateReserve aave (Core.DepositRedeemer userConfigId) dpAsset (reserve { rAmount = rAmount reserve + dpAmount }) @@ -259,6 +257,7 @@ data RepayParams = PlutusTx.unstableMakeIsData ''RepayParams PlutusTx.makeLift ''RepayParams +-- TODO should repay use collateral assets instead? repay :: (HasBlockchainActions s) => Aave -> RepayParams -> Contract w s Text () repay aave RepayParams {..} = do reserve <- State.findAaveReserve aave rpAsset From 674c8663875a560a3da39d9e2a41ab13d0f24e46 Mon Sep 17 00:00:00 2001 From: megakaban Date: Wed, 16 Jun 2021 03:16:37 +0700 Subject: [PATCH 097/169] Split aave into two contracts, handle multiple contract types on frontend --- MetaLamp/lending-pool/client/entry.js | 8 + .../client/src/Business/Aave.purs | 63 ++---- .../client/src/Business/AaveInfo.purs | 37 ++++ .../client/src/Business/AaveUser.purs | 40 ++++ .../client/src/Component/Contract.purs | 67 +++---- .../client/src/Component/MainPage.purs | 179 ++++++++++-------- .../client/src/Component/MainPage.scss | 17 ++ .../lending-pool/client/src/Utils/BEM.purs | 9 + .../lending-pool/generate-purs/AaveTypes.hs | 4 +- .../src/Ext/Plutus/Ledger/Contexts.hs | 5 +- .../src/Plutus/Contracts/Endpoints.hs | 99 ++++++---- .../src/Plutus/Contracts/TxUtils.hs | 4 +- .../lending-pool/src/Plutus/PAB/Simulation.hs | 42 ++-- .../lending-pool/src/Plutus/State/Update.hs | 4 +- 14 files changed, 355 insertions(+), 223 deletions(-) create mode 100644 MetaLamp/lending-pool/client/src/Business/AaveInfo.purs create mode 100644 MetaLamp/lending-pool/client/src/Business/AaveUser.purs create mode 100644 MetaLamp/lending-pool/client/src/Component/MainPage.scss create mode 100644 MetaLamp/lending-pool/client/src/Utils/BEM.purs diff --git a/MetaLamp/lending-pool/client/entry.js b/MetaLamp/lending-pool/client/entry.js index ce62e7165..b5880a3fc 100644 --- a/MetaLamp/lending-pool/client/entry.js +++ b/MetaLamp/lending-pool/client/entry.js @@ -1 +1,9 @@ import './src/Main.purs'; + +function importAll(resolve) { + resolve.keys().forEach(resolve); +} + +importAll( + require.context('./src', true, /\.scss$/) +); diff --git a/MetaLamp/lending-pool/client/src/Business/Aave.purs b/MetaLamp/lending-pool/client/src/Business/Aave.purs index 3bfced0c1..c17cc0ffa 100644 --- a/MetaLamp/lending-pool/client/src/Business/Aave.purs +++ b/MetaLamp/lending-pool/client/src/Business/Aave.purs @@ -1,33 +1,33 @@ module Business.Aave where import Prelude -import Capability.Contract (class Contract, ContractId, APIError, ContractUnit(..), Endpoint(..), getContracts) +import Capability.Contract (class Contract, APIError, ContractId(..), Endpoint, getContracts) import Capability.PollContract (class PollContract, LeftPoll(..), PollError, PollResponse, pollEndpoint) import Control.Monad.Except (runExcept, throwError, withExcept) -import Data.Either (Either, either) -import Data.Json.JsonTuple (JsonTuple) +import Data.Either (Either) +import Data.Json.JsonUUID (JsonUUID(..)) import Data.Lens (Prism', preview) -import Data.Maybe (Maybe(..), maybe) +import Data.Maybe (Maybe, maybe) import Data.RawJson (RawJson(..)) -import Foreign.Generic (class Encode, decodeJSON) -import Plutus.Contracts.Core (Reserve, UserConfig) -import Plutus.Contracts.Endpoints (BorrowParams, DepositParams, RepayParams, UserContractState, WithdrawParams, _Borrowed, _Deposited, _FundsAt, _GetPubKey, _Pending, _PoolFunds, _Repaid, _Reserves, _Users, _Withdrawn) +import Foreign.Generic (class Decode, class Encode, decodeJSON) +import Plutus.Contracts.Endpoints (ContractResponse(..)) import Plutus.PAB.Events.ContractInstanceState (PartiallyDecodedResponse(..)) import Plutus.PAB.Simulation (AaveContracts) import Plutus.PAB.Webserver.Types (ContractInstanceClientState(..)) -import Plutus.V1.Ledger.Crypto (PubKeyHash) -import Plutus.V1.Ledger.Value (AssetClass, Value) -import PlutusTx.AssocMap (Map) +import Wallet.Types (ContractInstanceId(..)) +import Data.UUID (toString) as UUID getAaveContracts :: forall m. Contract m => m (Either APIError (Array (ContractInstanceClientState AaveContracts))) getAaveContracts = getContracts getAaveResponseWith :: - forall m a p. + forall m a p s. PollContract m => Encode p => + Decode s => + Show s => Endpoint -> - Prism' UserContractState a -> + Prism' s a -> ContractId -> p -> m (Either PollError a) @@ -37,39 +37,18 @@ getAaveResponseWith endpoint pick cid param = pollEndpoint getNext endpoint para getNext (ContractInstanceClientState { cicCurrentState: PartiallyDecodedResponse { observableState: RawJson s } }) = runExcept $ do - (response :: Either String UserContractState) <- withExcept (ResponseError <<< show) (decodeJSON s) - state <- either (throwError <<< ResponseError <<< show) pure response - case (preview _Pending state) of - Just _ -> throwError Continue - Nothing -> + (contractResponse :: ContractResponse String s) <- withExcept (ResponseError <<< show) (decodeJSON s) + case contractResponse of + ContractPending -> throwError Continue + ContractError e -> throwError <<< ResponseError $ e + ContractSuccess state -> maybe (throwError <<< ResponseError $ "Invalid state: " <> (show state)) pure (preview pick state) -deposit :: forall m. PollContract m => ContractId -> DepositParams -> m (Either PollError Unit) -deposit = getAaveResponseWith (Endpoint "deposit") _Deposited +getAaveContractId :: forall a. Prism' AaveContracts a -> ContractInstanceClientState AaveContracts -> Maybe ContractId +getAaveContractId pick (ContractInstanceClientState { cicContract, cicDefintion }) = (const $ toContractIdParam cicContract) <$> (preview pick cicDefintion) -withdraw :: forall m. PollContract m => ContractId -> WithdrawParams -> m (Either PollError Unit) -withdraw = getAaveResponseWith (Endpoint "withdraw") _Withdrawn - -borrow :: forall m. PollContract m => ContractId -> BorrowParams -> m (Either PollError Unit) -borrow = getAaveResponseWith (Endpoint "borrow") _Borrowed - -repay :: forall m. PollContract m => ContractId -> RepayParams -> m (Either PollError Unit) -repay = getAaveResponseWith (Endpoint "repay") _Repaid - -fundsAt :: forall m. PollContract m => ContractId -> PubKeyHash -> m (Either PollError Value) -fundsAt = getAaveResponseWith (Endpoint "fundsAt") _FundsAt - -poolFunds :: forall m. PollContract m => ContractId -> m (Either PollError Value) -poolFunds cid = getAaveResponseWith (Endpoint "poolFunds") _PoolFunds cid ContractUnit - -reserves :: forall m. PollContract m => ContractId -> m (Either PollError (Map AssetClass Reserve)) -reserves cid = getAaveResponseWith (Endpoint "reserves") _Reserves cid ContractUnit - -users :: forall m. PollContract m => ContractId -> m (Either PollError (Map (JsonTuple AssetClass PubKeyHash) UserConfig)) -users cid = getAaveResponseWith (Endpoint "users") _Users cid ContractUnit - -ownPubKey :: forall m. PollContract m => ContractId -> m (Either PollError PubKeyHash) -ownPubKey cid = getAaveResponseWith (Endpoint "ownPubKey") _GetPubKey cid ContractUnit +toContractIdParam :: ContractInstanceId -> ContractId +toContractIdParam (ContractInstanceId { unContractInstanceId: JsonUUID uuid }) = ContractId <<< UUID.toString $ uuid diff --git a/MetaLamp/lending-pool/client/src/Business/AaveInfo.purs b/MetaLamp/lending-pool/client/src/Business/AaveInfo.purs new file mode 100644 index 000000000..881cf3859 --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Business/AaveInfo.purs @@ -0,0 +1,37 @@ +module Business.AaveInfo where + +import Prelude +import Business.Aave (getAaveContractId, getAaveResponseWith) +import Capability.Contract (ContractId, ContractUnit(..), Endpoint(..)) +import Capability.PollContract (class PollContract, PollError) +import Data.Either (Either) +import Data.Json.JsonTuple (JsonTuple) +import Data.Maybe (Maybe) +import Data.Newtype (class Newtype, unwrap) +import Plutus.Contracts.Core (Reserve, UserConfig) +import Plutus.Contracts.Endpoints (_FundsAt, _PoolFunds, _Reserves, _Users) +import Plutus.PAB.Simulation (AaveContracts, _AaveInfo) +import Plutus.PAB.Webserver.Types (ContractInstanceClientState) +import Plutus.V1.Ledger.Crypto (PubKeyHash) +import Plutus.V1.Ledger.Value (AssetClass, Value) +import PlutusTx.AssocMap (Map) + +newtype InfoContractId + = InfoContractId ContractId + +derive instance newtypeInfoContractId :: Newtype InfoContractId _ + +getInfoContractId :: ContractInstanceClientState AaveContracts -> Maybe InfoContractId +getInfoContractId = map InfoContractId <<< getAaveContractId _AaveInfo + +fundsAt :: forall m. PollContract m => InfoContractId -> PubKeyHash -> m (Either PollError Value) +fundsAt = getAaveResponseWith (Endpoint "fundsAt") _FundsAt <<< unwrap + +poolFunds :: forall m. PollContract m => InfoContractId -> m (Either PollError Value) +poolFunds cid = getAaveResponseWith (Endpoint "poolFunds") _PoolFunds (unwrap cid) ContractUnit + +reserves :: forall m. PollContract m => InfoContractId -> m (Either PollError (Map AssetClass Reserve)) +reserves cid = getAaveResponseWith (Endpoint "reserves") _Reserves (unwrap cid) ContractUnit + +users :: forall m. PollContract m => InfoContractId -> m (Either PollError (Map (JsonTuple AssetClass PubKeyHash) UserConfig)) +users cid = getAaveResponseWith (Endpoint "users") _Users (unwrap cid) ContractUnit diff --git a/MetaLamp/lending-pool/client/src/Business/AaveUser.purs b/MetaLamp/lending-pool/client/src/Business/AaveUser.purs new file mode 100644 index 000000000..ec8cdb99f --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Business/AaveUser.purs @@ -0,0 +1,40 @@ +module Business.AaveUser where + +import Prelude +import Business.Aave (getAaveContractId, getAaveResponseWith) +import Capability.Contract (ContractId, ContractUnit(..), Endpoint(..)) +import Capability.PollContract (class PollContract, PollError) +import Data.Either (Either) +import Data.Maybe (Maybe) +import Data.Newtype (class Newtype, unwrap) +import Plutus.Contracts.Endpoints (BorrowParams, DepositParams, RepayParams, WithdrawParams, _Borrowed, _Deposited, _GetPubKey, _GetPubKeyBalance, _Repaid, _Withdrawn) +import Plutus.PAB.Simulation (AaveContracts, _AaveUser) +import Plutus.PAB.Webserver.Types (ContractInstanceClientState) +import Plutus.V1.Ledger.Crypto (PubKeyHash) +import Plutus.V1.Ledger.Value (Value) + +newtype UserContractId + = UserContractId ContractId + +derive instance newtypeUserContractId :: Newtype UserContractId _ + +getUserContractId :: ContractInstanceClientState AaveContracts -> Maybe UserContractId +getUserContractId = map UserContractId <<< getAaveContractId _AaveUser + +deposit :: forall m. PollContract m => UserContractId -> DepositParams -> m (Either PollError Unit) +deposit = getAaveResponseWith (Endpoint "deposit") _Deposited <<< unwrap + +withdraw :: forall m. PollContract m => UserContractId -> WithdrawParams -> m (Either PollError Unit) +withdraw = getAaveResponseWith (Endpoint "withdraw") _Withdrawn <<< unwrap + +borrow :: forall m. PollContract m => UserContractId -> BorrowParams -> m (Either PollError Unit) +borrow = getAaveResponseWith (Endpoint "borrow") _Borrowed <<< unwrap + +repay :: forall m. PollContract m => UserContractId -> RepayParams -> m (Either PollError Unit) +repay = getAaveResponseWith (Endpoint "repay") _Repaid <<< unwrap + +ownPubKey :: forall m. PollContract m => UserContractId -> m (Either PollError PubKeyHash) +ownPubKey cid = getAaveResponseWith (Endpoint "ownPubKey") _GetPubKey (unwrap cid) ContractUnit + +ownPubKeyBalance :: forall m. PollContract m => UserContractId -> m (Either PollError Value) +ownPubKeyBalance cid = getAaveResponseWith (Endpoint "ownPubKeyBalance") _GetPubKeyBalance (unwrap cid) ContractUnit diff --git a/MetaLamp/lending-pool/client/src/Component/Contract.purs b/MetaLamp/lending-pool/client/src/Component/Contract.purs index e8e84acfb..9857c31f1 100644 --- a/MetaLamp/lending-pool/client/src/Component/Contract.purs +++ b/MetaLamp/lending-pool/client/src/Component/Contract.purs @@ -1,8 +1,8 @@ module Component.Contract where import Prelude -import Business.Aave as Aave -import Capability.Contract (ContractId) +import Business.AaveUser (UserContractId) +import Business.AaveUser as AaveUser import Capability.LogMessages (class LogMessages) import Capability.PollContract (class PollContract) import Component.AmountForm as AmountForm @@ -28,13 +28,12 @@ import Plutus.Contracts.Endpoints (BorrowParams(..), DepositParams(..), RepayPar import Plutus.V1.Ledger.Crypto (PubKeyHash) import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..), Value) import View.FundsTable (fundsTable) -import View.RemoteDataState (remoteDataState) type State - = { contractId :: ContractId + = { userContractId :: UserContractId , walletPubKey :: PubKeyHash , reserves :: Array { amount :: BigInteger, asset :: AssetClass } - , userFunds :: RemoteData String Value + , userFunds :: Value , deposit :: RemoteData String Unit , withdraw :: RemoteData String Unit , borrow :: RemoteData String Unit @@ -42,9 +41,6 @@ type State , submit :: RemoteData String Unit } -_userFunds :: Lens' State (RemoteData String Value) -_userFunds = prop (SProxy :: SProxy "userFunds") - _deposit :: Lens' State (RemoteData String Unit) _deposit = prop (SProxy :: SProxy "deposit") @@ -61,20 +57,21 @@ _submit :: Lens' State (RemoteData String Unit) _submit = prop (SProxy :: SProxy "submit") type Input - = { contractId :: ContractId + = { userContractId :: UserContractId , walletPubKey :: PubKeyHash , reserves :: Array { amount :: BigInteger, asset :: AssetClass } + , userFunds :: Value } data Output = SubmitSuccess initialState :: Input -> State -initialState { contractId, walletPubKey, reserves } = - { contractId +initialState { userFunds, userContractId, walletPubKey, reserves } = + { userContractId , walletPubKey , reserves - , userFunds: NotAsked + , userFunds , withdraw: NotAsked , deposit: NotAsked , borrow: NotAsked @@ -83,10 +80,7 @@ initialState { contractId, walletPubKey, reserves } = } data Action - = Init - | GetUserFunds - | GetUpdates - | Deposit { amount :: BigInteger, asset :: AssetClass } + = Deposit { amount :: BigInteger, asset :: AssetClass } | Withdraw { amount :: BigInteger, asset :: AssetClass } | Borrow { amount :: BigInteger, asset :: AssetClass } | Repay { amount :: BigInteger, asset :: AssetClass } @@ -118,44 +112,35 @@ component = H.mkComponent { initialState , render - , eval: H.mkEval H.defaultEval { handleAction = handleAction, initialize = Just Init } + , eval: H.mkEval H.defaultEval { handleAction = handleAction } } where handleAction :: Action -> H.HalogenM State Action Slots Output m Unit handleAction = case _ of - Init -> handleAction GetUserFunds - GetUserFunds -> - runRD _userFunds <<< runExceptT - $ do - { contractId, walletPubKey } <- lift H.get - lift (Aave.fundsAt contractId walletPubKey) >>= either (throwError <<< show) pure - GetUpdates -> do - handleAction GetUserFunds - H.raise SubmitSuccess Deposit { amount, asset } -> runRD _deposit <<< runExceptT $ do - { contractId, walletPubKey } <- lift H.get - lift (Aave.deposit contractId $ DepositParams { dpAmount: amount, dpAsset: asset, dpOnBehalfOf: walletPubKey }) - >>= either (throwError <<< show) (const <<< lift <<< handleAction $ GetUpdates) + { userContractId, walletPubKey } <- lift H.get + lift (AaveUser.deposit userContractId $ DepositParams { dpAmount: amount, dpAsset: asset, dpOnBehalfOf: walletPubKey }) + >>= either (throwError <<< show) (const <<< lift <<< H.raise $ SubmitSuccess) Withdraw { amount, asset } -> runRD _withdraw <<< runExceptT $ do - { contractId, walletPubKey } <- lift H.get - lift (Aave.withdraw contractId $ WithdrawParams { wpAmount: amount, wpAsset: asset, wpUser: walletPubKey }) - >>= either (throwError <<< show) (const <<< lift <<< handleAction $ GetUpdates) + { userContractId, walletPubKey } <- lift H.get + lift (AaveUser.withdraw userContractId $ WithdrawParams { wpAmount: amount, wpAsset: asset, wpUser: walletPubKey }) + >>= either (throwError <<< show) (const <<< lift <<< H.raise $ SubmitSuccess) Borrow { amount, asset } -> runRD _borrow <<< runExceptT $ do - { contractId, walletPubKey } <- lift H.get - lift (Aave.borrow contractId $ BorrowParams { bpAmount: amount, bpAsset: asset, bpOnBehalfOf: walletPubKey }) - >>= either (throwError <<< show) (const <<< lift <<< handleAction $ GetUpdates) + { userContractId, walletPubKey } <- lift H.get + lift (AaveUser.borrow userContractId $ BorrowParams { bpAmount: amount, bpAsset: asset, bpOnBehalfOf: walletPubKey }) + >>= either (throwError <<< show) (const <<< lift <<< H.raise $ SubmitSuccess) Repay { amount, asset } -> runRD _repay <<< runExceptT $ do - { contractId, walletPubKey } <- lift H.get - lift (Aave.repay contractId $ RepayParams { rpAmount: amount, rpAsset: asset, rpOnBehalfOf: walletPubKey }) - >>= either (throwError <<< show) (const <<< lift <<< handleAction $ GetUpdates) + { userContractId, walletPubKey } <- lift H.get + lift (AaveUser.repay userContractId $ RepayParams { rpAmount: amount, rpAsset: asset, rpOnBehalfOf: walletPubKey }) + >>= either (throwError <<< show) (const <<< lift <<< H.raise $ SubmitSuccess) OnSubmitAmount operation (AmountForm.Submit { name, amount }) -> runRD _submit <<< runExceptT $ do @@ -195,13 +180,11 @@ component = render :: State -> H.ComponentHTML Action Slots m render state = HH.div_ - [ remoteDataState - (\userFunds -> HH.div_ [ HH.h2_ [ HH.text "User funds" ], fundsTable userFunds ]) - state.userFunds + [ HH.div_ [ HH.h2_ [ HH.text "User funds" ], fundsTable state.userFunds ] , case state.submit of NotAsked -> HH.div_ [] Loading -> HH.div_ [] - Failure e -> HH.h2_ [ HH.text $ "Error: " <> show e ] + Failure e -> HH.div_ [ HH.text $ "Error: " <> show e ] Success _ -> HH.div_ [] , HH.div_ $ mapWithIndex diff --git a/MetaLamp/lending-pool/client/src/Component/MainPage.purs b/MetaLamp/lending-pool/client/src/Component/MainPage.purs index 0fb07d50b..c1f505b9b 100644 --- a/MetaLamp/lending-pool/client/src/Component/MainPage.purs +++ b/MetaLamp/lending-pool/client/src/Component/MainPage.purs @@ -2,7 +2,9 @@ module Component.MainPage where import Prelude import Business.Aave as Aave -import Capability.Contract (ContractId(..)) +import Business.AaveInfo as AaveInfo +import Business.AaveUser (UserContractId) +import Business.AaveUser as AaveUser import Capability.LogMessages (class LogMessages) import Capability.PollContract (class PollContract) import Component.Contract as Contract @@ -10,57 +12,61 @@ import Component.Contract as ContractComponent import Component.Utils (runRD) import Control.Monad.Except (lift, runExceptT, throwError) import Control.Parallel (parTraverse) -import Data.Array (groupBy, head, mapWithIndex, zip) +import Data.Array (catMaybes, findMap, groupBy, mapWithIndex, take) import Data.Array.NonEmpty as NEA import Data.BigInteger (BigInteger) import Data.Either (either) import Data.Json.JsonTuple (JsonTuple(..)) -import Data.Json.JsonUUID (JsonUUID(..)) import Data.Lens (Lens') import Data.Lens.Record (prop) import Data.Maybe (Maybe(..)) import Data.Symbol (SProxy(..)) import Data.Tuple (Tuple(..)) -import Data.UUID (toString) as UUID import Halogen as H import Halogen.HTML as HH +import Halogen.HTML.Properties (classes) import Network.RemoteData (RemoteData(..)) import Network.RemoteData as RD import Network.RemoteData as RemoteData import Plutus.Contracts.Core (Reserve(..), UserConfig) import Plutus.PAB.Simulation (AaveContracts) -import Plutus.PAB.Webserver.Types (ContractInstanceClientState(..)) +import Plutus.PAB.Webserver.Types (ContractInstanceClientState) import Plutus.V1.Ledger.Crypto (PubKeyHash) -import Plutus.V1.Ledger.Value (AssetClass) +import Plutus.V1.Ledger.Value (AssetClass, Value) import PlutusTx.AssocMap as Map import View.RemoteDataState (remoteDataState) import View.ReserveInfo (reserveInfo) import View.UsersTable (poolUsers) -import Wallet.Types (ContractInstanceId(..)) +import Utils.BEM as BEM type State = { contracts :: RemoteData String (Array (ContractInstanceClientState AaveContracts)) - , pubKeys :: RemoteData String (Array PubKeyHash) + , userContracts :: RemoteData String (Array ({ pubKey :: PubKeyHash, contractId :: UserContractId })) , users :: RemoteData String (Map.Map (JsonTuple AssetClass PubKeyHash) UserConfig) + , userFunds :: RemoteData String (Array (Tuple PubKeyHash Value)) , reserves :: RemoteData String (Map.Map AssetClass Reserve) } _contracts :: Lens' State (RemoteData String (Array (ContractInstanceClientState AaveContracts))) _contracts = prop (SProxy :: SProxy "contracts") -_pubKeys :: Lens' State (RemoteData String (Array PubKeyHash)) -_pubKeys = prop (SProxy :: SProxy "pubKeys") +_userContracts :: Lens' State (RemoteData String (Array ({ pubKey :: PubKeyHash, contractId :: UserContractId }))) +_userContracts = prop (SProxy :: SProxy "userContracts") _users :: Lens' State (RemoteData String (Map.Map (JsonTuple AssetClass PubKeyHash) UserConfig)) _users = prop (SProxy :: SProxy "users") +_userFunds :: Lens' State (RemoteData String (Array (Tuple PubKeyHash Value))) +_userFunds = prop (SProxy :: SProxy "userFunds") + _reserves :: Lens' State (RemoteData String (Map.Map AssetClass Reserve)) _reserves = prop (SProxy :: SProxy "reserves") data Action = Init | GetContracts - | GetPubKeys + | GetUserContracts + | GetUserFunds | GetUserConfigs | GetReserves | OnSubmitSuccess ContractComponent.Output @@ -71,7 +77,7 @@ type Slots _contract = SProxy :: SProxy "contract" initialState :: forall input. input -> State -initialState _ = { contracts: NotAsked, pubKeys: NotAsked, users: NotAsked, reserves: NotAsked } +initialState _ = { contracts: NotAsked, userContracts: NotAsked, userFunds: NotAsked, users: NotAsked, reserves: NotAsked } component :: forall m query input output. @@ -89,26 +95,41 @@ component = handleAction = case _ of Init -> do handleAction GetContracts - handleAction GetPubKeys + handleAction GetUserContracts + handleAction GetUserFunds handleAction GetReserves handleAction GetUserConfigs OnSubmitSuccess _ -> do + handleAction GetUserFunds handleAction GetReserves handleAction GetUserConfigs GetContracts -> runRD _contracts <<< runExceptT $ lift Aave.getAaveContracts >>= either (throwError <<< show) pure - GetPubKeys -> - runRD _pubKeys <<< runExceptT + GetUserContracts -> + runRD _userContracts <<< runExceptT $ do state <- lift H.get contracts <- RemoteData.maybe (throwError "No contracts found") pure state.contracts parTraverse - ( \(ContractInstanceClientState { cicContract }) -> - lift (Aave.ownPubKey (toContractIdParam cicContract)) >>= either (throwError <<< show) pure + ( \contractId -> do + pubKey <- lift (AaveUser.ownPubKey contractId) >>= either (throwError <<< show) pure + pure $ { pubKey, contractId } + ) + (catMaybes <<< map AaveUser.getUserContractId $ contracts) + GetUserFunds -> + runRD _userFunds <<< runExceptT + $ do + state <- lift H.get + userContracts <- + RD.maybe (throwError "userContracts are missing") pure + $ state.userContracts + parTraverse + ( \{ pubKey, contractId } -> + lift (AaveUser.ownPubKeyBalance contractId) >>= either (throwError <<< show) (\balance -> pure $ Tuple pubKey balance) ) - contracts + userContracts GetUserConfigs -> runRD _users <<< runExceptT $ do @@ -116,9 +137,9 @@ component = contracts <- RD.maybe (throwError "contracts are missing") pure $ state.contracts - case head contracts of - Nothing -> throwError "No contract" - Just (ContractInstanceClientState { cicContract }) -> lift (Aave.users (toContractIdParam cicContract)) >>= either (throwError <<< show) pure + case catMaybes (AaveInfo.getInfoContractId <$> contracts) of + [ cid ] -> lift (AaveInfo.users cid) >>= either (throwError <<< show) pure + _ -> throwError "Info contract not found" GetReserves -> runRD _reserves <<< runExceptT $ do @@ -126,64 +147,74 @@ component = contracts <- RD.maybe (throwError "contracts are missing") pure $ state.contracts - case head contracts of - Nothing -> throwError "No contract" - Just (ContractInstanceClientState { cicContract }) -> lift (Aave.reserves (toContractIdParam cicContract)) >>= either (throwError <<< show) pure + case catMaybes (AaveInfo.getInfoContractId <$> contracts) of + [ cid ] -> lift (AaveInfo.reserves cid) >>= either (throwError <<< show) pure + _ -> throwError "Info contract not found" + + content = BEM.block "content" render :: State -> H.ComponentHTML Action Slots m render state = - HH.div_ - [ remoteDataState - ( \reserves -> - HH.div_ - $ [ HH.h2_ [ HH.text "Pool funds" ] ] - <> map (\(Tuple a r) -> reserveInfo a r) reserves - ) - (map Map.toTuples state.reserves) - , remoteDataState - ( \userMap -> - let - getAsset (Tuple (JsonTuple (Tuple asset _)) _) = asset - - getName (Tuple (JsonTuple (Tuple _ pkh)) _) = show pkh - - getUser (Tuple _ user) = user - - usersByAsset = groupBy (\a b -> getAsset a == getAsset b) <<< Map.toTuples $ userMap - - html = - map - ( \users -> - poolUsers - (getAsset <<< NEA.head $ users) - (map (\user -> Tuple (getName user) (getUser user)) $ users) - ) - usersByAsset - in - HH.div_ - $ [ HH.h2_ [ HH.text "Users:" ], HH.div_ html ] - ) - state.users - , remoteDataState - ( \{ contracts, pubKeys, reserves } -> - HH.div_ - $ mapWithIndex - ( \index (Tuple (ContractInstanceClientState { cicContract }) walletPubKey) -> - HH.slot - _contract - index - Contract.component - ({ contractId: toContractIdParam cicContract, walletPubKey, reserves: toReserveInfo reserves }) - (Just <<< OnSubmitSuccess) - ) - (zip contracts pubKeys) - ) - ({ contracts: _, pubKeys: _, reserves: _ } <$> state.contracts <*> state.pubKeys <*> state.reserves) + HH.div [ classes [ content "" ] ] + [ HH.div [ classes [ content "statistics" ] ] + [ remoteDataState + ( \reserves -> + HH.div_ + $ [ HH.h2_ [ HH.text "Pool funds" ] ] + <> map (\(Tuple a r) -> reserveInfo a r) reserves + ) + (map Map.toTuples state.reserves) + , remoteDataState + ( \userMap -> + let + getAsset (Tuple (JsonTuple (Tuple asset _)) _) = asset + + getName (Tuple (JsonTuple (Tuple _ pkh)) _) = show pkh + + getUser (Tuple _ user) = user + + usersByAsset = groupBy (\a b -> getAsset a == getAsset b) <<< Map.toTuples $ userMap + + html = + map + ( \users -> + poolUsers + (getAsset <<< NEA.head $ users) + (map (\user -> Tuple (getName user) (getUser user)) $ users) + ) + usersByAsset + in + HH.div_ + $ [ HH.h2_ [ HH.text "Users:" ], HH.div_ html ] + ) + state.users + ] + , HH.div [ classes [ content "contracts" ] ] + [ remoteDataState + ( \{ userContracts, reserves, userFunds } -> + HH.div [ classes [ content "contracts-list" ] ] + $ mapWithIndex + ( \index ({ pubKey: walletPubKey, contractId }) -> case findMap (\(Tuple k v) -> if k == walletPubKey then Just v else Nothing) $ userFunds of + Nothing -> HH.div_ [ HH.text "No funds found" ] + Just funds -> + HH.slot + _contract + index + Contract.component + ( { userContractId: contractId + , walletPubKey + , reserves: toReserveInfo reserves + , userFunds: funds + } + ) + (Just <<< OnSubmitSuccess) + ) + (take 2 userContracts) + ) + ({ userContracts: _, reserves: _, userFunds: _ } <$> state.userContracts <*> state.reserves <*> state.userFunds) + ] ] -toContractIdParam :: ContractInstanceId -> ContractId -toContractIdParam (ContractInstanceId { unContractInstanceId: JsonUUID uuid }) = ContractId <<< UUID.toString $ uuid - toReserveInfo :: Map.Map AssetClass Reserve -> Array { amount :: BigInteger, asset :: AssetClass } toReserveInfo = map toInfo <<< Map.toTuples where diff --git a/MetaLamp/lending-pool/client/src/Component/MainPage.scss b/MetaLamp/lending-pool/client/src/Component/MainPage.scss new file mode 100644 index 000000000..424097994 --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Component/MainPage.scss @@ -0,0 +1,17 @@ +.content { + display: flex; + max-width: 1300px; + + &__statistics { + width: 40%; + } + + &__contracts { + width: 60%; + } + + &__contracts-list { + display: flex; + justify-content: space-evenly; + } +} diff --git a/MetaLamp/lending-pool/client/src/Utils/BEM.purs b/MetaLamp/lending-pool/client/src/Utils/BEM.purs new file mode 100644 index 000000000..247286d76 --- /dev/null +++ b/MetaLamp/lending-pool/client/src/Utils/BEM.purs @@ -0,0 +1,9 @@ +module Utils.BEM where + +import Prelude +import Halogen (ClassName(..)) + +block :: String -> String -> ClassName +block base next = case next of + "" -> ClassName base + s -> ClassName $ base <> "__" <> s diff --git a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs index 6349f8414..ab70ff68a 100644 --- a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs +++ b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs @@ -19,7 +19,7 @@ import Data.Proxy (Proxy (Proxy)) import qualified Plutus.Contracts.Core as Aave import qualified Plutus.Contracts.Endpoints as Aave import Plutus.PAB.Simulation (AaveContracts(..)) -import Language.PureScript.Bridge.TypeParameters (A) +import Language.PureScript.Bridge.TypeParameters (A, E) import Control.Monad.Reader (MonadReader) import Language.PureScript.Bridge.Builder (BridgeData) import qualified PSGenerator.Common @@ -39,9 +39,11 @@ psRatio = expand <$> psTypeParameters aaveTypes :: [SumType 'Haskell] aaveTypes = [ (equal <*> (genericShow <*> mkSumType)) (Proxy @AaveContracts) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.Aave) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(Aave.ContractResponse E A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.CreateParams) , (order <*> (equal <*> (genericShow <*> mkSumType))) (Proxy @AssetClass) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.UserContractState) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.InfoContractState) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.Reserve) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.UserConfig) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.DepositParams) diff --git a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs index e823adb6a..fa6b57a2b 100644 --- a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs +++ b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs @@ -13,10 +13,9 @@ import Ledger (Address (Address), ValidatorHash, Value, findDatum) import Plutus.V1.Ledger.Credential (Credential (PubKeyCredential, ScriptCredential)) import qualified PlutusTx -import PlutusTx.Prelude (Eq ((==)), Maybe (..), - find, fst, (>>=), +import PlutusTx.Prelude (Eq ((==)), Maybe (..), find, fst, mapMaybe, mconcat, snd, ($), (.), - (<$>)) + (<$>), (>>=)) {-# INLINABLE findDatumHashByValue #-} -- | Find the hash of a datum, if it is part of the pending transaction's diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 28344ae1d..9bf311947 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -53,7 +53,8 @@ import qualified PlutusTx.AssocMap as AssocMap import PlutusTx.Prelude hiding (Monoid (..), Semigroup (..), mconcat, unless) -import Prelude (Monoid (..), Semigroup (..), show, subtract) +import Prelude (Monoid (..), Semigroup (..), + show, subtract) import qualified Prelude import Text.Printf (printf) @@ -133,6 +134,9 @@ balanceAt pkh asset = flip assetClassValueOf asset <$> fundsAt pkh poolFunds :: HasBlockchainActions s => Aave -> Contract w s Text Value poolFunds aave = valueAt (Core.aaveAddress aave) +ownPubKeyBalance :: HasBlockchainActions s => Contract w s Text Value +ownPubKeyBalance = getOwnPubKey >>= fundsAt + data DepositParams = DepositParams { dpAsset :: AssetClass, @@ -279,60 +283,73 @@ repay aave RepayParams {..} = do _ <- awaitTxConfirmed $ txId ledgerTx pure () +data ContractResponse e a = ContractSuccess a | ContractError e | ContractPending + deriving stock (Prelude.Eq, Show, Generic) + deriving anyclass (ToJSON, FromJSON) + +handleContract :: forall l a p r s. + HasEndpoint l p s + => Proxy l + -> (a -> r) + -> (p -> Contract (Last (ContractResponse Text r)) s Text a) + -> Contract (Last (ContractResponse Text r)) s Void () +handleContract _ g c = do + e <- runError $ do + p <- endpoint @l + _ <- tell $ Last $ Just ContractPending + errorHandler `handleError` c p + tell $ Last $ Just $ case e of + Left err -> ContractError err + Right a -> ContractSuccess $ g a + where + errorHandler e = do + logInfo @Text ("Error submiting the transaction: " <> e) + throwError e + type AaveUserSchema = BlockchainActions .\/ Endpoint "deposit" DepositParams .\/ Endpoint "withdraw" WithdrawParams .\/ Endpoint "borrow" BorrowParams .\/ Endpoint "repay" RepayParams - .\/ Endpoint "fundsAt" PubKeyHash - .\/ Endpoint "poolFunds" () - .\/ Endpoint "reserves" () - .\/ Endpoint "users" () .\/ Endpoint "ownPubKey" () + .\/ Endpoint "ownPubKeyBalance" () data UserContractState = - Pending - | Created - | Closed - | Stopped - | Deposited + Deposited | Withdrawn | Borrowed | Repaid - | FundsAt Value + | GetPubKey PubKeyHash + | GetPubKeyBalance Value + deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) + +userEndpoints :: Aave -> Contract (Last (ContractResponse Text UserContractState)) AaveUserSchema Void () +userEndpoints aave = forever $ + handleContract (Proxy @"deposit") (const Deposited) (deposit aave) + `select` handleContract (Proxy @"withdraw") (const Withdrawn) (withdraw aave) + `select` handleContract (Proxy @"borrow") (const Borrowed) (borrow aave) + `select` handleContract (Proxy @"repay") (const Repaid) (repay aave) + `select` handleContract (Proxy @"ownPubKey") GetPubKey (const getOwnPubKey) + `select` handleContract (Proxy @"ownPubKeyBalance") GetPubKeyBalance (const ownPubKeyBalance) + +type AaveInfoSchema = + BlockchainActions + .\/ Endpoint "fundsAt" PubKeyHash + .\/ Endpoint "poolFunds" () + .\/ Endpoint "reserves" () + .\/ Endpoint "users" () + +data InfoContractState = + FundsAt Value | PoolFunds Value | Reserves (AssocMap.Map AssetClass Reserve) | Users (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) - | GetPubKey PubKeyHash deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) -userEndpoints :: Aave -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () -userEndpoints aa = forever $ - f (Proxy @"deposit") (const Deposited) deposit - `select` f (Proxy @"withdraw") (const Withdrawn) withdraw - `select` f (Proxy @"borrow") (const Borrowed) borrow - `select` f (Proxy @"repay") (const Repaid) repay - `select` f (Proxy @"fundsAt") FundsAt (\_ pkh -> fundsAt pkh) - `select` f (Proxy @"poolFunds") PoolFunds (\aave () -> poolFunds aave) - `select` f (Proxy @"reserves") Reserves (\aave () -> reserves aave) - `select` f (Proxy @"users") Users (\aave () -> users aave) - `select` f (Proxy @"ownPubKey") GetPubKey (\_ () -> getOwnPubKey) - where - f :: forall l a p. - HasEndpoint l p AaveUserSchema - => Proxy l - -> (a -> UserContractState) - -> (Aave -> p -> Contract (Last (Either Text UserContractState)) AaveUserSchema Text a) - -> Contract (Last (Either Text UserContractState)) AaveUserSchema Void () - f _ g c = do - e <- runError $ do - p <- endpoint @l - _ <- tell $ Last $ Just $ Right $ Pending - errorHandler `handleError` c aa p - tell $ Last $ Just $ case e of - Left err -> Left err - Right a -> Right $ g a - errorHandler e = do - logInfo @Text ("Error submiting the transaction: " <> e) - throwError e +infoEndpoints :: Aave -> Contract (Last (ContractResponse Text InfoContractState)) AaveInfoSchema Void () +infoEndpoints aave = forever $ + handleContract (Proxy @"fundsAt") FundsAt fundsAt + `select` handleContract (Proxy @"poolFunds") PoolFunds (const $ poolFunds aave) + `select` handleContract (Proxy @"reserves") Reserves (const $ reserves aave) + `select` handleContract (Proxy @"users") Users (const $ users aave) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs index a0a380b5a..8438dc0fe 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs @@ -18,8 +18,8 @@ import Ledger hiding (singleton) import qualified Ledger.Constraints as Constraints import qualified Ledger.Constraints.OnChain as Constraints import qualified Ledger.Constraints.TxConstraints as Constraints -import Ledger.Typed.Scripts (MonetaryPolicy, - TypedValidator, RedeemerType, DatumType) +import Ledger.Typed.Scripts (DatumType, MonetaryPolicy, + RedeemerType, TypedValidator) import qualified Ledger.Typed.Scripts as Scripts import Plutus.Contract import Plutus.Contracts.Core (Aave, Reserve (..)) diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index f0ade67a6..13ee39966 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -6,6 +6,7 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} @@ -85,7 +86,9 @@ initContract = do where amount = 1000000 -activateContracts :: Simulation (Builtin AaveContracts) (Map.Map Wallet ContractInstanceId) +data ContractIDs = ContractIDs { cidUser :: Map.Map Wallet ContractInstanceId, cidInfo :: ContractInstanceId } + +activateContracts :: Simulation (Builtin AaveContracts) ContractIDs activateContracts = do cidInit <- Simulator.activateContract (Wallet 1) Init _ <- Simulator.waitUntilFinished cidInit @@ -98,11 +101,15 @@ activateContracts = do _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Aave instance created: " ++ show aa - fmap Map.fromList $ forM wallets $ \w -> do + cidInfo <- Simulator.activateContract (Wallet 1) $ AaveInfo aa + + cidUser <- fmap Map.fromList $ forM (tail wallets) $ \w -> do cid <- Simulator.activateContract w $ AaveUser aa Simulator.logString @(Builtin AaveContracts) $ "Aave user contract started for " ++ show w return (w, cid) + pure $ ContractIDs cidUser cidInfo + runLendingPool :: IO () runLendingPool = void $ Simulator.runSimulationWith handlers $ do Simulator.logString @(Builtin AaveContracts) "Starting Aave PAB webserver on port 8080. Press enter to exit." @@ -115,8 +122,8 @@ runLendingPoolSimulation :: IO () runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do Simulator.logString @(Builtin AaveContracts) "Starting Aave PAB webserver on port 8080. Press enter to exit." shutdown <- PAB.Server.startServerDebug - cids <- activateContracts - let userCid = cids Map.! Wallet 2 + ContractIDs {..} <- activateContracts + let userCid = cidUser Map.! Wallet 2 sender = pubKeyHash . walletPubKey $ Wallet 2 _ <- @@ -135,7 +142,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful withdraw" - let lenderCid = cids Map.! Wallet 3 + let lenderCid = cidUser Map.! Wallet 3 let lender = pubKeyHash . walletPubKey $ Wallet 3 _ <- Simulator.callEndpointOnInstance lenderCid "deposit" $ @@ -161,32 +168,32 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful repay" - _ <- Simulator.callEndpointOnInstance userCid "fundsAt" sender - v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + _ <- Simulator.callEndpointOnInstance cidInfo "fundsAt" sender + v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.InfoContractState))) of Success (Monoid.Last (Just (Right (Aave.FundsAt v)))) -> Just v _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final user funds: " <> show v - _ <- Simulator.callEndpointOnInstance lenderCid "fundsAt" lender - v <- flip Simulator.waitForState lenderCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + _ <- Simulator.callEndpointOnInstance cidInfo"fundsAt" lender + v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.InfoContractState))) of Success (Monoid.Last (Just (Right (Aave.FundsAt v)))) -> Just v _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final lender funds: " <> show v - _ <- Simulator.callEndpointOnInstance userCid "reserves" () - reserves <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + _ <- Simulator.callEndpointOnInstance cidInfo "reserves" () + reserves <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.InfoContractState))) of Success (Monoid.Last (Just (Right (Aave.Reserves reserves)))) -> Just reserves _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final reserves: " <> show reserves - _ <- Simulator.callEndpointOnInstance userCid "poolFunds" () - v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + _ <- Simulator.callEndpointOnInstance cidInfo "poolFunds" () + v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.InfoContractState))) of Success (Monoid.Last (Just (Right (Aave.PoolFunds v)))) -> Just v _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final pool funds: " <> show v - _ <- Simulator.callEndpointOnInstance userCid "users" () - v <- flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of + _ <- Simulator.callEndpointOnInstance cidInfo "users" () + v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.InfoContractState))) of Success (Monoid.Last (Just (Right (Aave.Users v)))) -> Just v _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final users: " <> show v @@ -196,6 +203,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do data AaveContracts = Init | AaveStart [Aave.CreateParams] + | AaveInfo Aave.Aave | AaveUser Aave.Aave deriving (Eq, Show, Generic) deriving anyclass (FromJSON, ToJSON) @@ -212,10 +220,12 @@ handleAaveContract :: handleAaveContract = Builtin.handleBuiltin getSchema getContract where getSchema = \case AaveUser _ -> Builtin.endpointsToSchemas @(Aave.AaveUserSchema .\\ BlockchainActions) + AaveInfo _ -> Builtin.endpointsToSchemas @(Aave.AaveInfoSchema .\\ BlockchainActions) AaveStart _ -> Builtin.endpointsToSchemas @(Aave.AaveOwnerSchema .\\ BlockchainActions) Init -> Builtin.endpointsToSchemas @Empty getContract = \case - AaveUser us -> SomeBuiltin $ Aave.userEndpoints us + AaveInfo aave -> SomeBuiltin $ Aave.infoEndpoints aave + AaveUser aave -> SomeBuiltin $ Aave.userEndpoints aave AaveStart params -> SomeBuiltin $ Aave.ownerEndpoint params Init -> SomeBuiltin initContract diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index 007d7413a..aba847325 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -22,14 +22,14 @@ import qualified Data.Map as Map import Data.Text (Text, pack) import qualified Data.Text as Text import Data.Void (Void) +import Ext.Plutus.Ledger.Contexts (scriptInputsAt) import Ledger hiding (getDatum, singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints import Ledger.Constraints.TxConstraints as Constraints import qualified Ledger.Scripts as UntypedScripts +import Ledger.Typed.Scripts (DatumType, RedeemerType) import qualified Ledger.Typed.Scripts as Scripts -import Ledger.Typed.Scripts (RedeemerType, DatumType) -import Ext.Plutus.Ledger.Contexts (scriptInputsAt) import Playground.Contract import Plutus.Contract hiding (when) import qualified Plutus.Contracts.TxUtils as TxUtils From d0966a7ab194e4513140dcee157a1f4a9d1534de Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 16 Jun 2021 13:42:31 +0700 Subject: [PATCH 098/169] fix user config updates --- .../lending-pool/src/Plutus/Contracts/Core.hs | 11 +++++------ .../src/Plutus/Contracts/Endpoints.hs | 15 +++++---------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index fb7bed15e..56b2e9ba3 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -241,10 +241,9 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( maybe False (checkRedeemerConfig $ AssocMap.lookup userConfigId userConfigs) (AssocMap.lookup userConfigId newUserConfigs) checkRedeemerConfig :: Maybe UserConfig -> UserConfig -> Bool checkRedeemerConfig oldState newState = - let oldDebt = fromMaybe 0 $ oldState >>= ucDebt - debtAmount = maybe 0 (flip (-) oldDebt) (ucDebt newState) + let debtAmount = (ucDebt newState -) $ maybe 0 ucDebt oldState disbursementAmount = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId - in debtAmount == disbursementAmount && debtAmount > 0 && disbursementAmount > 0 && + in debtAmount == disbursementAmount && debtAmount > 0 && disbursementAmount > 0 validateBorrow aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateBorrow: Reserves Datum change is not valid" $ checkNegativeReservesTransformation stateToken reserves ctx userConfigId @@ -281,10 +280,10 @@ validateRepay aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(r (checkRedeemerConfig <$> AssocMap.lookup userConfigId userConfigs <*> AssocMap.lookup userConfigId newUserConfigs)) checkRedeemerConfig :: UserConfig -> UserConfig -> Bool checkRedeemerConfig oldState newState = - let debtChange = fromMaybe 0 $ (-) <$> ucDebt oldState <*> ucDebt newState - newDebt = fromMaybe 0 $ ucDebt newState + let newDebt = ucDebt newState + debtChange = ucDebt oldState - newDebt reimbursementAmount = assetClassValueOf actorSpentValue reserveId - assetClassValueOf actorRemainderValue reserveId - in debtChange == reimbursementAmount && debtChange > 0 && reimbursementAmount > 0 && newDebt >= 0 && + in debtChange == reimbursementAmount && debtChange > 0 && reimbursementAmount > 0 && newDebt >= 0 validateRepay aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateRepay: Reserves Datum change is not valid" $ checkPositiveReservesTransformation stateToken reserves ctx userConfigId diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 8048d9572..fb8d49c24 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -185,19 +185,13 @@ PlutusTx.makeLift ''WithdrawParams withdraw :: (HasBlockchainActions s) => Aave -> WithdrawParams -> Contract w s Text () withdraw aave WithdrawParams {..} = do reserve <- State.findAaveReserve aave wpAsset - let userConfigId = (wpAsset, wpUser) - balance <- balanceAt wpUser (rAToken reserve) - userConfigsTx <- if wpAmount == balance then do - userConfig <- State.findAaveUserConfig aave userConfigId - State.updateUserConfig aave (Core.WithdrawRedeemer userConfigId) userConfigId $ userConfig { ucUsingAsCollateral = False } - else pure mempty burnTx <- AToken.burnATokensFrom aave reserve wpUser wpAmount reservesTx <- State.updateReserve aave (Core.WithdrawRedeemer userConfigId) wpAsset (reserve { rAmount = rAmount reserve - wpAmount }) - ledgerTx <- TxUtils.submitTxPair $ burnTx <> reservesTx <> userConfigsTx + ledgerTx <- TxUtils.submitTxPair $ burnTx <> reservesTx _ <- awaitTxConfirmed $ txId ledgerTx pure () @@ -234,10 +228,10 @@ borrow aave BorrowParams {..} = do aave (Core.BorrowRedeemer userConfigId) userConfigId - UserConfig {ucUsingAsCollateral = False, ucDebt = Just bpAmount} + UserConfig { ucDebt = bpAmount } Just userConfig -> State.updateUserConfig aave (Core.BorrowRedeemer userConfigId) userConfigId $ - userConfig {ucDebt = Just $ maybe bpAmount (+ bpAmount) $ ucDebt userConfig} + userConfig { ucDebt = ucDebt userConfig + bpAmount} reservesTx <- State.updateReserve aave (Core.BorrowRedeemer userConfigId) bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) @@ -271,7 +265,7 @@ repay aave RepayParams {..} = do Nothing -> throwError "User does not have any debt." Just userConfig -> - State.updateUserConfig aave (Core.RepayRedeemer userConfigId) userConfigId $ userConfig { ucDebt = subtract rpAmount <$> ucDebt userConfig } + State.updateUserConfig aave (Core.RepayRedeemer userConfigId) userConfigId $ userConfig { ucDebt = ucDebt userConfig - rpAmount } reservesTx <- State.updateReserve aave (Core.RepayRedeemer userConfigId) rpAsset (reserve { rAmount = rAmount reserve + rpAmount }) @@ -281,6 +275,7 @@ repay aave RepayParams {..} = do -- TODO add provideCollateral -- TODO add revokeCollateral +-- TODO ? add repayWithCollateral type AaveUserSchema = BlockchainActions .\/ Endpoint "deposit" DepositParams From 2100415a22fa2bd32359cac9206b22af4b7c5ff2 Mon Sep 17 00:00:00 2001 From: megakaban Date: Wed, 16 Jun 2021 15:21:52 +0700 Subject: [PATCH 099/169] Fix simulation, add mock error for ui --- .../client/src/View/RemoteDataState.purs | 2 +- .../lending-pool/src/Plutus/PAB/Simulation.hs | 43 ++++++++++--------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs b/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs index a59444fee..9b35ee0fc 100644 --- a/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs +++ b/MetaLamp/lending-pool/client/src/View/RemoteDataState.purs @@ -8,5 +8,5 @@ remoteDataState :: forall props act e a. Show e => (a -> HH.HTML props act) -> R remoteDataState onSuccess = case _ of NotAsked -> HH.div_ [ HH.text "" ] Loading -> HH.div_ [ HH.text "Loading..." ] - Failure e -> HH.div_ [ HH.text $ "Error: " <> show e ] + Failure e -> HH.div_ [ HH.text "Something went wrong" ] Success a -> onSuccess a diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 13ee39966..59257821c 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -40,6 +40,7 @@ import Plutus.Contract hiding (when) import qualified Plutus.Contracts.Core as Aave import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.Endpoints as Aave +import Plutus.Contracts.Endpoints (ContractResponse(..)) import qualified Plutus.Contracts.FungibleToken as FungibleToken import Plutus.PAB.Effects.Contract (ContractEffect (..)) import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), @@ -129,16 +130,16 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do _ <- Simulator.callEndpointOnInstance userCid "deposit" $ Aave.DepositParams { Aave.dpAsset = head testAssets, Aave.dpOnBehalfOf = sender, Aave.dpAmount = 100 } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right Aave.Deposited))) -> Just () + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of + Success (Monoid.Last (Just (ContractSuccess Aave.Deposited))) -> Just () _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful deposit" _ <- Simulator.callEndpointOnInstance userCid "withdraw" $ Aave.WithdrawParams { Aave.wpAsset = head testAssets, Aave.wpUser = sender, Aave.wpAmount = 30 } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right Aave.Withdrawn))) -> Just () + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of + Success (Monoid.Last (Just (ContractSuccess Aave.Withdrawn))) -> Just () _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful withdraw" @@ -147,54 +148,54 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do _ <- Simulator.callEndpointOnInstance lenderCid "deposit" $ Aave.DepositParams { Aave.dpAsset = testAssets !! 1, Aave.dpOnBehalfOf = lender, Aave.dpAmount = 200 } - flip Simulator.waitForState lenderCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right Aave.Deposited))) -> Just () + flip Simulator.waitForState lenderCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of + Success (Monoid.Last (Just (ContractSuccess Aave.Deposited))) -> Just () _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful deposit from lender" _ <- Simulator.callEndpointOnInstance userCid "borrow" $ Aave.BorrowParams { Aave.bpAsset = testAssets !! 1, Aave.bpAmount = 35, Aave.bpOnBehalfOf = sender } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right Aave.Borrowed))) -> Just () + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of + Success (Monoid.Last (Just (ContractSuccess Aave.Borrowed))) -> Just () _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful borrow" _ <- Simulator.callEndpointOnInstance userCid "repay" $ Aave.RepayParams { Aave.rpAsset = testAssets !! 1, Aave.rpAmount = 25, Aave.rpOnBehalfOf = sender } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.UserContractState))) of - Success (Monoid.Last (Just (Right Aave.Repaid))) -> Just () + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of + Success (Monoid.Last (Just (ContractSuccess Aave.Repaid))) -> Just () _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful repay" _ <- Simulator.callEndpointOnInstance cidInfo "fundsAt" sender - v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.InfoContractState))) of - Success (Monoid.Last (Just (Right (Aave.FundsAt v)))) -> Just v + v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.InfoContractState))) of + Success (Monoid.Last (Just (ContractSuccess (Aave.FundsAt v)))) -> Just v _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final user funds: " <> show v - _ <- Simulator.callEndpointOnInstance cidInfo"fundsAt" lender - v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.InfoContractState))) of - Success (Monoid.Last (Just (Right (Aave.FundsAt v)))) -> Just v + _ <- Simulator.callEndpointOnInstance cidInfo "fundsAt" lender + v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.InfoContractState))) of + Success (Monoid.Last (Just (ContractSuccess (Aave.FundsAt v)))) -> Just v _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final lender funds: " <> show v _ <- Simulator.callEndpointOnInstance cidInfo "reserves" () - reserves <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.InfoContractState))) of - Success (Monoid.Last (Just (Right (Aave.Reserves reserves)))) -> Just reserves + reserves <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.InfoContractState))) of + Success (Monoid.Last (Just (ContractSuccess (Aave.Reserves reserves)))) -> Just reserves _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final reserves: " <> show reserves _ <- Simulator.callEndpointOnInstance cidInfo "poolFunds" () - v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.InfoContractState))) of - Success (Monoid.Last (Just (Right (Aave.PoolFunds v)))) -> Just v + v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.InfoContractState))) of + Success (Monoid.Last (Just (ContractSuccess (Aave.PoolFunds v)))) -> Just v _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final pool funds: " <> show v _ <- Simulator.callEndpointOnInstance cidInfo "users" () - v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.InfoContractState))) of - Success (Monoid.Last (Just (Right (Aave.Users v)))) -> Just v + v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.InfoContractState))) of + Success (Monoid.Last (Just (ContractSuccess (Aave.Users v)))) -> Just v _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final users: " <> show v _ <- liftIO getLine From 2e595319f7103e923c19dca2a68a8e88a8089202 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 16 Jun 2021 15:25:13 +0700 Subject: [PATCH 100/169] add provideCollateral endpoint --- .../lending-pool/src/Plutus/Contracts/Core.hs | 1 + .../src/Plutus/Contracts/Endpoints.hs | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 56b2e9ba3..a946ddbf2 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -214,6 +214,7 @@ validateWithdraw aave ReserveFundsDatum ctx userConfigId = validateWithdraw _ _ _ _ = trace "validateWithdraw: Lending Pool Datum management is not allowed" False +-- TODO prohibit borrowing asset which is deposited validateBorrow :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) = traceIfFalse "validateBorrow: User Configs Datum change is not valid" isValidUserConfigsTransformation diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index fb8d49c24..8ed7559a2 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -273,6 +273,29 @@ repay aave RepayParams {..} = do _ <- awaitTxConfirmed $ txId ledgerTx pure () +data ProvideCollateralParams = + ProvideCollateralParams { + pcpUnderlyingAsset :: AssetClass, + pcpAmount :: Integer, + pcpOnBehalfOf :: PubKeyHash + } + deriving stock (Prelude.Eq, Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''ProvideCollateralParams +PlutusTx.makeLift ''ProvideCollateralParams + +provideCollateral :: (HasBlockchainActions s) => Aave -> ProvideCollateralParams -> Contract w s Text () +provideCollateral aave ProvideCollateralParams {..} = do + reserve <- State.findAaveReserve aave pcpUnderlyingAsset + + let payment = assetClassValue (rAToken reserve) pcpAmount + let fundsLockingTx = TxUtils.mustPayToScript (Core.aaveInstance aave) pcpOnBehalfOf (Core.UserCollateralFundsDatum pcpOnBehalfOf) payment + + ledgerTx <- TxUtils.submitTxPair fundsLockingTx + _ <- awaitTxConfirmed $ txId ledgerTx + pure () + -- TODO add provideCollateral -- TODO add revokeCollateral -- TODO ? add repayWithCollateral From e7caf001863feb21ee93bacd8b6392a762c04ca4 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 16 Jun 2021 17:31:49 +0700 Subject: [PATCH 101/169] add revokeCollateral endpoint --- .../lending-pool/src/Plutus/Contracts/Core.hs | 1 + .../src/Plutus/Contracts/Endpoints.hs | 33 +++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index a946ddbf2..c095f9947 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -92,6 +92,7 @@ data AaveRedeemer = | WithdrawRedeemer (AssetClass, PubKeyHash) | BorrowRedeemer (AssetClass, PubKeyHash) | RepayRedeemer (AssetClass, PubKeyHash) + | RevokeCollateralRedeemer (AssetClass, PubKeyHash) deriving Show PlutusTx.unstableMakeIsData ''AaveRedeemer diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 5ca9d551d..a1e9fb5c1 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -299,8 +299,37 @@ provideCollateral aave ProvideCollateralParams {..} = do _ <- awaitTxConfirmed $ txId ledgerTx pure () --- TODO add provideCollateral --- TODO add revokeCollateral +data RevokeCollateralParams = + RevokeCollateralParams { + rcpUnderlyingAsset :: AssetClass, + rcpAmount :: Integer, + rcpOnBehalfOf :: PubKeyHash + } + deriving stock (Prelude.Eq, Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''RevokeCollateralParams +PlutusTx.makeLift ''RevokeCollateralParams + +revokeCollateral :: (HasBlockchainActions s) => Aave -> RevokeCollateralParams -> Contract w s Text () +revokeCollateral aave RevokeCollateralParams {..} = do + reserve <- State.findAaveReserve aave rcpUnderlyingAsset + + let aTokenAsset = rAToken reserve + utxos <- + Map.filter ((> 0) . flip assetClassValueOf aTokenAsset . txOutValue . txOutTxOut) + <$> utxoAt (Core.aaveAddress aave) + let userConfigId = (rCurrency reserve, rcpOnBehalfOf) + let inputs = (\(ref, tx) -> OutputValue ref tx (Core.RevokeCollateralRedeemer userConfigId)) <$> Map.toList utxos + let payment = assetClassValue aTokenAsset rcpAmount + let remainder = assetClassValue aTokenAsset (rAmount reserve - rcpAmount) + let fundsUnlockingTx = TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs rcpOnBehalfOf payment <> + TxUtils.mustPayToScript (Core.aaveInstance aave) rcpOnBehalfOf (Core.UserCollateralFundsDatum rcpOnBehalfOf) remainder + + ledgerTx <- TxUtils.submitTxPair fundsUnlockingTx + _ <- awaitTxConfirmed $ txId ledgerTx + pure () + -- TODO ? add repayWithCollateral data ContractResponse e a = ContractSuccess a | ContractError e | ContractPending From 7df188a75d8c57669be2b73555ded32744b7b545 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 16 Jun 2021 17:46:50 +0700 Subject: [PATCH 102/169] add collateral filter --- MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index a1e9fb5c1..a10fcffd4 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -317,18 +317,23 @@ revokeCollateral aave RevokeCollateralParams {..} = do let aTokenAsset = rAToken reserve utxos <- - Map.filter ((> 0) . flip assetClassValueOf aTokenAsset . txOutValue . txOutTxOut) + Map.filter (getUsersCollateral aTokenAsset) <$> utxoAt (Core.aaveAddress aave) let userConfigId = (rCurrency reserve, rcpOnBehalfOf) let inputs = (\(ref, tx) -> OutputValue ref tx (Core.RevokeCollateralRedeemer userConfigId)) <$> Map.toList utxos let payment = assetClassValue aTokenAsset rcpAmount let remainder = assetClassValue aTokenAsset (rAmount reserve - rcpAmount) let fundsUnlockingTx = TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs rcpOnBehalfOf payment <> - TxUtils.mustPayToScript (Core.aaveInstance aave) rcpOnBehalfOf (Core.UserCollateralFundsDatum rcpOnBehalfOf) remainder + TxUtils.mustPayToScript (Core.aaveInstance aave) rcpOnBehalfOf userDatum remainder ledgerTx <- TxUtils.submitTxPair fundsUnlockingTx _ <- awaitTxConfirmed $ txId ledgerTx pure () + where + userDatum = Core.UserCollateralFundsDatum rcpOnBehalfOf + getUsersCollateral :: AssetClass -> TxOutTx -> Bool + getUsersCollateral asset tx = ((> 0) . flip assetClassValueOf asset . txOutValue . txOutTxOut $ tx) && + (txOutDatumHash . txOutTxOut $ tx) == Just (datumHash . Datum . PlutusTx.toData $ userDatum) -- TODO ? add repayWithCollateral From 6352145f8fd1f4c03b20aca9fbcae21834c4b575 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 17 Jun 2021 12:41:40 +0700 Subject: [PATCH 103/169] fix lending pool readme --- MetaLamp/lending-pool/README.md | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/MetaLamp/lending-pool/README.md b/MetaLamp/lending-pool/README.md index 90b1b830c..1d05910e8 100644 --- a/MetaLamp/lending-pool/README.md +++ b/MetaLamp/lending-pool/README.md @@ -1,6 +1,7 @@ -# Plutus Platform starter project +# Lending Pool -This project gives a simple starter project for using the Plutus Platform. +Lending Pool is a smart contract application on Plutus Platform. +The smart contract protocol is based on [Aave](https://aave.com/), but does not follow it literally. ## Setting up @@ -8,28 +9,38 @@ This project gives a simple starter project for using the Plutus Platform. - Clone https://github.com/input-output-hk/plutus - Set up your machine to build things with Nix, following the Plutus README (make sure to set up the binary cache!) -## The Plutus Application Backend (PAB) example +## The Plutus Application Backend (PAB) usage -We have provided an example PAB application in `./pab`. With the PAB we can serve and interact -with contracts over a web API. You can read more about the PAB here: [PAB Architecture](https://github.com/input-output-hk/plutus/blob/master/plutus-pab/ARCHITECTURE.adoc). +We have provided two PAB applications in `./pab` and `./pab-simulation`. First one is made for real world usage and interaction throw frontend [client](client/README.md), second one is a big test scenario. +With the PAB we can serve and interact with contracts over a web API. You can read more about the PAB here: [PAB Architecture](https://github.com/input-output-hk/plutus/blob/master/plutus-pab/ARCHITECTURE.adoc). 1. Enter the nix shell (cd to the cloned Plutus repo): ``` -git checkout 58bf9ed626d498c140c69a859a508da03843d097 +git checkout 5cdd2c3d708bf4c33514681dee096da6463273b7 nix-shell ``` -2. Build the PAB executable (cd to plutus-use-cases/MetaLamp/lending-pool): +2. Build the PAB executables (cd to plutus-use-cases/MetaLamp/lending-pool): ``` -cabal build +cabal build all ``` 3. Run the PAB binary: ``` -cabal run plutus-starter-pab -```` +cabal run pab +``` This will then start up the server on port 8080. + +4. To Run test simulation do: + +``` +cabal run pab-simulation +``` + +## Client + +See the client [readme](client/README.md). From 198fef4a6431e788f9aac0c39fa59d4de7012c5d Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 17 Jun 2021 12:54:53 +0700 Subject: [PATCH 104/169] fix client readme --- MetaLamp/lending-pool/client/README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/MetaLamp/lending-pool/client/README.md b/MetaLamp/lending-pool/client/README.md index fa54d2c5e..a3431ba89 100644 --- a/MetaLamp/lending-pool/client/README.md +++ b/MetaLamp/lending-pool/client/README.md @@ -1,16 +1,23 @@ -# lending pool client +# Lending pool client + +The client application has minimalistic interface to the PAB [server](/MetaLamp/lending-pool/README.md). ## Running the project +1. Generate necessary PureScript code from Haskell source (cd to /MetaLamp/lending-pool/client/): + ``` npm install ``` +2. Start the client: + ``` npm start ``` -CORS protection needs to be disabled. You can use this script to launch chrome: +3. Open browser to interact with the app at https://localhost:8009/. +CORS protection needs to be disabled. You can use this script to launch chromium (note that first you need to close chromium completely, otherwise security won't be disabled): ``` npm run start-chrome From 1c1c101b120f86c5ce3d028ae6464e5380514695 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 17 Jun 2021 13:10:38 +0700 Subject: [PATCH 105/169] add troubleshooting --- MetaLamp/lending-pool/README.md | 4 ++++ MetaLamp/lending-pool/client/README.md | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/MetaLamp/lending-pool/README.md b/MetaLamp/lending-pool/README.md index 1d05910e8..719f0204a 100644 --- a/MetaLamp/lending-pool/README.md +++ b/MetaLamp/lending-pool/README.md @@ -44,3 +44,7 @@ cabal run pab-simulation ## Client See the client [readme](client/README.md). + +## Troubleshooting + +See [note](client/README.md/#Troubleshooting). diff --git a/MetaLamp/lending-pool/client/README.md b/MetaLamp/lending-pool/client/README.md index a3431ba89..441d598bc 100644 --- a/MetaLamp/lending-pool/client/README.md +++ b/MetaLamp/lending-pool/client/README.md @@ -22,3 +22,16 @@ CORS protection needs to be disabled. You can use this script to launch chromium ``` npm run start-chrome ``` + +## Troubleshooting + +Sometimes the build results in error with Haskell IDE enabled. If the build does not work or the app behaves strangely, disable IDE and clean all source files: + +``` +cd MetaLamp/lending-pool/ && cabal clean +``` + +``` +cd MetaLamp/lending-pool/client && rm -rf node_modules/ generated/ output/ plutus-purs/ .spago/ +``` + From 8964417f435b725ae0c3bdfb2c29ee08d2b2fbbb Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 17 Jun 2021 14:35:01 +0700 Subject: [PATCH 106/169] add functions description --- MetaLamp/lending-pool/README.md | 4 ++++ MetaLamp/lending-pool/client/README.md | 1 - MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs | 1 + MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs | 9 +++++++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/README.md b/MetaLamp/lending-pool/README.md index 719f0204a..110402109 100644 --- a/MetaLamp/lending-pool/README.md +++ b/MetaLamp/lending-pool/README.md @@ -48,3 +48,7 @@ See the client [readme](client/README.md). ## Troubleshooting See [note](client/README.md/#Troubleshooting). + +## Protocol functionality + +See description of user endpoints [here](src/Plutus/Contracts/Endpoints.hs) diff --git a/MetaLamp/lending-pool/client/README.md b/MetaLamp/lending-pool/client/README.md index 441d598bc..0f16fd0d9 100644 --- a/MetaLamp/lending-pool/client/README.md +++ b/MetaLamp/lending-pool/client/README.md @@ -34,4 +34,3 @@ cd MetaLamp/lending-pool/ && cabal clean ``` cd MetaLamp/lending-pool/client && rm -rf node_modules/ generated/ output/ plutus-purs/ .spago/ ``` - diff --git a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs index 721d46993..6a699ec23 100644 --- a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs +++ b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs @@ -37,6 +37,7 @@ findValueByDatumHash dh outs = mconcat $ mapMaybe f outs | otherwise = Nothing {-# INLINABLE parseDatum #-} +-- | Find datum inside pending transaction and parse it from data parseDatum :: PlutusTx.IsData a => TxInfo -> DatumHash -> Maybe a parseDatum txInfo dh = findDatum dh txInfo >>= (PlutusTx.fromData . getDatum) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 9bf311947..0026f7d49 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -76,6 +76,7 @@ createReserve aave CreateParams {..} = rCurrentStableBorrowRate = 11 % 10 -- TODO configure borrow rate when lending core will be ready } +-- | Starts the Lending Pool protocol: minting pool NFTs, creating empty user configuration state and all specified liquidity reserves start :: HasBlockchainActions s => [CreateParams] -> Contract w s Text Aave start params = do pkh <- pubKeyHash <$> ownPubKey @@ -111,9 +112,11 @@ type AaveOwnerSchema = BlockchainActions .\/ Endpoint "start" () +-- | Gets current Lending Pool reserves state reserves :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map AssetClass Reserve) reserves aave = ovValue <$> State.findAaveReserves aave +-- | Gets current Lending Pool user configs state users :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) users aave = ovValue <$> State.findAaveUserConfigs aave @@ -125,12 +128,14 @@ valueAt address = do getOwnPubKey :: HasBlockchainActions s => Contract w s Text PubKeyHash getOwnPubKey = pubKeyHash <$> ownPubKey +-- | Gets all UTxOs belonging to a user and concats them into one Value fundsAt :: HasBlockchainActions s => PubKeyHash -> Contract w s Text Value fundsAt pkh = valueAt (pubKeyHashAddress pkh) balanceAt :: HasBlockchainActions s => PubKeyHash -> AssetClass -> Contract w s Text Integer balanceAt pkh asset = flip assetClassValueOf asset <$> fundsAt pkh +-- | Gets all UTxOs belonging to the Lending Pool script and concats them into one Value poolFunds :: HasBlockchainActions s => Aave -> Contract w s Text Value poolFunds aave = valueAt (Core.aaveAddress aave) @@ -149,6 +154,7 @@ data DepositParams = PlutusTx.unstableMakeIsData ''DepositParams PlutusTx.makeLift ''DepositParams +-- | The user puts N amount of his asset into a corresponding reserve, in exchange he gets N equivalent aTokens deposit :: (HasBlockchainActions s) => Aave -> DepositParams -> Contract w s Text () deposit aave DepositParams {..} = do reserve <- State.findAaveReserve aave dpAsset @@ -187,6 +193,7 @@ data WithdrawParams = PlutusTx.unstableMakeIsData ''WithdrawParams PlutusTx.makeLift ''WithdrawParams +-- | The user withdraws N amount of a specific asset from the corresponding reserve, N aTokens are taken from his wallet and burned withdraw :: (HasBlockchainActions s) => Aave -> WithdrawParams -> Contract w s Text () withdraw aave WithdrawParams {..} = do reserve <- State.findAaveReserve aave wpAsset @@ -218,6 +225,7 @@ data BorrowParams = PlutusTx.unstableMakeIsData ''BorrowParams PlutusTx.makeLift ''BorrowParams +-- | The user borrows N amount of a needed asset from the corresponding reserve, his debt entry state is encreased by N borrow :: (HasBlockchainActions s) => Aave -> BorrowParams -> Contract w s Text () borrow aave BorrowParams {..} = do reserve <- State.findAaveReserve aave bpAsset @@ -262,6 +270,7 @@ data RepayParams = PlutusTx.unstableMakeIsData ''RepayParams PlutusTx.makeLift ''RepayParams +-- | The user repays N amount of a specific asset to the corresponding reserve, his debt entry state is decreased by N repay :: (HasBlockchainActions s) => Aave -> RepayParams -> Contract w s Text () repay aave RepayParams {..} = do reserve <- State.findAaveReserve aave rpAsset From f82f5fc512dd74594ef401f388f0c8911960a356 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 17 Jun 2021 14:50:56 +0700 Subject: [PATCH 107/169] add logs for completing initialization --- MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 59257821c..47df913aa 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -116,6 +116,7 @@ runLendingPool = void $ Simulator.runSimulationWith handlers $ do Simulator.logString @(Builtin AaveContracts) "Starting Aave PAB webserver on port 8080. Press enter to exit." shutdown <- PAB.Server.startServerDebug _ <- activateContracts + Simulator.logString @(Builtin AaveContracts) "Aave PAB webserver started on port 8080. Initialization complete. Press enter to exit." _ <- liftIO getLine shutdown From ec40066209a5474068e29932b6e4e12ad181c43d Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 17 Jun 2021 15:09:19 +0700 Subject: [PATCH 108/169] fix typos --- MetaLamp/lending-pool/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MetaLamp/lending-pool/README.md b/MetaLamp/lending-pool/README.md index 110402109..d394d8453 100644 --- a/MetaLamp/lending-pool/README.md +++ b/MetaLamp/lending-pool/README.md @@ -11,7 +11,7 @@ The smart contract protocol is based on [Aave](https://aave.com/), but does not ## The Plutus Application Backend (PAB) usage -We have provided two PAB applications in `./pab` and `./pab-simulation`. First one is made for real world usage and interaction throw frontend [client](client/README.md), second one is a big test scenario. +We have provided two PAB applications in `./pab` and `./pab-simulation`. The first one is made for real world usage and interaction through frontend [client](client/README.md), the second one is a big test scenario. With the PAB we can serve and interact with contracts over a web API. You can read more about the PAB here: [PAB Architecture](https://github.com/input-output-hk/plutus/blob/master/plutus-pab/ARCHITECTURE.adoc). 1. Enter the nix shell (cd to the cloned Plutus repo): @@ -35,7 +35,7 @@ cabal run pab This will then start up the server on port 8080. -4. To Run test simulation do: +4. To run test simulation do: ``` cabal run pab-simulation @@ -51,4 +51,4 @@ See [note](client/README.md/#Troubleshooting). ## Protocol functionality -See description of user endpoints [here](src/Plutus/Contracts/Endpoints.hs) +See the description of user endpoints [here](src/Plutus/Contracts/Endpoints.hs) From 37f6eb09de8ff814c6e8f8559a128f6f257e4ece Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 17 Jun 2021 15:29:36 +0700 Subject: [PATCH 109/169] add collateral endpoints into schema --- MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index a10fcffd4..698f4d402 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -366,6 +366,8 @@ type AaveUserSchema = .\/ Endpoint "withdraw" WithdrawParams .\/ Endpoint "borrow" BorrowParams .\/ Endpoint "repay" RepayParams + .\/ Endpoint "provideCollateral" ProvideCollateralParams + .\/ Endpoint "revokeCollateral" RevokeCollateralParams .\/ Endpoint "ownPubKey" () .\/ Endpoint "ownPubKeyBalance" () @@ -374,6 +376,8 @@ data UserContractState = | Withdrawn | Borrowed | Repaid + | CollateralProvided + | CollateralRevoked | GetPubKey PubKeyHash | GetPubKeyBalance Value deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) @@ -384,6 +388,8 @@ userEndpoints aave = forever $ `select` handleContract (Proxy @"withdraw") (const Withdrawn) (withdraw aave) `select` handleContract (Proxy @"borrow") (const Borrowed) (borrow aave) `select` handleContract (Proxy @"repay") (const Repaid) (repay aave) + `select` handleContract (Proxy @"provideCollateral") (const CollateralProvided) (provideCollateral aave) + `select` handleContract (Proxy @"revokeCollateral") (const CollateralRevoked) (revokeCollateral aave) `select` handleContract (Proxy @"ownPubKey") GetPubKey (const getOwnPubKey) `select` handleContract (Proxy @"ownPubKeyBalance") GetPubKeyBalance (const ownPubKeyBalance) From 841ef40c6ba887c7416f52d49d3db52efa224cbb Mon Sep 17 00:00:00 2001 From: megakaban Date: Thu, 17 Jun 2021 17:00:01 +0700 Subject: [PATCH 110/169] Fix client README, replace literally with strictly --- MetaLamp/lending-pool/README.md | 2 +- MetaLamp/lending-pool/client/README.md | 23 +++++++++++++++++++---- MetaLamp/lending-pool/client/package.json | 4 ++-- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/MetaLamp/lending-pool/README.md b/MetaLamp/lending-pool/README.md index d394d8453..c1aaaa9c4 100644 --- a/MetaLamp/lending-pool/README.md +++ b/MetaLamp/lending-pool/README.md @@ -1,7 +1,7 @@ # Lending Pool Lending Pool is a smart contract application on Plutus Platform. -The smart contract protocol is based on [Aave](https://aave.com/), but does not follow it literally. +The smart contract protocol is based on [Aave](https://aave.com/), but does not strictly follow it. ## Setting up diff --git a/MetaLamp/lending-pool/client/README.md b/MetaLamp/lending-pool/client/README.md index 0f16fd0d9..155196fcf 100644 --- a/MetaLamp/lending-pool/client/README.md +++ b/MetaLamp/lending-pool/client/README.md @@ -1,22 +1,37 @@ # Lending pool client -The client application has minimalistic interface to the PAB [server](/MetaLamp/lending-pool/README.md). +The client application has a minimalistic interface to the PAB [server](/MetaLamp/lending-pool/README.md). ## Running the project -1. Generate necessary PureScript code from Haskell source (cd to /MetaLamp/lending-pool/client/): +1. Install npm packages. ``` npm install ``` -2. Start the client: +2. Generate necessary PureScript code from Haskell source. This step runs an executable(`generate-purs`) from `lending-pool` directory, which requires a certain environment. The setup steps are described in `lending-pool/README`. Provided that you are able to build the backend, you can use the same approach to run purescript generation from `client` folder, i.e. + +Enter the nix shell (cd to the cloned Plutus repo): + +``` +git checkout 5cdd2c3d708bf4c33514681dee096da6463273b7 +nix-shell +``` + +cd to `lending-pool/client` folder and execute + +``` +npm run generate-purs +``` + +3. Start the client: ``` npm start ``` -3. Open browser to interact with the app at https://localhost:8009/. +4. Open browser to interact with the app at https://localhost:8009/. CORS protection needs to be disabled. You can use this script to launch chromium (note that first you need to close chromium completely, otherwise security won't be disabled): ``` diff --git a/MetaLamp/lending-pool/client/package.json b/MetaLamp/lending-pool/client/package.json index b1e4ec580..8e1155d8e 100644 --- a/MetaLamp/lending-pool/client/package.json +++ b/MetaLamp/lending-pool/client/package.json @@ -9,10 +9,10 @@ "purs:compile": "spago build", "docs": "spago docs", "repl": "spago repl", - "generate-purs": "sh ./scripts/generate-purs.sh", "fetch-plutus-purs": "sh ./scripts/fetch-plutus-purs.sh", + "generate-purs-only": "sh ./scripts/generate-purs.sh", + "generate-purs": "npm run fetch-plutus-purs && npm run generate-purs-only", "start-chrome": "sh ./scripts/start-chrome.sh", - "preinstall": "npm run fetch-plutus-purs && npm run generate-purs", "start": "npm run purs:compile && npm run webpack:server" }, "dependencies": { From e092477311406b918f2ffaa9aa90209c3ba06d9c Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 17 Jun 2021 17:44:47 +0700 Subject: [PATCH 111/169] fix collateral payment transactions --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 1 + MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index c095f9947..3f4b4cf87 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -154,6 +154,7 @@ makeAaveValidator aave datum (DepositRedeemer userConfigId) ctx = trace "Deposi makeAaveValidator aave datum (WithdrawRedeemer userConfigId) ctx = trace "WithdrawRedeemer" $ validateWithdraw aave datum ctx userConfigId makeAaveValidator aave datum (BorrowRedeemer userConfigId) ctx = trace "BorrowRedeemer" $ validateBorrow aave datum ctx userConfigId makeAaveValidator aave datum (RepayRedeemer userConfigId) ctx = trace "RepayRedeemer" $ validateRepay aave datum ctx userConfigId +makeAaveValidator aave datum (RevokeCollateralRedeemer userConfigId) ctx = trace "RevokeCollateralRedeemer" True validateStart :: Aave -> AaveDatum -> ScriptContext -> Bool validateStart aave (LendingPoolDatum operator) ctx = diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 698f4d402..9fce4d28e 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -292,8 +292,11 @@ provideCollateral :: (HasBlockchainActions s) => Aave -> ProvideCollateralParams provideCollateral aave ProvideCollateralParams {..} = do reserve <- State.findAaveReserve aave pcpUnderlyingAsset + userOwnedAtokenAmount <- balanceAt pcpOnBehalfOf (rAToken reserve) let payment = assetClassValue (rAToken reserve) pcpAmount + let remainder = assetClassValue (rAToken reserve) (userOwnedAtokenAmount - pcpAmount) let fundsLockingTx = TxUtils.mustPayToScript (Core.aaveInstance aave) pcpOnBehalfOf (Core.UserCollateralFundsDatum pcpOnBehalfOf) payment + <> (Prelude.mempty, mustPayToPubKey pcpOnBehalfOf remainder) ledgerTx <- TxUtils.submitTxPair fundsLockingTx _ <- awaitTxConfirmed $ txId ledgerTx @@ -319,10 +322,11 @@ revokeCollateral aave RevokeCollateralParams {..} = do utxos <- Map.filter (getUsersCollateral aTokenAsset) <$> utxoAt (Core.aaveAddress aave) + let usersCollateralValue = Prelude.foldMap (txOutValue . txOutTxOut) utxos let userConfigId = (rCurrency reserve, rcpOnBehalfOf) let inputs = (\(ref, tx) -> OutputValue ref tx (Core.RevokeCollateralRedeemer userConfigId)) <$> Map.toList utxos let payment = assetClassValue aTokenAsset rcpAmount - let remainder = assetClassValue aTokenAsset (rAmount reserve - rcpAmount) + let remainder = assetClassValue aTokenAsset (assetClassValueOf usersCollateralValue aTokenAsset - rcpAmount) let fundsUnlockingTx = TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs rcpOnBehalfOf payment <> TxUtils.mustPayToScript (Core.aaveInstance aave) rcpOnBehalfOf userDatum remainder From 0fea720479d47b24900bbbf3ad4a01b21bbb5126 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 17 Jun 2021 17:52:09 +0700 Subject: [PATCH 112/169] add collateral endpoints to simulation --- .../lending-pool/src/Plutus/PAB/Simulation.hs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 59257821c..20ea71b46 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -129,7 +129,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do _ <- Simulator.callEndpointOnInstance userCid "deposit" $ - Aave.DepositParams { Aave.dpAsset = head testAssets, Aave.dpOnBehalfOf = sender, Aave.dpAmount = 100 } + Aave.DepositParams { Aave.dpAsset = head testAssets, Aave.dpOnBehalfOf = sender, Aave.dpAmount = 400 } flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of Success (Monoid.Last (Just (ContractSuccess Aave.Deposited))) -> Just () _ -> Nothing @@ -143,6 +143,22 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful withdraw" + _ <- + Simulator.callEndpointOnInstance userCid "provideCollateral" $ + Aave.ProvideCollateralParams { Aave.pcpUnderlyingAsset = head testAssets, Aave.pcpOnBehalfOf = sender, Aave.pcpAmount = 200 } + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of + Success (Monoid.Last (Just (ContractSuccess Aave.CollateralProvided))) -> Just () + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Successful provideCollateral" + + _ <- + Simulator.callEndpointOnInstance userCid "revokeCollateral" $ + Aave.RevokeCollateralParams { Aave.rcpUnderlyingAsset = head testAssets, Aave.rcpOnBehalfOf = sender, Aave.rcpAmount = 50 } + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of + Success (Monoid.Last (Just (ContractSuccess Aave.CollateralRevoked))) -> Just () + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Successful revokeCollateral" + let lenderCid = cidUser Map.! Wallet 3 let lender = pubKeyHash . walletPubKey $ Wallet 3 _ <- From 0852982875fcd8326e9948112d4a67c0c2c6697b Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 17 Jun 2021 20:59:31 +0700 Subject: [PATCH 113/169] add collateralized investment in user config --- .../lending-pool/src/Plutus/Contracts/Core.hs | 31 +++++++++---- .../src/Plutus/Contracts/Endpoints.hs | 44 ++++++++++++++----- 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 3f4b4cf87..524d713a1 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -76,9 +76,11 @@ PlutusTx.makeLift ''Reserve -- , iaSlot :: Slot -- } -newtype UserConfig = UserConfig +data UserConfig = UserConfig { - ucDebt :: Integer + ucDebt :: Integer, + ucCollateralizedInvestment :: Integer + } deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) @@ -90,9 +92,10 @@ data AaveRedeemer = StartRedeemer | DepositRedeemer (AssetClass, PubKeyHash) | WithdrawRedeemer (AssetClass, PubKeyHash) - | BorrowRedeemer (AssetClass, PubKeyHash) + | BorrowRedeemer (AssetClass, PubKeyHash) -- we need to check amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace | RepayRedeemer (AssetClass, PubKeyHash) - | RevokeCollateralRedeemer (AssetClass, PubKeyHash) + | ProvideCollateralRedeemer (AssetClass, PubKeyHash) + | RevokeCollateralRedeemer (AssetClass, PubKeyHash) -- we need to check amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace deriving Show PlutusTx.unstableMakeIsData ''AaveRedeemer @@ -105,10 +108,10 @@ type Oracles = AssocMap.Map AssetClass Integer -- Shows how many lovelaces shoul data AaveDatum = LendingPoolDatum LendingPoolOperator - | ReservesDatum AssetClass (AssocMap.Map AssetClass Reserve) + | ReservesDatum AssetClass (AssocMap.Map AssetClass Reserve) -- State token and reserve currency -> reserve map | ReserveFundsDatum - | UserConfigsDatum AssetClass (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) - | UserCollateralFundsDatum PubKeyHash + | UserConfigsDatum AssetClass (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -- State token and UserConfigId -> user config map + | UserCollateralFundsDatum PubKeyHash AssetClass -- User pub key and aToken asset type deriving stock (Show) PlutusTx.unstableMakeIsData ''AaveDatum @@ -142,6 +145,7 @@ instance Scripts.ValidatorTypes AaveScript where -- Main validator -- Each state field must have one or more associated actions(Redeemer types), -- produced on state update, which are then validated here +-- TODO validate ucCollateralizedInvestment does not change on Deposit Withdraw Borrow Repay makeAaveValidator :: Aave -> AaveDatum -> AaveRedeemer @@ -154,7 +158,7 @@ makeAaveValidator aave datum (DepositRedeemer userConfigId) ctx = trace "Deposi makeAaveValidator aave datum (WithdrawRedeemer userConfigId) ctx = trace "WithdrawRedeemer" $ validateWithdraw aave datum ctx userConfigId makeAaveValidator aave datum (BorrowRedeemer userConfigId) ctx = trace "BorrowRedeemer" $ validateBorrow aave datum ctx userConfigId makeAaveValidator aave datum (RepayRedeemer userConfigId) ctx = trace "RepayRedeemer" $ validateRepay aave datum ctx userConfigId -makeAaveValidator aave datum (RevokeCollateralRedeemer userConfigId) ctx = trace "RevokeCollateralRedeemer" True +makeAaveValidator aave datum (RevokeCollateralRedeemer userConfigId) ctx = trace "RevokeCollateralRedeemer" $ validateRevokeCollateral aave datum ctx userConfigId validateStart :: Aave -> AaveDatum -> ScriptContext -> Bool validateStart aave (LendingPoolDatum operator) ctx = @@ -293,6 +297,17 @@ validateRepay aave (ReservesDatum stateToken reserves) ctx userConfigId = validateRepay _ _ _ _ = trace "validateRepay: Lending Pool Datum management is not allowed" False +validateRevokeCollateral :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool +validateRevokeCollateral aave (UserCollateralFundsDatum owner aTokenAsset) ctx (reserveId, actor) = + traceIfFalse "validateRevokeCollateral: UserCollateralFundsDatum change is not valid" $ owner == actor + where + txInfo = scriptContextTxInfo ctx + + actorSpentValue = valueSpentFrom txInfo actor + actorRemainderValue = valuePaidTo txInfo actor + +validateRevokeCollateral _ _ _ _ = trace "validateRevokeCollateral: Lending Pool Datum management is not allowed" False + checkNegativeFundsTransformation :: ScriptContext -> (AssetClass, PubKeyHash) -> Bool checkNegativeFundsTransformation ctx (reserveId, actor) = isValidFundsChange where diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 4d2f0e618..8d9c17996 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -169,7 +169,7 @@ deposit aave DepositParams {..} = do aave (Core.DepositRedeemer userConfigId) userConfigId - UserConfig { ucDebt = 0 } + UserConfig { ucDebt = 0, ucCollateralizedInvestment = 0 } Just userConfig -> pure mempty @@ -239,7 +239,7 @@ borrow aave BorrowParams {..} = do aave (Core.BorrowRedeemer userConfigId) userConfigId - UserConfig { ucDebt = bpAmount } + UserConfig { ucDebt = bpAmount, ucCollateralizedInvestment = 0 } Just userConfig -> State.updateUserConfig aave (Core.BorrowRedeemer userConfigId) userConfigId $ userConfig { ucDebt = ucDebt userConfig + bpAmount} @@ -301,13 +301,28 @@ provideCollateral :: (HasBlockchainActions s) => Aave -> ProvideCollateralParams provideCollateral aave ProvideCollateralParams {..} = do reserve <- State.findAaveReserve aave pcpUnderlyingAsset - userOwnedAtokenAmount <- balanceAt pcpOnBehalfOf (rAToken reserve) - let payment = assetClassValue (rAToken reserve) pcpAmount - let remainder = assetClassValue (rAToken reserve) (userOwnedAtokenAmount - pcpAmount) - let fundsLockingTx = TxUtils.mustPayToScript (Core.aaveInstance aave) pcpOnBehalfOf (Core.UserCollateralFundsDatum pcpOnBehalfOf) payment + let aTokenAsset = rAToken reserve + userOwnedAtokenAmount <- balanceAt pcpOnBehalfOf aTokenAsset + let payment = assetClassValue aTokenAsset pcpAmount + let remainder = assetClassValue aTokenAsset (userOwnedAtokenAmount - pcpAmount) + let fundsLockingTx = TxUtils.mustPayToScript (Core.aaveInstance aave) pcpOnBehalfOf (Core.UserCollateralFundsDatum pcpOnBehalfOf aTokenAsset) payment <> (Prelude.mempty, mustPayToPubKey pcpOnBehalfOf remainder) - ledgerTx <- TxUtils.submitTxPair fundsLockingTx + let userConfigId = (rCurrency reserve, pcpOnBehalfOf) + userConfigsTx <- do + userConfigs <- ovValue <$> State.findAaveUserConfigs aave + case AssocMap.lookup userConfigId userConfigs of + Nothing -> + State.addUserConfig + aave + (Core.ProvideCollateralRedeemer userConfigId) + userConfigId + UserConfig { ucDebt = 0, ucCollateralizedInvestment = pcpAmount } + Just userConfig -> + State.updateUserConfig aave (Core.ProvideCollateralRedeemer userConfigId) userConfigId $ + userConfig { ucCollateralizedInvestment = ucCollateralizedInvestment userConfig + pcpAmount } + + ledgerTx <- TxUtils.submitTxPair $ fundsLockingTx <> userConfigsTx _ <- awaitTxConfirmed $ txId ledgerTx pure () @@ -337,16 +352,25 @@ revokeCollateral aave RevokeCollateralParams {..} = do let payment = assetClassValue aTokenAsset rcpAmount let remainder = assetClassValue aTokenAsset (assetClassValueOf usersCollateralValue aTokenAsset - rcpAmount) let fundsUnlockingTx = TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs rcpOnBehalfOf payment <> - TxUtils.mustPayToScript (Core.aaveInstance aave) rcpOnBehalfOf userDatum remainder + TxUtils.mustPayToScript (Core.aaveInstance aave) rcpOnBehalfOf (userDatum aTokenAsset) remainder + + userConfigsTx <- do + userConfigs <- ovValue <$> State.findAaveUserConfigs aave + case AssocMap.lookup userConfigId userConfigs of + Nothing -> + throwError "User does not have any collateral." + Just userConfig -> + State.updateUserConfig aave (Core.RevokeCollateralRedeemer userConfigId) userConfigId $ + userConfig { ucCollateralizedInvestment = ucCollateralizedInvestment userConfig - rcpAmount } - ledgerTx <- TxUtils.submitTxPair fundsUnlockingTx + ledgerTx <- TxUtils.submitTxPair $ fundsUnlockingTx <> userConfigsTx _ <- awaitTxConfirmed $ txId ledgerTx pure () where userDatum = Core.UserCollateralFundsDatum rcpOnBehalfOf getUsersCollateral :: AssetClass -> TxOutTx -> Bool getUsersCollateral asset tx = ((> 0) . flip assetClassValueOf asset . txOutValue . txOutTxOut $ tx) && - (txOutDatumHash . txOutTxOut $ tx) == Just (datumHash . Datum . PlutusTx.toData $ userDatum) + (txOutDatumHash . txOutTxOut $ tx) == Just (datumHash . Datum . PlutusTx.toData $ userDatum asset) -- TODO ? add repayWithCollateral From 3e29e82c498b335af88f64866f4eac31dce804c8 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 18 Jun 2021 14:55:43 +0700 Subject: [PATCH 114/169] add provide collateral validator --- .../lending-pool/src/Plutus/Contracts/Core.hs | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 524d713a1..abbf64748 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -128,6 +128,11 @@ pickReserves :: AaveDatum -> Maybe (AssetClass, AssocMap.Map AssetClass Reserve) pickReserves (ReservesDatum stateToken configs) = Just (stateToken, configs) pickReserves _ = Nothing +{-# INLINABLE pickUserCollateralFunds #-} +pickUserCollateralFunds :: AaveDatum -> Maybe (PubKeyHash, AssetClass) +pickUserCollateralFunds (UserCollateralFundsDatum user aTokenAsset) = Just (user, aTokenAsset) +pickUserCollateralFunds _ = Nothing + -- TODO calculate these params in new module: -- totalCollateralInLovelace :: AssocMap.Map AssetClass Integer -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig -> Either String Integer -- totalCollateralInLovelace oracles userConfigs = 0 @@ -158,6 +163,7 @@ makeAaveValidator aave datum (DepositRedeemer userConfigId) ctx = trace "Deposi makeAaveValidator aave datum (WithdrawRedeemer userConfigId) ctx = trace "WithdrawRedeemer" $ validateWithdraw aave datum ctx userConfigId makeAaveValidator aave datum (BorrowRedeemer userConfigId) ctx = trace "BorrowRedeemer" $ validateBorrow aave datum ctx userConfigId makeAaveValidator aave datum (RepayRedeemer userConfigId) ctx = trace "RepayRedeemer" $ validateRepay aave datum ctx userConfigId +makeAaveValidator aave datum (ProvideCollateralRedeemer userConfigId) ctx = trace "ProvideCollateralRedeemer" $ validateProvideCollateral aave datum ctx userConfigId makeAaveValidator aave datum (RevokeCollateralRedeemer userConfigId) ctx = trace "RevokeCollateralRedeemer" $ validateRevokeCollateral aave datum ctx userConfigId validateStart :: Aave -> AaveDatum -> ScriptContext -> Bool @@ -297,9 +303,51 @@ validateRepay aave (ReservesDatum stateToken reserves) ctx userConfigId = validateRepay _ _ _ _ = trace "validateRepay: Lending Pool Datum management is not allowed" False +validateProvideCollateral :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool +validateProvideCollateral aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) = + traceIfFalse "validateProvideCollateral: User Configs Datum change is not valid" isValidUserConfigsTransformation + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + + userConfigsOutputDatumHash = + findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs + userConfigsOutputDatum :: + Maybe (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) + userConfigsOutputDatum = + userConfigsOutputDatumHash >>= parseDatum txInfo >>= pickUserConfigs + + actorSpentValue = valueSpentFrom txInfo actor + actorRemainderValue = valuePaidTo txInfo actor + + collateralOutputDatumHash = + findOnlyOneDatumHashByValue (actorSpentValue - actorRemainderValue - txInfoFee txInfo) scriptOutputs + collateralOutputDatum :: + Maybe (PubKeyHash, AssetClass) + collateralOutputDatum = + collateralOutputDatumHash >>= parseDatum txInfo >>= pickUserCollateralFunds + + isValidUserConfigsTransformation :: Bool + isValidUserConfigsTransformation = + fromMaybe False $ checkUserConfigs <$> userConfigsOutputDatum <*> collateralOutputDatum + checkUserConfigs :: + (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -> (PubKeyHash, AssetClass) -> Bool + checkUserConfigs (newStateToken, newUserConfigs) (user, aTokenAsset) = + newStateToken == stateToken && user == actor && + maybe False (checkRedeemerConfig aTokenAsset $ AssocMap.lookup userConfigId userConfigs) (AssocMap.lookup userConfigId newUserConfigs) + checkRedeemerConfig :: AssetClass -> Maybe UserConfig -> UserConfig -> Bool + checkRedeemerConfig asset oldState newState = + let investmentAmount = (ucCollateralizedInvestment newState -) $ maybe 0 ucCollateralizedInvestment oldState + disbursementAmount = assetClassValueOf actorSpentValue asset - assetClassValueOf actorRemainderValue asset + in investmentAmount == disbursementAmount && investmentAmount > 0 && disbursementAmount > 0 && + maybe (ucDebt newState == 0) ((ucDebt newState ==) . ucDebt) oldState + +validateProvideCollateral _ _ _ _ = trace "validateProvideCollateral: Lending Pool Datum management is not allowed" False + validateRevokeCollateral :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool validateRevokeCollateral aave (UserCollateralFundsDatum owner aTokenAsset) ctx (reserveId, actor) = - traceIfFalse "validateRevokeCollateral: UserCollateralFundsDatum change is not valid" $ owner == actor + traceIfFalse "validateRevokeCollateral: UserCollateralFundsDatum change is not valid" $ owner == actor && False where txInfo = scriptContextTxInfo ctx From 9536907041c7acaf16e7e3ff324a9a4b14390867 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 18 Jun 2021 15:34:24 +0700 Subject: [PATCH 115/169] add user configs validator for revoke --- .../lending-pool/src/Plutus/Contracts/Core.hs | 45 ++++++++++++++++--- .../src/Plutus/Contracts/Endpoints.hs | 7 +-- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index abbf64748..c343a6d72 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -92,10 +92,10 @@ data AaveRedeemer = StartRedeemer | DepositRedeemer (AssetClass, PubKeyHash) | WithdrawRedeemer (AssetClass, PubKeyHash) - | BorrowRedeemer (AssetClass, PubKeyHash) -- we need to check amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace + | BorrowRedeemer (AssetClass, PubKeyHash) -- TODO we need to check amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace | RepayRedeemer (AssetClass, PubKeyHash) | ProvideCollateralRedeemer (AssetClass, PubKeyHash) - | RevokeCollateralRedeemer (AssetClass, PubKeyHash) -- we need to check amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace + | RevokeCollateralRedeemer (AssetClass, PubKeyHash) AssetClass -- TODO we need to check amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace deriving Show PlutusTx.unstableMakeIsData ''AaveRedeemer @@ -164,7 +164,7 @@ makeAaveValidator aave datum (WithdrawRedeemer userConfigId) ctx = trace "Withdr makeAaveValidator aave datum (BorrowRedeemer userConfigId) ctx = trace "BorrowRedeemer" $ validateBorrow aave datum ctx userConfigId makeAaveValidator aave datum (RepayRedeemer userConfigId) ctx = trace "RepayRedeemer" $ validateRepay aave datum ctx userConfigId makeAaveValidator aave datum (ProvideCollateralRedeemer userConfigId) ctx = trace "ProvideCollateralRedeemer" $ validateProvideCollateral aave datum ctx userConfigId -makeAaveValidator aave datum (RevokeCollateralRedeemer userConfigId) ctx = trace "RevokeCollateralRedeemer" $ validateRevokeCollateral aave datum ctx userConfigId +makeAaveValidator aave datum (RevokeCollateralRedeemer userConfigId aTokenAsset) ctx = trace "RevokeCollateralRedeemer" $ validateRevokeCollateral aave datum ctx userConfigId aTokenAsset validateStart :: Aave -> AaveDatum -> ScriptContext -> Bool validateStart aave (LendingPoolDatum operator) ctx = @@ -345,8 +345,41 @@ validateProvideCollateral aave (UserConfigsDatum stateToken userConfigs) ctx us validateProvideCollateral _ _ _ _ = trace "validateProvideCollateral: Lending Pool Datum management is not allowed" False -validateRevokeCollateral :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool -validateRevokeCollateral aave (UserCollateralFundsDatum owner aTokenAsset) ctx (reserveId, actor) = +validateRevokeCollateral :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> AssetClass -> Bool +validateRevokeCollateral aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) aTokenAsset = + traceIfFalse "validateRevokeCollateral: User Configs Datum change is not valid" isValidUserConfigsTransformation + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + + userConfigsOutputDatumHash = + findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs + userConfigsOutputDatum :: + Maybe (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) + userConfigsOutputDatum = + userConfigsOutputDatumHash >>= parseDatum txInfo >>= pickUserConfigs + + actorSpentValue = valueSpentFrom txInfo actor + actorRemainderValue = valuePaidTo txInfo actor + + isValidUserConfigsTransformation :: Bool + isValidUserConfigsTransformation = + maybe False checkUserConfigs userConfigsOutputDatum + checkUserConfigs :: + (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -> Bool + checkUserConfigs (newStateToken, newUserConfigs) = + newStateToken == stateToken && + fromMaybe False (checkRedeemerConfig <$> (AssocMap.lookup userConfigId userConfigs) <*> (AssocMap.lookup userConfigId newUserConfigs)) + checkRedeemerConfig :: UserConfig -> UserConfig -> Bool + checkRedeemerConfig oldState newState = + let newInvestmentAmount = ucCollateralizedInvestment newState + investmentShrinkedBy = ucCollateralizedInvestment oldState - newInvestmentAmount + disbursementAmount = assetClassValueOf actorRemainderValue aTokenAsset - assetClassValueOf actorSpentValue aTokenAsset + in investmentShrinkedBy == disbursementAmount && investmentShrinkedBy > 0 && disbursementAmount > 0 && newInvestmentAmount >= 0 && + (ucDebt newState == ucDebt oldState) + +validateRevokeCollateral aave (UserCollateralFundsDatum owner aTokenAsset) ctx (reserveId, actor) revokedAsset = traceIfFalse "validateRevokeCollateral: UserCollateralFundsDatum change is not valid" $ owner == actor && False where txInfo = scriptContextTxInfo ctx @@ -354,7 +387,7 @@ validateRevokeCollateral aave (UserCollateralFundsDatum owner aTokenAsset) ctx actorSpentValue = valueSpentFrom txInfo actor actorRemainderValue = valuePaidTo txInfo actor -validateRevokeCollateral _ _ _ _ = trace "validateRevokeCollateral: Lending Pool Datum management is not allowed" False +validateRevokeCollateral _ _ _ _ _ = trace "validateRevokeCollateral: Lending Pool Datum management is not allowed" False checkNegativeFundsTransformation :: ScriptContext -> (AssetClass, PubKeyHash) -> Bool checkNegativeFundsTransformation ctx (reserveId, actor) = isValidFundsChange diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 8d9c17996..94f65fc18 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -343,12 +343,13 @@ revokeCollateral aave RevokeCollateralParams {..} = do reserve <- State.findAaveReserve aave rcpUnderlyingAsset let aTokenAsset = rAToken reserve + let userConfigId = (rCurrency reserve, rcpOnBehalfOf) + let redeemer = Core.RevokeCollateralRedeemer userConfigId aTokenAsset utxos <- Map.filter (getUsersCollateral aTokenAsset) <$> utxoAt (Core.aaveAddress aave) let usersCollateralValue = Prelude.foldMap (txOutValue . txOutTxOut) utxos - let userConfigId = (rCurrency reserve, rcpOnBehalfOf) - let inputs = (\(ref, tx) -> OutputValue ref tx (Core.RevokeCollateralRedeemer userConfigId)) <$> Map.toList utxos + let inputs = (\(ref, tx) -> OutputValue ref tx redeemer) <$> Map.toList utxos let payment = assetClassValue aTokenAsset rcpAmount let remainder = assetClassValue aTokenAsset (assetClassValueOf usersCollateralValue aTokenAsset - rcpAmount) let fundsUnlockingTx = TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs rcpOnBehalfOf payment <> @@ -360,7 +361,7 @@ revokeCollateral aave RevokeCollateralParams {..} = do Nothing -> throwError "User does not have any collateral." Just userConfig -> - State.updateUserConfig aave (Core.RevokeCollateralRedeemer userConfigId) userConfigId $ + State.updateUserConfig aave redeemer userConfigId $ userConfig { ucCollateralizedInvestment = ucCollateralizedInvestment userConfig - rcpAmount } ledgerTx <- TxUtils.submitTxPair $ fundsUnlockingTx <> userConfigsTx From 0049731175c369815fbdadf13fe82289a0954a21 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 18 Jun 2021 15:55:29 +0700 Subject: [PATCH 116/169] add revoke funds validator --- .../lending-pool/src/Plutus/Contracts/Core.hs | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index c343a6d72..d582ea83c 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -221,8 +221,8 @@ validateWithdraw aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId validateWithdraw aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateWithdraw: Reserves Datum change is not valid" $ checkNegativeReservesTransformation stateToken reserves ctx userConfigId -validateWithdraw aave ReserveFundsDatum ctx userConfigId = - traceIfFalse "validateWithdraw: Reserve Funds Datum change is not valid" $ checkNegativeFundsTransformation ctx userConfigId +validateWithdraw aave ReserveFundsDatum ctx (reserveId, actor) = + traceIfFalse "validateWithdraw: Reserve Funds Datum change is not valid" $ checkNegativeFundsTransformation ctx reserveId actor validateWithdraw _ _ _ _ = trace "validateWithdraw: Lending Pool Datum management is not allowed" False @@ -261,8 +261,8 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( validateBorrow aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateBorrow: Reserves Datum change is not valid" $ checkNegativeReservesTransformation stateToken reserves ctx userConfigId -validateBorrow aave ReserveFundsDatum ctx userConfigId = - traceIfFalse "validateBorrow: Reserve Funds Datum change is not valid" $ checkNegativeFundsTransformation ctx userConfigId +validateBorrow aave ReserveFundsDatum ctx (reserveId, actor) = + traceIfFalse "validateBorrow: Reserve Funds Datum change is not valid" $ checkNegativeFundsTransformation ctx reserveId actor validateBorrow _ _ _ _ = trace "validateBorrow: Lending Pool Datum management is not allowed" False @@ -380,17 +380,13 @@ validateRevokeCollateral aave (UserConfigsDatum stateToken userConfigs) ctx use (ucDebt newState == ucDebt oldState) validateRevokeCollateral aave (UserCollateralFundsDatum owner aTokenAsset) ctx (reserveId, actor) revokedAsset = - traceIfFalse "validateRevokeCollateral: UserCollateralFundsDatum change is not valid" $ owner == actor && False - where - txInfo = scriptContextTxInfo ctx - - actorSpentValue = valueSpentFrom txInfo actor - actorRemainderValue = valuePaidTo txInfo actor + traceIfFalse "validateRevokeCollateral: UserCollateralFundsDatum change is not valid" $ + owner == actor && revokedAsset == aTokenAsset && checkNegativeFundsTransformation ctx aTokenAsset actor validateRevokeCollateral _ _ _ _ _ = trace "validateRevokeCollateral: Lending Pool Datum management is not allowed" False -checkNegativeFundsTransformation :: ScriptContext -> (AssetClass, PubKeyHash) -> Bool -checkNegativeFundsTransformation ctx (reserveId, actor) = isValidFundsChange +checkNegativeFundsTransformation :: ScriptContext -> AssetClass -> PubKeyHash -> Bool +checkNegativeFundsTransformation ctx asset actor = isValidFundsChange where txInfo = scriptContextTxInfo ctx (scriptsHash, scriptsDatumHash) = ownHashes ctx @@ -403,8 +399,8 @@ checkNegativeFundsTransformation ctx (reserveId, actor) = isValidFundsChange isValidFundsChange :: Bool isValidFundsChange = - let paidAmout = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId - fundsChange = assetClassValueOf scriptSpentValue reserveId - assetClassValueOf scriptRemainderValue reserveId + let paidAmout = assetClassValueOf actorRemainderValue asset - assetClassValueOf actorSpentValue asset + fundsChange = assetClassValueOf scriptSpentValue asset - assetClassValueOf scriptRemainderValue asset in fundsChange == paidAmout && fundsChange > 0 && paidAmout > 0 checkNegativeReservesTransformation :: AssetClass From 4e2d1cd910d0f50be29e3ad5d153139b187a43f8 Mon Sep 17 00:00:00 2001 From: megakaban Date: Fri, 18 Jun 2021 16:02:35 +0700 Subject: [PATCH 117/169] Use uniform way of handling contract endpoints for owner contract --- .../src/Plutus/Contracts/Endpoints.hs | 57 +++++++++---------- .../lending-pool/src/Plutus/PAB/Simulation.hs | 19 ++++--- 2 files changed, 39 insertions(+), 37 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 9bf311947..3a9a84ae3 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -100,16 +100,38 @@ start params = do logInfo @Prelude.String $ printf "started Aave %s at address %s" (show aave) (show $ Core.aaveAddress aave) pure aave -ownerEndpoint :: [CreateParams] -> Contract (Last (Either Text Aave)) BlockchainActions Void () -ownerEndpoint params = do - e <- runError $ start params +data ContractResponse e a = ContractSuccess a | ContractError e | ContractPending + deriving stock (Prelude.Eq, Show, Generic) + deriving anyclass (ToJSON, FromJSON) + +handleContract :: forall l a p r s. + HasEndpoint l p s + => Proxy l + -> (a -> r) + -> (p -> Contract (Last (ContractResponse Text r)) s Text a) + -> Contract (Last (ContractResponse Text r)) s Void () +handleContract _ g c = do + e <- runError $ do + p <- endpoint @l + _ <- tell $ Last $ Just ContractPending + errorHandler `handleError` c p tell $ Last $ Just $ case e of - Left err -> Left err - Right aa -> Right aa + Left err -> ContractError err + Right a -> ContractSuccess $ g a + where + errorHandler e = do + logInfo @Text ("Error submiting the transaction: " <> e) + throwError e type AaveOwnerSchema = BlockchainActions - .\/ Endpoint "start" () + .\/ Endpoint "start" [CreateParams] + +data OwnerContractState = Started Aave + deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) + +ownerEndpoints :: Contract (Last (ContractResponse Text OwnerContractState)) AaveOwnerSchema Void () +ownerEndpoints = forever $ handleContract (Proxy @"start") Started start reserves :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map AssetClass Reserve) reserves aave = ovValue <$> State.findAaveReserves aave @@ -283,29 +305,6 @@ repay aave RepayParams {..} = do _ <- awaitTxConfirmed $ txId ledgerTx pure () -data ContractResponse e a = ContractSuccess a | ContractError e | ContractPending - deriving stock (Prelude.Eq, Show, Generic) - deriving anyclass (ToJSON, FromJSON) - -handleContract :: forall l a p r s. - HasEndpoint l p s - => Proxy l - -> (a -> r) - -> (p -> Contract (Last (ContractResponse Text r)) s Text a) - -> Contract (Last (ContractResponse Text r)) s Void () -handleContract _ g c = do - e <- runError $ do - p <- endpoint @l - _ <- tell $ Last $ Just ContractPending - errorHandler `handleError` c p - tell $ Last $ Just $ case e of - Left err -> ContractError err - Right a -> ContractSuccess $ g a - where - errorHandler e = do - logInfo @Text ("Error submiting the transaction: " <> e) - throwError e - type AaveUserSchema = BlockchainActions .\/ Endpoint "deposit" DepositParams diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 59257821c..c85e49bb2 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -95,11 +95,14 @@ activateContracts = do _ <- Simulator.waitUntilFinished cidInit Simulator.logString @(Builtin AaveContracts) "Initialization finished." - let params = fmap Aave.CreateParams testAssets - cidStart <- Simulator.activateContract (Wallet 1) (AaveStart params) - aa <- flip Simulator.waitForState cidStart $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.Aave))) of - Success (Monoid.Last (Just (Right aa))) -> Just aa - _ -> Nothing + cidStart <- Simulator.activateContract (Wallet 1) AaveStart + _ <- + Simulator.callEndpointOnInstance cidStart "start" $ + fmap Aave.CreateParams testAssets + aa <- flip Simulator.waitForState cidStart $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.OwnerContractState))) of + Success (Monoid.Last (Just (ContractSuccess (Aave.Started aave)))) -> Just aave + _ -> Nothing + Simulator.logString @(Builtin AaveContracts) $ "Aave instance created: " ++ show aa cidInfo <- Simulator.activateContract (Wallet 1) $ AaveInfo aa @@ -203,7 +206,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do data AaveContracts = Init - | AaveStart [Aave.CreateParams] + | AaveStart | AaveInfo Aave.Aave | AaveUser Aave.Aave deriving (Eq, Show, Generic) @@ -222,12 +225,12 @@ handleAaveContract = Builtin.handleBuiltin getSchema getContract where getSchema = \case AaveUser _ -> Builtin.endpointsToSchemas @(Aave.AaveUserSchema .\\ BlockchainActions) AaveInfo _ -> Builtin.endpointsToSchemas @(Aave.AaveInfoSchema .\\ BlockchainActions) - AaveStart _ -> Builtin.endpointsToSchemas @(Aave.AaveOwnerSchema .\\ BlockchainActions) + AaveStart -> Builtin.endpointsToSchemas @(Aave.AaveOwnerSchema .\\ BlockchainActions) Init -> Builtin.endpointsToSchemas @Empty getContract = \case AaveInfo aave -> SomeBuiltin $ Aave.infoEndpoints aave AaveUser aave -> SomeBuiltin $ Aave.userEndpoints aave - AaveStart params -> SomeBuiltin $ Aave.ownerEndpoint params + AaveStart -> SomeBuiltin Aave.ownerEndpoints Init -> SomeBuiltin initContract handlers :: SimulatorEffectHandlers (Builtin AaveContracts) From 4f54a21c34be5a75d99003643657ef38632fa427 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 18 Jun 2021 17:55:51 +0700 Subject: [PATCH 118/169] calculate total collateral --- .../lending-pool/src/Plutus/Contracts/Core.hs | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index d582ea83c..c887397af 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -133,9 +133,26 @@ pickUserCollateralFunds :: AaveDatum -> Maybe (PubKeyHash, AssetClass) pickUserCollateralFunds (UserCollateralFundsDatum user aTokenAsset) = Just (user, aTokenAsset) pickUserCollateralFunds _ = Nothing --- TODO calculate these params in new module: --- totalCollateralInLovelace :: AssocMap.Map AssetClass Integer -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig -> Either String Integer --- totalCollateralInLovelace oracles userConfigs = 0 +-- TODO calculate these params +{-# INLINABLE totalCollateralInLovelace #-} +totalCollateralInLovelace :: + PubKeyHash + -> AssocMap.Map AssetClass Integer + -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig + -> Maybe Integer +totalCollateralInLovelace actor oracles userConfigs = + foldrM addCollateral 0 $ AssocMap.toList userConfigs + where + addCollateral :: + ((AssetClass, PubKeyHash), UserConfig) + -> Integer + -> Maybe Integer + addCollateral ((asset, user), UserConfig {..}) currentTotal + | user == actor = + (\rate -> rate * ucCollateralizedInvestment + currentTotal) <$> + AssocMap.lookup asset oracles + | otherwise = Just currentTotal + -- totalDebtInLovelace = 0 -- doesCollateralCoverNewBorrow = amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace -- where From b077656bef7cf67437d09d647722dfd0555aacf1 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 18 Jun 2021 18:11:13 +0700 Subject: [PATCH 119/169] update old user configs validators --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 11 ++++++----- .../lending-pool/src/Plutus/Contracts/Endpoints.hs | 4 +--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index c887397af..855829a48 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -167,7 +167,6 @@ instance Scripts.ValidatorTypes AaveScript where -- Main validator -- Each state field must have one or more associated actions(Redeemer types), -- produced on state update, which are then validated here --- TODO validate ucCollateralizedInvestment does not change on Deposit Withdraw Borrow Repay makeAaveValidator :: Aave -> AaveDatum -> AaveRedeemer @@ -223,14 +222,14 @@ validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId checkRedeemerConfig :: Maybe UserConfig -> UserConfig -> Bool checkRedeemerConfig oldState newState = - maybe True ((ucDebt newState ==) . ucDebt) oldState + maybe (ucDebt newState == 0) ((ucDebt newState ==) . ucDebt) oldState && + maybe (ucCollateralizedInvestment newState == 0) ((ucCollateralizedInvestment newState ==) . ucCollateralizedInvestment) oldState validateDeposit aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateDeposit: Reserves Datum change is not valid" $ checkPositiveReservesTransformation stateToken reserves ctx userConfigId validateDeposit _ _ _ _ = trace "validateDeposit: Lending Pool Datum management is not allowed" False --- TODO withdraw should check if there is enough collateral remains deposited so that health factor is >= 1.05 validateWithdraw :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool validateWithdraw aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId = -- TODO add implementation for this case @@ -273,7 +272,8 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( checkRedeemerConfig oldState newState = let debtAmount = (ucDebt newState -) $ maybe 0 ucDebt oldState disbursementAmount = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId - in debtAmount == disbursementAmount && debtAmount > 0 && disbursementAmount > 0 + in debtAmount == disbursementAmount && debtAmount > 0 && disbursementAmount > 0 && + maybe (ucCollateralizedInvestment newState == 0) ((ucCollateralizedInvestment newState ==) . ucCollateralizedInvestment) oldState validateBorrow aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateBorrow: Reserves Datum change is not valid" $ checkNegativeReservesTransformation stateToken reserves ctx userConfigId @@ -313,7 +313,8 @@ validateRepay aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(r let newDebt = ucDebt newState debtChange = ucDebt oldState - newDebt reimbursementAmount = assetClassValueOf actorSpentValue reserveId - assetClassValueOf actorRemainderValue reserveId - in debtChange == reimbursementAmount && debtChange > 0 && reimbursementAmount > 0 && newDebt >= 0 + in debtChange == reimbursementAmount && debtChange > 0 && reimbursementAmount > 0 && newDebt >= 0 && + ucCollateralizedInvestment newState == ucCollateralizedInvestment oldState validateRepay aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateRepay: Reserves Datum change is not valid" $ checkPositiveReservesTransformation stateToken reserves ctx userConfigId diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 94f65fc18..c0e0afa51 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -262,7 +262,6 @@ data RepayParams = PlutusTx.unstableMakeIsData ''RepayParams PlutusTx.makeLift ''RepayParams --- TODO should repay use collateral assets instead? -- | The user repays N amount of a specific asset to the corresponding reserve, his debt entry state is decreased by N repay :: (HasBlockchainActions s) => Aave -> RepayParams -> Contract w s Text () repay aave RepayParams {..} = do @@ -373,8 +372,6 @@ revokeCollateral aave RevokeCollateralParams {..} = do getUsersCollateral asset tx = ((> 0) . flip assetClassValueOf asset . txOutValue . txOutTxOut $ tx) && (txOutDatumHash . txOutTxOut $ tx) == Just (datumHash . Datum . PlutusTx.toData $ userDatum asset) --- TODO ? add repayWithCollateral - data ContractResponse e a = ContractSuccess a | ContractError e | ContractPending deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON) @@ -420,6 +417,7 @@ data UserContractState = | GetPubKeyBalance Value deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) +-- TODO ? add repayWithCollateral userEndpoints :: Aave -> Contract (Last (ContractResponse Text UserContractState)) AaveUserSchema Void () userEndpoints aave = forever $ handleContract (Proxy @"deposit") (const Deposited) (deposit aave) From e1fd10a207f36b83a835dd62b1e5fcde1a3aead1 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 18 Jun 2021 18:32:43 +0700 Subject: [PATCH 120/169] prohibit borrowing with the same collateral --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 855829a48..d61d56547 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -242,7 +242,6 @@ validateWithdraw aave ReserveFundsDatum ctx (reserveId, actor) = validateWithdraw _ _ _ _ = trace "validateWithdraw: Lending Pool Datum management is not allowed" False --- TODO prohibit borrowing asset which is deposited validateBorrow :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) = traceIfFalse "validateBorrow: User Configs Datum change is not valid" isValidUserConfigsTransformation @@ -273,7 +272,7 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( let debtAmount = (ucDebt newState -) $ maybe 0 ucDebt oldState disbursementAmount = assetClassValueOf actorRemainderValue reserveId - assetClassValueOf actorSpentValue reserveId in debtAmount == disbursementAmount && debtAmount > 0 && disbursementAmount > 0 && - maybe (ucCollateralizedInvestment newState == 0) ((ucCollateralizedInvestment newState ==) . ucCollateralizedInvestment) oldState + ucCollateralizedInvestment newState == 0 && maybe True ((== 0) . ucCollateralizedInvestment) oldState validateBorrow aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateBorrow: Reserves Datum change is not valid" $ checkNegativeReservesTransformation stateToken reserves ctx userConfigId From 428701e9a2109ade519c5b8b4fe1cea58e9481bd Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Fri, 18 Jun 2021 18:56:07 +0700 Subject: [PATCH 121/169] prohibit depositing without repaying --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index d61d56547..13bf35b07 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -195,7 +195,6 @@ validateStart aave (LendingPoolDatum operator) ctx = outs -> isJust $ AssocMap.lookup scriptsDatumHash $ AssocMap.fromList outs validateStart aave _ ctx = trace "validateStart: Lending Pool Datum management is not allowed" False --- TODO prohibit depositing asset which is not repaid validateDeposit :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId = traceIfFalse "validateDeposit: User Configs Datum change is not valid" isValidUserConfigsTransformation @@ -222,8 +221,8 @@ validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId checkRedeemerConfig :: Maybe UserConfig -> UserConfig -> Bool checkRedeemerConfig oldState newState = - maybe (ucDebt newState == 0) ((ucDebt newState ==) . ucDebt) oldState && - maybe (ucCollateralizedInvestment newState == 0) ((ucCollateralizedInvestment newState ==) . ucCollateralizedInvestment) oldState + maybe (ucCollateralizedInvestment newState == 0) ((ucCollateralizedInvestment newState ==) . ucCollateralizedInvestment) oldState && + ucDebt newState == 0 && maybe True ((== 0) . ucDebt) oldState validateDeposit aave (ReservesDatum stateToken reserves) ctx userConfigId = traceIfFalse "validateDeposit: Reserves Datum change is not valid" $ checkPositiveReservesTransformation stateToken reserves ctx userConfigId @@ -358,7 +357,7 @@ validateProvideCollateral aave (UserConfigsDatum stateToken userConfigs) ctx us let investmentAmount = (ucCollateralizedInvestment newState -) $ maybe 0 ucCollateralizedInvestment oldState disbursementAmount = assetClassValueOf actorSpentValue asset - assetClassValueOf actorRemainderValue asset in investmentAmount == disbursementAmount && investmentAmount > 0 && disbursementAmount > 0 && - maybe (ucDebt newState == 0) ((ucDebt newState ==) . ucDebt) oldState + ucDebt newState == 0 && maybe True ((== 0) . ucDebt) oldState validateProvideCollateral _ _ _ _ = trace "validateProvideCollateral: Lending Pool Datum management is not allowed" False From 31898fd26aabf0d0984bcac1523910eeca74b13d Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 21 Jun 2021 16:17:09 +0700 Subject: [PATCH 122/169] add collateral on chain logic --- .../lending-pool/src/Plutus/Contracts/Core.hs | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 13bf35b07..16a4713f8 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -64,6 +64,7 @@ data Reserve = Reserve PlutusTx.unstableMakeIsData ''Reserve PlutusTx.makeLift ''Reserve +Lens.makeClassy_ ''Reserve -- TODO (?) only aTokens pledged as collateral should accumulate interest -- data UserConfig = UserConfig @@ -87,6 +88,7 @@ data UserConfig = UserConfig PlutusTx.unstableMakeIsData ''UserConfig PlutusTx.makeLift ''UserConfig +Lens.makeClassy_ ''UserConfig data AaveRedeemer = StartRedeemer @@ -133,30 +135,36 @@ pickUserCollateralFunds :: AaveDatum -> Maybe (PubKeyHash, AssetClass) pickUserCollateralFunds (UserCollateralFundsDatum user aTokenAsset) = Just (user, aTokenAsset) pickUserCollateralFunds _ = Nothing --- TODO calculate these params -{-# INLINABLE totalCollateralInLovelace #-} -totalCollateralInLovelace :: +{-# INLINABLE totalDebtAndCollateralInLovelace #-} +totalDebtAndCollateralInLovelace :: PubKeyHash -> AssocMap.Map AssetClass Integer -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig - -> Maybe Integer -totalCollateralInLovelace actor oracles userConfigs = - foldrM addCollateral 0 $ AssocMap.toList userConfigs + -> Maybe UserConfig +totalDebtAndCollateralInLovelace actor oracles userConfigs = + foldrM addCollateral (UserConfig 0 0) $ AssocMap.toList userConfigs where addCollateral :: ((AssetClass, PubKeyHash), UserConfig) - -> Integer - -> Maybe Integer - addCollateral ((asset, user), UserConfig {..}) currentTotal + -> UserConfig + -> Maybe UserConfig + addCollateral ((asset, user), userConfig) currentTotal | user == actor = - (\rate -> rate * ucCollateralizedInvestment + currentTotal) <$> + (\rate -> UserConfig { + ucCollateralizedInvestment = rate * ucCollateralizedInvestment userConfig + ucCollateralizedInvestment currentTotal, + ucDebt = rate * ucDebt userConfig + ucDebt currentTotal } + ) <$> AssocMap.lookup asset oracles | otherwise = Just currentTotal --- totalDebtInLovelace = 0 --- doesCollateralCoverNewBorrow = amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace --- where --- userCollateralBalanceLovelace = totalCollateralInLovelace +{-# INLINABLE doesCollateralCoverDebt #-} +doesCollateralCoverDebt :: + PubKeyHash + -> AssocMap.Map AssetClass Integer + -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig + -> Bool +doesCollateralCoverDebt actor oracles userConfigs = maybe False (\UserConfig{..} -> ucDebt <= ucCollateralizedInvestment) $ + totalDebtAndCollateralInLovelace actor oracles userConfigs data AaveScript instance Scripts.ValidatorTypes AaveScript where From ed85093166f7fa1fab3de3bd408345d4419a858b Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 21 Jun 2021 18:42:54 +0700 Subject: [PATCH 123/169] cp oracle module --- MetaLamp/lending-pool/plutus-starter.cabal | 2 +- .../src/Plutus/Contracts/Oracle.hs | 207 ++++++++++++++++++ 2 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 7fb07a995..fed43d89a 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -23,7 +23,7 @@ maintainer: Your email library exposed-modules: - Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.State Plutus.State.Select Plutus.State.Update Plutus.Contracts.TxUtils Plutus.OutputValue Ext.Plutus.Ledger.Contexts Plutus.PAB.Simulation + Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.Oracle Plutus.Contracts.State Plutus.State.Select Plutus.State.Update Plutus.Contracts.TxUtils Plutus.OutputValue Ext.Plutus.Ledger.Contexts Plutus.PAB.Simulation build-depends: base >= 4.9 && < 5, aeson, diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs new file mode 100644 index 000000000..3a3b96746 --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs @@ -0,0 +1,207 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE DerivingStrategies #-} + +module Plutus.Contracts.Oracle + ( Oracle (..) + , OracleRedeemer (..) + , oracleTokenName + , oracleValue + , oracleAsset + , oracleInst + , oracleValidator + , oracleAddress + , OracleSchema + , OracleParams (..) + , runOracle + , findOracle + ) where + +import Control.Monad hiding (fmap) +import Data.Aeson (FromJSON, ToJSON) +import qualified Data.Map as Map +import Data.Monoid (Last (..)) +import Data.Text (Text, pack) +import GHC.Generics (Generic) +import Plutus.Contract as Contract hiding (when) +import qualified PlutusTx +import PlutusTx.Prelude hiding (Semigroup(..), unless) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import qualified Ledger.Typed.Scripts as Scripts +import Ledger.Value as Value +import Ledger.Ada as Ada +import Plutus.Contracts.Currency as Currency +import Prelude (Semigroup (..)) +import qualified Prelude as Prelude +import Schema ( ToSchema) + +data Oracle = Oracle + { oSymbol :: CurrencySymbol + , oOperator :: PubKeyHash + , oFee :: Integer + , oAsset :: AssetClass + } + deriving stock (Prelude.Eq, Prelude.Ord, Prelude.Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.makeLift ''Oracle +PlutusTx.unstableMakeIsData ''Oracle + +data OracleRedeemer = Update | Use + deriving stock (Prelude.Eq, Prelude.Ord, Prelude.Show, Generic) + +PlutusTx.unstableMakeIsData ''OracleRedeemer + +{-# INLINABLE oracleTokenName #-} +oracleTokenName :: TokenName +oracleTokenName = TokenName emptyByteString + +{-# INLINABLE oracleAsset #-} +oracleAsset :: Oracle -> AssetClass +oracleAsset oracle = AssetClass (oSymbol oracle, oracleTokenName) + +{-# INLINABLE oracleValue #-} +oracleValue :: TxOut -> (DatumHash -> Maybe Datum) -> Maybe Integer +oracleValue o f = do + dh <- txOutDatum o + Datum d <- f dh + PlutusTx.fromData d + +{-# INLINABLE mkOracleValidator #-} +mkOracleValidator :: Oracle -> Integer -> OracleRedeemer -> ScriptContext -> Bool +mkOracleValidator oracle x r ctx = + traceIfFalse "token missing from input" inputHasToken && + traceIfFalse "token missing from output" outputHasToken && + case r of + Update -> traceIfFalse "operator signature missing" (txSignedBy info $ oOperator oracle) && + traceIfFalse "invalid output datum" validOutputDatum + Use -> traceIfFalse "oracle value changed" (outputDatum == Just x) && + traceIfFalse "fees not paid" feesPaid + where + info :: TxInfo + info = scriptContextTxInfo ctx + + ownInput :: TxOut + ownInput = case findOwnInput ctx of + Nothing -> traceError "oracle input missing" + Just i -> txInInfoResolved i + + inputHasToken :: Bool + inputHasToken = assetClassValueOf (txOutValue ownInput) (oracleAsset oracle) == 1 + + ownOutput :: TxOut + ownOutput = case getContinuingOutputs ctx of + [o] -> o + _ -> traceError "expected exactly one oracle output" + + outputHasToken :: Bool + outputHasToken = assetClassValueOf (txOutValue ownOutput) (oracleAsset oracle) == 1 + + outputDatum :: Maybe Integer + outputDatum = oracleValue ownOutput (`findDatum` info) + + validOutputDatum :: Bool + validOutputDatum = isJust outputDatum + + feesPaid :: Bool + feesPaid = + let + inVal = txOutValue ownInput + outVal = txOutValue ownOutput + in + outVal `geq` (inVal <> Ada.lovelaceValueOf (oFee oracle)) + +data Oracling +instance Scripts.ValidatorTypes Oracling where + type instance DatumType Oracling = Integer + type instance RedeemerType Oracling = OracleRedeemer + +oracleInst :: Oracle -> Scripts.TypedValidator Oracling +oracleInst oracle = Scripts.mkTypedValidator @Oracling + ($$(PlutusTx.compile [|| mkOracleValidator ||]) `PlutusTx.applyCode` PlutusTx.liftCode oracle) + $$(PlutusTx.compile [|| wrap ||]) + where + wrap = Scripts.wrapValidator @Integer @OracleRedeemer + +oracleValidator :: Oracle -> Validator +oracleValidator = Scripts.validatorScript . oracleInst + +oracleAddress :: Oracle -> Ledger.Address +oracleAddress = scriptAddress . oracleValidator + +data OracleParams = OracleParams + { opFees :: Integer + , opSymbol :: CurrencySymbol + , opToken :: TokenName + } + deriving stock (Prelude.Eq, Prelude.Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +startOracle :: forall w s. HasBlockchainActions s => OracleParams -> Contract w s Text Oracle +startOracle op = do + pkh <- pubKeyHash <$> Contract.ownPubKey + osc <- mapError (pack . Prelude.show) (forgeContract pkh [(oracleTokenName, 1)] :: Contract w s CurrencyError OneShotCurrency) + let cs = Currency.currencySymbol osc + oracle = Oracle + { oSymbol = cs + , oOperator = pkh + , oFee = opFees op + , oAsset = AssetClass (opSymbol op, opToken op) + } + logInfo @Prelude.String $ "started oracle " ++ Prelude.show oracle + return oracle + +updateOracle :: forall w s. HasBlockchainActions s => Oracle -> Integer -> Contract w s Text () +updateOracle oracle x = do + m <- findOracle oracle + let c = Constraints.mustPayToTheScript x $ assetClassValue (oracleAsset oracle) 1 + case m of + Nothing -> do + ledgerTx <- submitTxConstraints (oracleInst oracle) c + awaitTxConfirmed $ txId ledgerTx + logInfo @Prelude.String $ "set initial oracle value to " ++ Prelude.show x + Just (oref, o, _) -> do + let lookups = Constraints.unspentOutputs (Map.singleton oref o) <> + Constraints.typedValidatorLookups (oracleInst oracle) <> + Constraints.otherScript (oracleValidator oracle) + tx = c <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData Update) + ledgerTx <- submitTxConstraintsWith @Oracling lookups tx + awaitTxConfirmed $ txId ledgerTx + logInfo @Prelude.String $ "updated oracle value to " ++ Prelude.show x + +findOracle :: forall w s. HasBlockchainActions s => Oracle -> Contract w s Text (Maybe (TxOutRef, TxOutTx, Integer)) +findOracle oracle = do + utxos <- Map.filter f <$> utxoAt (oracleAddress oracle) + return $ case Map.toList utxos of + [(oref, o)] -> do + x <- oracleValue (txOutTxOut o) $ \dh -> Map.lookup dh $ txData $ txOutTxTx o + return (oref, o, x) + _ -> Nothing + where + f :: TxOutTx -> Bool + f o = assetClassValueOf (txOutValue $ txOutTxOut o) (oracleAsset oracle) == 1 + +type OracleSchema = BlockchainActions .\/ Endpoint "update" Integer + +runOracle :: OracleParams -> Contract (Last Oracle) OracleSchema Text () +runOracle op = do + oracle <- startOracle op + tell $ Last $ Just oracle + go oracle + where + go :: Oracle -> Contract (Last Oracle) OracleSchema Text a + go oracle = do + x <- endpoint @"update" + updateOracle oracle x + go oracle From bd92e4beff82afdcc9bce1ece5907b71f75ff9bf Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 21 Jun 2021 18:57:39 +0700 Subject: [PATCH 124/169] add oracle into reserve --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 16a4713f8..40cf0768a 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -57,10 +57,11 @@ data Reserve = Reserve rAToken :: AssetClass, rAmount :: Integer, rLiquidityIndex :: Integer, - rCurrentStableBorrowRate :: Rational + rCurrentStableBorrowRate :: Rational, + rTrustedOracle :: (Address, AssetClass) } deriving stock (Prelude.Eq, Show, Generic) - deriving anyclass (ToJSON, FromJSON, ToSchema) + deriving anyclass (ToJSON, FromJSON) PlutusTx.unstableMakeIsData ''Reserve PlutusTx.makeLift ''Reserve @@ -81,7 +82,6 @@ data UserConfig = UserConfig { ucDebt :: Integer, ucCollateralizedInvestment :: Integer - } deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) From 558a4e3767da07a1cab22d20df57a247f98847a9 Mon Sep 17 00:00:00 2001 From: stanislav-az Date: Tue, 22 Jun 2021 00:14:05 +0700 Subject: [PATCH 125/169] add use oracle function --- .../lending-pool/src/Plutus/Contracts/Core.hs | 5 ++-- .../src/Plutus/Contracts/Oracle.hs | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 40cf0768a..956a5e6e0 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -51,6 +51,7 @@ newtype Aave = Aave PlutusTx.makeLift ''Aave deriving anyclass instance ToSchema Rational +deriving anyclass instance ToSchema (CurrencySymbol, PubKeyHash, Integer, AssetClass) data Reserve = Reserve { rCurrency :: AssetClass, -- reserve id @@ -58,10 +59,10 @@ data Reserve = Reserve rAmount :: Integer, rLiquidityIndex :: Integer, rCurrentStableBorrowRate :: Rational, - rTrustedOracle :: (Address, AssetClass) + rTrustedOracle :: (CurrencySymbol, PubKeyHash, Integer, AssetClass) } deriving stock (Prelude.Eq, Show, Generic) - deriving anyclass (ToJSON, FromJSON) + deriving anyclass (ToJSON, FromJSON, ToSchema) PlutusTx.unstableMakeIsData ''Reserve PlutusTx.makeLift ''Reserve diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs index 3a3b96746..3f1631d22 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} @@ -25,6 +27,8 @@ module Plutus.Contracts.Oracle , OracleParams (..) , runOracle , findOracle + , useOracle + , fromTuple ) where import Control.Monad hiding (fmap) @@ -45,6 +49,9 @@ import Plutus.Contracts.Currency as Currency import Prelude (Semigroup (..)) import qualified Prelude as Prelude import Schema ( ToSchema) +import qualified Plutus.State.Select as Select +import qualified Plutus.Contracts.TxUtils as TxUtils +import Plutus.OutputValue data Oracle = Oracle { oSymbol :: CurrencySymbol @@ -58,6 +65,9 @@ data Oracle = Oracle PlutusTx.makeLift ''Oracle PlutusTx.unstableMakeIsData ''Oracle +fromTuple :: (CurrencySymbol, PubKeyHash, Integer, AssetClass) -> Oracle +fromTuple (oSymbol, oOperator, oFee, oAsset) = Oracle {..} + data OracleRedeemer = Update | Use deriving stock (Prelude.Eq, Prelude.Ord, Prelude.Show, Generic) @@ -192,6 +202,26 @@ findOracle oracle = do f :: TxOutTx -> Bool f o = assetClassValueOf (txOutValue $ txOutTxOut o) (oracleAsset oracle) == 1 +useOracle :: + forall w s scriptType. + ( HasBlockchainActions s + , PlutusTx.IsData (Scripts.DatumType scriptType) + , PlutusTx.IsData (Scripts.RedeemerType scriptType) + ) + => (CurrencySymbol, PubKeyHash, Integer, AssetClass) + -> Contract w s Text (TxUtils.TxPair scriptType) +useOracle (fromTuple -> oracle) = do + oracleOutput <- Select.findOutputBy (oracleAddress oracle) oracleCoin Just + let unspent = Map.singleton (ovOutRef oracleOutput) (ovOutTx oracleOutput) + let lookups = + Constraints.otherScript (oracleValidator oracle) <> + Constraints.unspentOutputs unspent + let tx = Constraints.mustSpendScriptOutput (ovOutRef oracleOutput) (Redeemer $ PlutusTx.toData Use) <> + Constraints.mustPayToTheScript (ovValue oracleOutput) (assetClassValue oracleCoin 1) + pure $ (lookups, tx) + where + oracleCoin = oracleAsset oracle + type OracleSchema = BlockchainActions .\/ Endpoint "update" Integer runOracle :: OracleParams -> Contract (Last Oracle) OracleSchema Text () From dfd00090dba9505c843fe7bd175ca4bc3e4ad30c Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 22 Jun 2021 13:36:24 +0700 Subject: [PATCH 126/169] add oracles tx into borrow --- .../src/Plutus/Contracts/Endpoints.hs | 69 ++++++++++++------- .../src/Plutus/Contracts/State.hs | 12 ++-- .../lending-pool/src/Plutus/State/Update.hs | 16 ++--- 3 files changed, 59 insertions(+), 38 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index c0e0afa51..d3f4be22a 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -57,6 +57,7 @@ import Prelude (Monoid (..), Semigroup (..), show, subtract) import qualified Prelude import Text.Printf (printf) +import qualified Plutus.Contracts.Oracle as Oracle newtype CreateParams = CreateParams @@ -161,7 +162,7 @@ deposit aave DepositParams {..} = do forgeTx <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount let userConfigId = (rCurrency reserve, dpOnBehalfOf) - userConfigsTx <- do + (userConfigsTx, _) <- do userConfigs <- ovValue <$> State.findAaveUserConfigs aave case AssocMap.lookup userConfigId userConfigs of Nothing -> @@ -171,9 +172,9 @@ deposit aave DepositParams {..} = do userConfigId UserConfig { ucDebt = 0, ucCollateralizedInvestment = 0 } Just userConfig -> - pure mempty + pure (mempty, userConfigs) - reservesTx <- State.updateReserve aave (Core.DepositRedeemer userConfigId) dpAsset (reserve { rAmount = rAmount reserve + dpAmount }) + (reservesTx, _) <- State.updateReserve aave (Core.DepositRedeemer userConfigId) dpAsset (reserve { rAmount = rAmount reserve + dpAmount }) ledgerTx <- TxUtils.submitTxPair $ forgeTx <> reservesTx <> userConfigsTx _ <- awaitTxConfirmed $ txId ledgerTx @@ -199,7 +200,7 @@ withdraw aave WithdrawParams {..} = do burnTx <- AToken.burnATokensFrom aave reserve wpUser wpAmount - reservesTx <- State.updateReserve aave (Core.WithdrawRedeemer userConfigId) wpAsset (reserve { rAmount = rAmount reserve - wpAmount }) + (reservesTx, _) <- State.updateReserve aave (Core.WithdrawRedeemer userConfigId) wpAsset (reserve { rAmount = rAmount reserve - wpAmount }) ledgerTx <- TxUtils.submitTxPair $ burnTx <> reservesTx _ <- awaitTxConfirmed $ txId ledgerTx @@ -232,24 +233,43 @@ borrow aave BorrowParams {..} = do let disbursementTx = TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs bpOnBehalfOf payment <> TxUtils.mustPayToScript (Core.aaveInstance aave) bpOnBehalfOf Core.ReserveFundsDatum remainder - userConfigs <- ovValue <$> State.findAaveUserConfigs aave - userConfigsTx <- case AssocMap.lookup userConfigId userConfigs of - Nothing -> - State.addUserConfig - aave - (Core.BorrowRedeemer userConfigId) - userConfigId - UserConfig { ucDebt = bpAmount, ucCollateralizedInvestment = 0 } - Just userConfig -> - State.updateUserConfig aave (Core.BorrowRedeemer userConfigId) userConfigId $ - userConfig { ucDebt = ucDebt userConfig + bpAmount} - - reservesTx <- State.updateReserve aave (Core.BorrowRedeemer userConfigId) bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) - - ledgerTx <- TxUtils.submitTxPair $ disbursementTx <> reservesTx <> userConfigsTx + (userConfigsTx, userConfigs) <- do + userConfigs <- ovValue <$> State.findAaveUserConfigs aave + case AssocMap.lookup userConfigId userConfigs of + Nothing -> + State.addUserConfig + aave + (Core.BorrowRedeemer userConfigId) + userConfigId + UserConfig { ucDebt = bpAmount, ucCollateralizedInvestment = 0 } + Just userConfig -> + State.updateUserConfig aave (Core.BorrowRedeemer userConfigId) userConfigId $ + userConfig { ucDebt = ucDebt userConfig + bpAmount} + + (reservesTx, reserves) <- State.updateReserve aave (Core.BorrowRedeemer userConfigId) bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) + + oracles <- either throwError pure $ findOraclesForUser bpOnBehalfOf reserves userConfigs + oraclesTx <- mconcat <$> forM oracles Oracle.useOracle + + ledgerTx <- TxUtils.submitTxPair $ disbursementTx <> reservesTx <> userConfigsTx <> oraclesTx _ <- awaitTxConfirmed $ txId ledgerTx pure () +findOraclesForUser + :: PubKeyHash + -> AssocMap.Map AssetClass Reserve + -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig + -> Either Text [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] +findOraclesForUser actor reserves userConfigs = + foldrM findOracle [] $ AssocMap.keys userConfigs + where + findOracle (asset, user) oracles + | user == actor = + maybe (Left "findOraclesForUser: User reserve not found") + (\reserve -> Right $ rTrustedOracle reserve : oracles) $ + AssocMap.lookup asset reserves + | otherwise = Right oracles + data RepayParams = RepayParams { rpAsset :: AssetClass, @@ -270,15 +290,16 @@ repay aave RepayParams {..} = do let payment = assetClassValue (rCurrency reserve) rpAmount let reimbursementTx = TxUtils.mustPayToScript (Core.aaveInstance aave) rpOnBehalfOf Core.ReserveFundsDatum payment - userConfigs <- ovValue <$> State.findAaveUserConfigs aave let userConfigId = (rCurrency reserve, rpOnBehalfOf) - userConfigsTx <- case AssocMap.lookup userConfigId userConfigs of + (userConfigsTx, _) <- do + userConfigs <- ovValue <$> State.findAaveUserConfigs aave + case AssocMap.lookup userConfigId userConfigs of Nothing -> throwError "User does not have any debt." Just userConfig -> State.updateUserConfig aave (Core.RepayRedeemer userConfigId) userConfigId $ userConfig { ucDebt = ucDebt userConfig - rpAmount } - reservesTx <- State.updateReserve aave (Core.RepayRedeemer userConfigId) rpAsset (reserve { rAmount = rAmount reserve + rpAmount }) + (reservesTx, _) <- State.updateReserve aave (Core.RepayRedeemer userConfigId) rpAsset (reserve { rAmount = rAmount reserve + rpAmount }) ledgerTx <- TxUtils.submitTxPair $ reimbursementTx <> reservesTx <> userConfigsTx _ <- awaitTxConfirmed $ txId ledgerTx @@ -308,7 +329,7 @@ provideCollateral aave ProvideCollateralParams {..} = do <> (Prelude.mempty, mustPayToPubKey pcpOnBehalfOf remainder) let userConfigId = (rCurrency reserve, pcpOnBehalfOf) - userConfigsTx <- do + (userConfigsTx, _) <- do userConfigs <- ovValue <$> State.findAaveUserConfigs aave case AssocMap.lookup userConfigId userConfigs of Nothing -> @@ -354,7 +375,7 @@ revokeCollateral aave RevokeCollateralParams {..} = do let fundsUnlockingTx = TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs rcpOnBehalfOf payment <> TxUtils.mustPayToScript (Core.aaveInstance aave) rcpOnBehalfOf (userDatum aTokenAsset) remainder - userConfigsTx <- do + (userConfigsTx, _) <- do userConfigs <- ovValue <$> State.findAaveUserConfigs aave case AssocMap.lookup userConfigId userConfigs of Nothing -> diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index 7c18d0864..c0a68406a 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -86,7 +86,7 @@ putState aave stateHandle newState = do stateHandle newState -updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> OutputValue a -> Contract w s Text (TxUtils.TxPair AaveScript) +updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> OutputValue a -> Contract w s Text (TxUtils.TxPair AaveScript, a) updateState aave = Update.updateState (Core.aaveInstance aave) makeReserveHandle :: Aave -> (AssocMap.Map AssetClass Reserve -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map AssetClass Reserve) @@ -101,10 +101,10 @@ makeReserveHandle aave toRedeemer = putReserves :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssocMap.Map AssetClass Reserve -> Contract w s Text (TxUtils.TxPair AaveScript) putReserves aave redeemer = putState aave $ makeReserveHandle aave (const redeemer) -updateReserves :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map AssetClass Reserve) -> Contract w s Text (TxUtils.TxPair AaveScript) +updateReserves :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map AssetClass Reserve) -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map AssetClass Reserve) updateReserves aave redeemer = updateState aave $ makeReserveHandle aave (const redeemer) -updateReserve :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssetClass -> Reserve -> Contract w s Text (TxUtils.TxPair AaveScript) +updateReserve :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssetClass -> Reserve -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map AssetClass Reserve) updateReserve aave redeemer reserveId reserve = do reservesOutput <- findAaveReserves aave _ <- maybe (throwError "Update failed: reserve not found") pure $ @@ -123,17 +123,17 @@ makeUserHandle aave toRedeemer = putUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript) putUserConfigs aave redeemer = putState aave $ makeUserHandle aave (const redeemer) -updateUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -> Contract w s Text (TxUtils.TxPair AaveScript) +updateUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) updateUserConfigs aave redeemer = updateState aave $ makeUserHandle aave (const redeemer) -addUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> (AssetClass, PubKeyHash) -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript) +addUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> (AssetClass, PubKeyHash) -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) addUserConfig aave redeemer userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (pure ()) (const $ throwError "Add user config failed: config exists") $ AssocMap.lookup userConfigId (ovValue configsOutput) updateUserConfigs aave redeemer $ Prelude.fmap (AssocMap.insert userConfigId userConfig) configsOutput -updateUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> (AssetClass, PubKeyHash) -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript) +updateUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> (AssetClass, PubKeyHash) -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) updateUserConfig aave redeemer userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (throwError "Update failed: user config not found") pure $ diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/State/Update.hs index aba847325..4c03e1ac5 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/State/Update.hs @@ -109,13 +109,13 @@ updateState :: Scripts.TypedValidator scriptType -> StateHandle scriptType a -> OutputValue a -> - Contract w s Text (TxUtils.TxPair scriptType) + Contract w s Text (TxUtils.TxPair scriptType, a) updateState script StateHandle{..} output = do pkh <- pubKeyHash <$> ownPubKey - pure $ - TxUtils.mustRoundTripToScript - script - [toRedeemer Prelude.<$> output] - (toDatum . ovValue $ output) - pkh - (assetClassValue stateToken 1) + let tx = TxUtils.mustRoundTripToScript + script + [toRedeemer Prelude.<$> output] + (toDatum . ovValue $ output) + pkh + (assetClassValue stateToken 1) + pure (tx, ovValue output) From 911c7396bef7a2d59c2af1f7bfb517092e9e8b4c Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 22 Jun 2021 14:38:28 +0700 Subject: [PATCH 127/169] add oracle start at initialization --- .../lending-pool/src/Plutus/Contracts/Core.hs | 3 --- .../src/Plutus/Contracts/Endpoints.hs | 9 ++++--- .../src/Plutus/Contracts/Oracle.hs | 6 +++++ .../lending-pool/src/Plutus/PAB/Simulation.hs | 24 +++++++++++++++---- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 956a5e6e0..6031fb0bb 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -524,6 +524,3 @@ aaveAddress = Ledger.scriptAddress . aaveValidator aave :: CurrencySymbol -> Aave aave protocol = Aave (assetClass protocol aaveProtocolName) - -oneAdaInLovelace :: Integer -oneAdaInLovelace = 1000000 diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index d3f4be22a..a3f4bb81a 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -59,9 +59,11 @@ import qualified Prelude import Text.Printf (printf) import qualified Plutus.Contracts.Oracle as Oracle -newtype CreateParams = +data CreateParams = CreateParams - { cpAsset :: AssetClass } + { cpAsset :: AssetClass, + cpOracle :: Oracle.Oracle + } deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (FromJSON, ToJSON, ToSchema) @@ -74,7 +76,8 @@ createReserve aave CreateParams {..} = rAmount = 0, rAToken = AToken.makeAToken (Core.aaveHash aave) cpAsset, rLiquidityIndex = 1, - rCurrentStableBorrowRate = 11 % 10 -- TODO configure borrow rate when lending core will be ready + rCurrentStableBorrowRate = 11 % 10, -- TODO configure borrow rate when lending core will be ready + rTrustedOracle = Oracle.toTuple cpOracle } -- | Starts the Lending Pool protocol: minting pool NFTs, creating empty user configuration state and all specified liquidity reserves diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs index 3f1631d22..b8ea21fec 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs @@ -26,9 +26,12 @@ module Plutus.Contracts.Oracle , OracleSchema , OracleParams (..) , runOracle + , startOracle + , updateOracle , findOracle , useOracle , fromTuple + , toTuple ) where import Control.Monad hiding (fmap) @@ -68,6 +71,9 @@ PlutusTx.unstableMakeIsData ''Oracle fromTuple :: (CurrencySymbol, PubKeyHash, Integer, AssetClass) -> Oracle fromTuple (oSymbol, oOperator, oFee, oAsset) = Oracle {..} +toTuple :: Oracle -> (CurrencySymbol, PubKeyHash, Integer, AssetClass) +toTuple Oracle{..} = (oSymbol, oOperator, oFee, oAsset) + data OracleRedeemer = Update | Use deriving stock (Prelude.Eq, Prelude.Ord, Prelude.Show, Generic) diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 6b30dcf05..08a3c8412 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -56,6 +56,7 @@ import Plutus.V1.Ledger.Crypto (getPubKeyHash, pubKeyHash) import Prelude hiding (init) import Wallet.Emulator.Types (Wallet (..), walletPubKey) import Wallet.Types (ContractInstanceId) +import qualified Plutus.Contracts.Oracle as Oracle wallets :: [Wallet] wallets = [Wallet i | i <- [1 .. 4]] @@ -70,7 +71,7 @@ toAsset tokenName = testAssets :: [AssetClass] testAssets = fmap toAsset testCurrencyNames -initContract :: Contract (Maybe (Semigroup.Last Currency.OneShotCurrency)) Currency.CurrencySchema Currency.CurrencyError () +initContract :: Contract (Monoid.Last [Oracle.Oracle]) BlockchainActions Text () initContract = do ownPK <- pubKeyHash <$> ownPubKey let testCurrenciesValue = mconcat $ fmap (`assetClassValue` 1000) testAssets @@ -84,6 +85,16 @@ initContract = do when (pkh /= ownPK) $ do ledgerTx <- submitTxConstraintsWith @Scripts.Any lookups tx void $ awaitTxConfirmed $ txId ledgerTx + oracles <- forM testAssets $ \asset -> do + let oracleParams = Oracle.OracleParams + { opFees = 0 + , opSymbol = fst . unAssetClass $ asset + , opToken = snd . unAssetClass $ asset + } + oracle <- Oracle.startOracle oracleParams + Oracle.updateOracle oracle oneAdaInLovelace + pure oracle + tell $ Monoid.Last $ Just oracles where amount = 1000000 @@ -92,10 +103,12 @@ data ContractIDs = ContractIDs { cidUser :: Map.Map Wallet ContractInstanceId, c activateContracts :: Simulation (Builtin AaveContracts) ContractIDs activateContracts = do cidInit <- Simulator.activateContract (Wallet 1) Init - _ <- Simulator.waitUntilFinished cidInit + oracles <- flip Simulator.waitForState cidInit $ \json -> case (fromJSON json :: Result (Monoid.Last [Oracle.Oracle])) of + Success (Monoid.Last (Just res)) -> Just res + _ -> Nothing Simulator.logString @(Builtin AaveContracts) "Initialization finished." - let params = fmap Aave.CreateParams testAssets + let params = fmap (\o -> Aave.CreateParams (Oracle.oAsset o) o) oracles cidStart <- Simulator.activateContract (Wallet 1) (AaveStart params) aa <- flip Simulator.waitForState cidStart $ \json -> case (fromJSON json :: Result (Monoid.Last (Either Text Aave.Aave))) of Success (Monoid.Last (Just (Right aa))) -> Just aa @@ -159,7 +172,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do Success (Monoid.Last (Just (ContractSuccess Aave.CollateralRevoked))) -> Just () _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful revokeCollateral" - + let lenderCid = cidUser Map.! Wallet 3 let lender = pubKeyHash . walletPubKey $ Wallet 3 _ <- @@ -251,3 +264,6 @@ handlers :: SimulatorEffectHandlers (Builtin AaveContracts) handlers = Simulator.mkSimulatorHandlers @(Builtin AaveContracts) [] $ interpret handleAaveContract + +oneAdaInLovelace :: Integer +oneAdaInLovelace = 1000000 From 87043cd5d55850dd480587856bdc10939d5e8f61 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 22 Jun 2021 16:00:13 +0700 Subject: [PATCH 128/169] combine multiple scripts tx pairs --- .../src/Plutus/Contracts/Endpoints.hs | 2 +- .../src/Plutus/Contracts/Oracle.hs | 14 ++++----- .../src/Plutus/Contracts/TxUtils.hs | 30 +++++++++++++++---- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index a3f4bb81a..e45f817dd 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -254,7 +254,7 @@ borrow aave BorrowParams {..} = do oracles <- either throwError pure $ findOraclesForUser bpOnBehalfOf reserves userConfigs oraclesTx <- mconcat <$> forM oracles Oracle.useOracle - ledgerTx <- TxUtils.submitTxPair $ disbursementTx <> reservesTx <> userConfigsTx <> oraclesTx + ledgerTx <- TxUtils.submitRawUnbalancedTx $ (disbursementTx <> reservesTx <> userConfigsTx) `TxUtils.concatTxPairs` oraclesTx _ <- awaitTxConfirmed $ txId ledgerTx pure () diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs index b8ea21fec..35e8a0239 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs @@ -209,21 +209,19 @@ findOracle oracle = do f o = assetClassValueOf (txOutValue $ txOutTxOut o) (oracleAsset oracle) == 1 useOracle :: - forall w s scriptType. + forall w s. ( HasBlockchainActions s - , PlutusTx.IsData (Scripts.DatumType scriptType) - , PlutusTx.IsData (Scripts.RedeemerType scriptType) ) => (CurrencySymbol, PubKeyHash, Integer, AssetClass) - -> Contract w s Text (TxUtils.TxPair scriptType) + -> Contract w s Text (TxUtils.TxPair Oracling) useOracle (fromTuple -> oracle) = do - oracleOutput <- Select.findOutputBy (oracleAddress oracle) oracleCoin Just - let unspent = Map.singleton (ovOutRef oracleOutput) (ovOutTx oracleOutput) + (oracleRef, oracleOutTx, oracleDatum) <- findOracle oracle >>= maybe (throwError "useOracle: oracle not found") pure + let unspent = Map.singleton oracleRef oracleOutTx let lookups = Constraints.otherScript (oracleValidator oracle) <> Constraints.unspentOutputs unspent - let tx = Constraints.mustSpendScriptOutput (ovOutRef oracleOutput) (Redeemer $ PlutusTx.toData Use) <> - Constraints.mustPayToTheScript (ovValue oracleOutput) (assetClassValue oracleCoin 1) + let tx = Constraints.mustSpendScriptOutput oracleRef (Redeemer $ PlutusTx.toData Use) <> + Constraints.mustPayToTheScript oracleDatum (assetClassValue oracleCoin 1) pure $ (lookups, tx) where oracleCoin = oracleAsset oracle diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs index 8438dc0fe..10f859c53 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs @@ -9,6 +9,7 @@ module Plutus.Contracts.TxUtils where +import Control.Lens (review) import Control.Monad (void) import Data.ByteString (ByteString) import qualified Data.Map as Map @@ -40,12 +41,29 @@ import qualified Prelude type TxPair a = (Constraints.ScriptLookups a, Constraints.TxConstraints (RedeemerType a) (DatumType a)) -submitTxPair :: (AsContractError e, HasWriteTx s, PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => +type IsScriptData a = (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) + +submitTxPair :: (AsContractError e, HasWriteTx s, IsScriptData a) => TxPair a -> Contract w s e Tx submitTxPair = Prelude.uncurry submitTxConstraintsWith -mustForgeValue :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => +concatTxPairs :: (IsScriptData a, IsScriptData b) => TxPair a -> TxPair b -> Either Constraints.MkTxError Constraints.UnbalancedTx +concatTxPairs (lookupsA, txA) (lookupsB, txB) = + Constraints.mkSomeTx [Constraints.SomeLookupsAndConstraints lookupsA txA, Constraints.SomeLookupsAndConstraints lookupsB txB] + +submitRawUnbalancedTx + :: forall w s e. + ( HasWriteTx s + , AsContractError e + ) + => Either Constraints.MkTxError Constraints.UnbalancedTx + -> Contract w s e Tx +submitRawUnbalancedTx rawUnbalancedTx = do + tx <- either (throwError . review _ConstraintResolutionError) pure rawUnbalancedTx + submitUnbalancedTx tx + +mustForgeValue :: (IsScriptData a) => MonetaryPolicy -> Value -> TxPair a @@ -54,7 +72,7 @@ mustForgeValue policy value = (lookups, tx) lookups = Constraints.monetaryPolicy policy tx = Constraints.mustForgeValue value -mustPayToScript :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => +mustPayToScript :: (IsScriptData a) => TypedValidator a -> PubKeyHash -> DatumType a @@ -65,7 +83,7 @@ mustPayToScript script pkh datum value = (lookups, tx) lookups = Constraints.ownPubKeyHash pkh <> Constraints.typedValidatorLookups script tx = Constraints.mustPayToTheScript datum value -mustSpendScriptOutputs :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => +mustSpendScriptOutputs :: (IsScriptData a) => TypedValidator a -> [OutputValue (RedeemerType a)] -> TxPair a @@ -76,7 +94,7 @@ mustSpendScriptOutputs script inputs = (lookups, tx) tx = Prelude.mconcat $ fmap (\(OutputValue ref _ redeemer) -> Constraints.mustSpendScriptOutput ref (Redeemer $ PlutusTx.toData redeemer)) inputs -mustSpendFromScript :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => +mustSpendFromScript :: (IsScriptData a) => TypedValidator a -> [OutputValue (RedeemerType a)] -> PubKeyHash @@ -87,7 +105,7 @@ mustSpendFromScript script inputs pkh value = (lookups, tx) <> mustSpendScriptOu lookups = Constraints.ownPubKeyHash pkh tx = Constraints.mustPayToPubKey pkh value -mustRoundTripToScript :: (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) => +mustRoundTripToScript :: (IsScriptData a) => TypedValidator a -> [OutputValue (RedeemerType a)] -> DatumType a From d2747f1b8ed8c97ff7bd54f3b012cb3cc0e47714 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 22 Jun 2021 16:45:35 +0700 Subject: [PATCH 129/169] fix use oracle function --- .../src/Plutus/Contracts/Endpoints.hs | 2 +- .../lending-pool/src/Plutus/Contracts/Oracle.hs | 8 ++++---- .../lending-pool/src/Plutus/Contracts/TxUtils.hs | 15 --------------- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index e45f817dd..a3f4bb81a 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -254,7 +254,7 @@ borrow aave BorrowParams {..} = do oracles <- either throwError pure $ findOraclesForUser bpOnBehalfOf reserves userConfigs oraclesTx <- mconcat <$> forM oracles Oracle.useOracle - ledgerTx <- TxUtils.submitRawUnbalancedTx $ (disbursementTx <> reservesTx <> userConfigsTx) `TxUtils.concatTxPairs` oraclesTx + ledgerTx <- TxUtils.submitTxPair $ disbursementTx <> reservesTx <> userConfigsTx <> oraclesTx _ <- awaitTxConfirmed $ txId ledgerTx pure () diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs index 35e8a0239..0158e86e4 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs @@ -209,11 +209,11 @@ findOracle oracle = do f o = assetClassValueOf (txOutValue $ txOutTxOut o) (oracleAsset oracle) == 1 useOracle :: - forall w s. - ( HasBlockchainActions s + forall a w s. + ( HasBlockchainActions s, TxUtils.IsScriptData a ) => (CurrencySymbol, PubKeyHash, Integer, AssetClass) - -> Contract w s Text (TxUtils.TxPair Oracling) + -> Contract w s Text (TxUtils.TxPair a) useOracle (fromTuple -> oracle) = do (oracleRef, oracleOutTx, oracleDatum) <- findOracle oracle >>= maybe (throwError "useOracle: oracle not found") pure let unspent = Map.singleton oracleRef oracleOutTx @@ -221,7 +221,7 @@ useOracle (fromTuple -> oracle) = do Constraints.otherScript (oracleValidator oracle) <> Constraints.unspentOutputs unspent let tx = Constraints.mustSpendScriptOutput oracleRef (Redeemer $ PlutusTx.toData Use) <> - Constraints.mustPayToTheScript oracleDatum (assetClassValue oracleCoin 1) + Constraints.mustPayToOtherScript (validatorHash $ oracleValidator oracle) (Datum $ PlutusTx.toData oracleDatum) (assetClassValue oracleCoin 1) pure $ (lookups, tx) where oracleCoin = oracleAsset oracle diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs index 10f859c53..40b670a35 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs @@ -48,21 +48,6 @@ submitTxPair :: (AsContractError e, HasWriteTx s, IsScriptData a) => -> Contract w s e Tx submitTxPair = Prelude.uncurry submitTxConstraintsWith -concatTxPairs :: (IsScriptData a, IsScriptData b) => TxPair a -> TxPair b -> Either Constraints.MkTxError Constraints.UnbalancedTx -concatTxPairs (lookupsA, txA) (lookupsB, txB) = - Constraints.mkSomeTx [Constraints.SomeLookupsAndConstraints lookupsA txA, Constraints.SomeLookupsAndConstraints lookupsB txB] - -submitRawUnbalancedTx - :: forall w s e. - ( HasWriteTx s - , AsContractError e - ) - => Either Constraints.MkTxError Constraints.UnbalancedTx - -> Contract w s e Tx -submitRawUnbalancedTx rawUnbalancedTx = do - tx <- either (throwError . review _ConstraintResolutionError) pure rawUnbalancedTx - submitUnbalancedTx tx - mustForgeValue :: (IsScriptData a) => MonetaryPolicy -> Value From 8baefbcdc9c15c08575e193ae7beb81ac54d053b Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Tue, 22 Jun 2021 18:36:03 +0700 Subject: [PATCH 130/169] add oracle lookup --- MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs index 0158e86e4..dffaa32ea 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs @@ -68,9 +68,11 @@ data Oracle = Oracle PlutusTx.makeLift ''Oracle PlutusTx.unstableMakeIsData ''Oracle +{-# INLINABLE fromTuple #-} fromTuple :: (CurrencySymbol, PubKeyHash, Integer, AssetClass) -> Oracle fromTuple (oSymbol, oOperator, oFee, oAsset) = Oracle {..} +{-# INLINABLE toTuple #-} toTuple :: Oracle -> (CurrencySymbol, PubKeyHash, Integer, AssetClass) toTuple Oracle{..} = (oSymbol, oOperator, oFee, oAsset) @@ -94,6 +96,15 @@ oracleValue o f = do Datum d <- f dh PlutusTx.fromData d +{-# INLINABLE findOracleValueInTxInputs #-} +findOracleValueInTxInputs :: TxInfo -> (CurrencySymbol, PubKeyHash, Integer, AssetClass) -> Maybe Integer +findOracleValueInTxInputs txInfo tuple = oracleTxOut >>= (`oracleValue` selector) + where + inputs = txInInfoResolved <$> txInfoInputs txInfo + selector = (`findDatum` txInfo) + oracleTxOut = find (hasOracleCoin . txOutValue) inputs + hasOracleCoin val = assetClassValueOf val (oracleAsset . fromTuple $ tuple) == 1 + {-# INLINABLE mkOracleValidator #-} mkOracleValidator :: Oracle -> Integer -> OracleRedeemer -> ScriptContext -> Bool mkOracleValidator oracle x r ctx = From 7f7514b46c72c2025f2a0b1d0c07e21cfe45da62 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 23 Jun 2021 13:30:24 +0700 Subject: [PATCH 131/169] add oracle fee into use function --- MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs index dffaa32ea..7aa04d8fe 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs @@ -231,8 +231,9 @@ useOracle (fromTuple -> oracle) = do let lookups = Constraints.otherScript (oracleValidator oracle) <> Constraints.unspentOutputs unspent + let val = (assetClassValue oracleCoin 1) <> lovelaceValueOf (oFee oracle) let tx = Constraints.mustSpendScriptOutput oracleRef (Redeemer $ PlutusTx.toData Use) <> - Constraints.mustPayToOtherScript (validatorHash $ oracleValidator oracle) (Datum $ PlutusTx.toData oracleDatum) (assetClassValue oracleCoin 1) + Constraints.mustPayToOtherScript (validatorHash $ oracleValidator oracle) (Datum $ PlutusTx.toData oracleDatum) val pure $ (lookups, tx) where oracleCoin = oracleAsset oracle From 362dd1bcb8d941b5ce06a948a68f3110028f14d3 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 23 Jun 2021 14:43:58 +0700 Subject: [PATCH 132/169] add oracle consistency check --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 5 ++++- MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs | 6 ++++++ MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs | 2 -- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 6031fb0bb..d069b2f2d 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -42,6 +42,7 @@ import PlutusTx.Prelude hiding (Semigroup (..), unless) import Prelude (Semigroup (..)) import qualified Prelude +import qualified Plutus.Contracts.Oracle as Oracle newtype Aave = Aave { aaveProtocolInst :: AssetClass @@ -184,6 +185,7 @@ makeAaveValidator :: Aave makeAaveValidator aave datum StartRedeemer ctx = trace "StartRedeemer" $ validateStart aave datum ctx -- TODO ? further validators should check that ReservesDatum & UserConfigsDatum transormation happens one time -- & ReserveFundsDatum transormation happens at least one time +-- TODO ? check that reedeemers contain the same data during transformation makeAaveValidator aave datum (DepositRedeemer userConfigId) ctx = trace "DepositRedeemer" $ validateDeposit aave datum ctx userConfigId makeAaveValidator aave datum (WithdrawRedeemer userConfigId) ctx = trace "WithdrawRedeemer" $ validateWithdraw aave datum ctx userConfigId makeAaveValidator aave datum (BorrowRedeemer userConfigId) ctx = trace "BorrowRedeemer" $ validateBorrow aave datum ctx userConfigId @@ -500,7 +502,8 @@ checkReservesConsistency oldState newState = rCurrency oldState == rCurrency newState && rAToken oldState == rAToken newState && rLiquidityIndex oldState == rLiquidityIndex newState && - rCurrentStableBorrowRate oldState == rCurrentStableBorrowRate newState + rCurrentStableBorrowRate oldState == rCurrentStableBorrowRate newState && + Oracle.fromTuple (rTrustedOracle oldState) == Oracle.fromTuple (rTrustedOracle newState) aaveProtocolName :: TokenName aaveProtocolName = "Aave" diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs index 7aa04d8fe..927fd2820 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs @@ -68,6 +68,12 @@ data Oracle = Oracle PlutusTx.makeLift ''Oracle PlutusTx.unstableMakeIsData ''Oracle +instance Eq Oracle where + {-# INLINABLE (==) #-} + (Oracle oSymbol oOperator oFee oAsset) == (Oracle oSymbol' oOperator' oFee' oAsset') = + oSymbol == oSymbol' && + oOperator == oOperator' && oFee == oFee' && oAsset == oAsset' + {-# INLINABLE fromTuple #-} fromTuple :: (CurrencySymbol, PubKeyHash, Integer, AssetClass) -> Oracle fromTuple (oSymbol, oOperator, oFee, oAsset) = Oracle {..} diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs index 40b670a35..ef6d4ccbd 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs @@ -23,8 +23,6 @@ import Ledger.Typed.Scripts (DatumType, MonetaryPolicy, RedeemerType, TypedValidator) import qualified Ledger.Typed.Scripts as Scripts import Plutus.Contract -import Plutus.Contracts.Core (Aave, Reserve (..)) -import qualified Plutus.Contracts.Core as Core import qualified Plutus.Contracts.FungibleToken as FungibleToken import Plutus.OutputValue (OutputValue (..)) import Plutus.V1.Ledger.Contexts (ScriptContext, From ac4450be7e4f236988ce001bf339b25616315552 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 23 Jun 2021 16:58:42 +0700 Subject: [PATCH 133/169] wip add collateral logic --- .../lending-pool/src/Plutus/Contracts/Core.hs | 21 ++++++----- .../src/Plutus/Contracts/Endpoints.hs | 36 +++++++++---------- .../src/Plutus/Contracts/Oracle.hs | 2 ++ 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index d069b2f2d..acde10826 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE TupleSections #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} @@ -96,7 +97,7 @@ data AaveRedeemer = StartRedeemer | DepositRedeemer (AssetClass, PubKeyHash) | WithdrawRedeemer (AssetClass, PubKeyHash) - | BorrowRedeemer (AssetClass, PubKeyHash) -- TODO we need to check amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace + | BorrowRedeemer (AssetClass, PubKeyHash) [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] -- TODO we need to check amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace | RepayRedeemer (AssetClass, PubKeyHash) | ProvideCollateralRedeemer (AssetClass, PubKeyHash) | RevokeCollateralRedeemer (AssetClass, PubKeyHash) AssetClass -- TODO we need to check amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace @@ -188,7 +189,7 @@ makeAaveValidator aave datum StartRedeemer ctx = trace "StartRedeemer" $ vali -- TODO ? check that reedeemers contain the same data during transformation makeAaveValidator aave datum (DepositRedeemer userConfigId) ctx = trace "DepositRedeemer" $ validateDeposit aave datum ctx userConfigId makeAaveValidator aave datum (WithdrawRedeemer userConfigId) ctx = trace "WithdrawRedeemer" $ validateWithdraw aave datum ctx userConfigId -makeAaveValidator aave datum (BorrowRedeemer userConfigId) ctx = trace "BorrowRedeemer" $ validateBorrow aave datum ctx userConfigId +makeAaveValidator aave datum (BorrowRedeemer userConfigId oracles) ctx = trace "BorrowRedeemer" $ validateBorrow aave datum ctx userConfigId oracles makeAaveValidator aave datum (RepayRedeemer userConfigId) ctx = trace "RepayRedeemer" $ validateRepay aave datum ctx userConfigId makeAaveValidator aave datum (ProvideCollateralRedeemer userConfigId) ctx = trace "ProvideCollateralRedeemer" $ validateProvideCollateral aave datum ctx userConfigId makeAaveValidator aave datum (RevokeCollateralRedeemer userConfigId aTokenAsset) ctx = trace "RevokeCollateralRedeemer" $ validateRevokeCollateral aave datum ctx userConfigId aTokenAsset @@ -252,8 +253,8 @@ validateWithdraw aave ReserveFundsDatum ctx (reserveId, actor) = validateWithdraw _ _ _ _ = trace "validateWithdraw: Lending Pool Datum management is not allowed" False -validateBorrow :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool -validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) = +validateBorrow :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] -> Bool +validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) oracles = traceIfFalse "validateBorrow: User Configs Datum change is not valid" isValidUserConfigsTransformation where txInfo = scriptContextTxInfo ctx @@ -269,13 +270,16 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( actorSpentValue = valueSpentFrom txInfo actor actorRemainderValue = valuePaidTo txInfo actor + oracleValues = maybe (traceError "validateBorrow: Oracles have not been provided") AssocMap.fromList $ + foldrM (\o@(_, _, _, oAsset) acc -> fmap ((: acc) . (oAsset, )) (Oracle.findOracleValueInTxInputs txInfo o)) [] oracles + isValidUserConfigsTransformation :: Bool isValidUserConfigsTransformation = maybe False checkUserConfigs userConfigsOutputDatum checkUserConfigs :: (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -> Bool checkUserConfigs (newStateToken, newUserConfigs) = - newStateToken == stateToken && + newStateToken == stateToken && doesCollateralCoverDebt actor oracleValues newUserConfigs && maybe False (checkRedeemerConfig $ AssocMap.lookup userConfigId userConfigs) (AssocMap.lookup userConfigId newUserConfigs) checkRedeemerConfig :: Maybe UserConfig -> UserConfig -> Bool checkRedeemerConfig oldState newState = @@ -284,13 +288,14 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( in debtAmount == disbursementAmount && debtAmount > 0 && disbursementAmount > 0 && ucCollateralizedInvestment newState == 0 && maybe True ((== 0) . ucCollateralizedInvestment) oldState -validateBorrow aave (ReservesDatum stateToken reserves) ctx userConfigId = +-- TODO validate that oracles are trusted +validateBorrow aave (ReservesDatum stateToken reserves) ctx userConfigId oracles = traceIfFalse "validateBorrow: Reserves Datum change is not valid" $ checkNegativeReservesTransformation stateToken reserves ctx userConfigId -validateBorrow aave ReserveFundsDatum ctx (reserveId, actor) = +validateBorrow aave ReserveFundsDatum ctx (reserveId, actor) oracles = traceIfFalse "validateBorrow: Reserve Funds Datum change is not valid" $ checkNegativeFundsTransformation ctx reserveId actor -validateBorrow _ _ _ _ = trace "validateBorrow: Lending Pool Datum management is not allowed" False +validateBorrow _ _ _ _ _ = trace "validateBorrow: Lending Pool Datum management is not allowed" False validateRepay :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool validateRepay aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) = diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index a3f4bb81a..0170b0edd 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -18,7 +18,7 @@ module Plutus.Contracts.Endpoints where -import Control.Monad hiding (fmap) +import Control.Monad (forever, void, forM) import qualified Data.ByteString as BS import qualified Data.Map as Map import Data.Monoid (Last (..)) @@ -224,34 +224,34 @@ PlutusTx.makeLift ''BorrowParams -- | The user borrows N amount of a needed asset from the corresponding reserve, his debt entry state is encreased by N borrow :: (HasBlockchainActions s) => Aave -> BorrowParams -> Contract w s Text () borrow aave BorrowParams {..} = do - reserve <- State.findAaveReserve aave bpAsset + reserves <- ovValue <$> State.findAaveReserves aave + reserve <- maybe (throwError "Reserve not found") pure $ AssocMap.lookup bpAsset reserves + let userConfigId = (rCurrency reserve, bpOnBehalfOf) + userConfigs <- do + userConfigs <- ovValue <$> State.findAaveUserConfigs aave + pure $ case AssocMap.lookup userConfigId userConfigs of + Nothing -> + AssocMap.insert userConfigId UserConfig { ucDebt = bpAmount, ucCollateralizedInvestment = 0 } userConfigs + Just userConfig -> + AssocMap.insert userConfigId userConfig { ucDebt = ucDebt userConfig + bpAmount} userConfigs + oracles <- either throwError pure $ findOraclesForUser bpOnBehalfOf reserves userConfigs + let redeemer = Core.BorrowRedeemer userConfigId oracles utxos <- Map.filter ((> 0) . flip assetClassValueOf bpAsset . txOutValue . txOutTxOut) <$> utxoAt (Core.aaveAddress aave) - let userConfigId = (rCurrency reserve, bpOnBehalfOf) - let inputs = (\(ref, tx) -> OutputValue ref tx (Core.BorrowRedeemer userConfigId)) <$> Map.toList utxos + let inputs = (\(ref, tx) -> OutputValue ref tx redeemer) <$> Map.toList utxos let payment = assetClassValue (rCurrency reserve) bpAmount let remainder = assetClassValue (rCurrency reserve) (rAmount reserve - bpAmount) let disbursementTx = TxUtils.mustSpendFromScript (Core.aaveInstance aave) inputs bpOnBehalfOf payment <> TxUtils.mustPayToScript (Core.aaveInstance aave) bpOnBehalfOf Core.ReserveFundsDatum remainder - (userConfigsTx, userConfigs) <- do - userConfigs <- ovValue <$> State.findAaveUserConfigs aave - case AssocMap.lookup userConfigId userConfigs of - Nothing -> - State.addUserConfig - aave - (Core.BorrowRedeemer userConfigId) - userConfigId - UserConfig { ucDebt = bpAmount, ucCollateralizedInvestment = 0 } - Just userConfig -> - State.updateUserConfig aave (Core.BorrowRedeemer userConfigId) userConfigId $ - userConfig { ucDebt = ucDebt userConfig + bpAmount} + (userConfigsTx, _) <- do + configsOutput <- State.findAaveUserConfigs aave + State.updateUserConfigs aave redeemer $ userConfigs Prelude.<$ configsOutput - (reservesTx, reserves) <- State.updateReserve aave (Core.BorrowRedeemer userConfigId) bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) + (reservesTx, reserves) <- State.updateReserve aave redeemer bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) - oracles <- either throwError pure $ findOraclesForUser bpOnBehalfOf reserves userConfigs oraclesTx <- mconcat <$> forM oracles Oracle.useOracle ledgerTx <- TxUtils.submitTxPair $ disbursementTx <> reservesTx <> userConfigsTx <> oraclesTx diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs index 927fd2820..2e2eccd79 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs @@ -13,6 +13,7 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE DerivingStrategies #-} +{-# OPTIONS_GHC -fno-specialise #-} module Plutus.Contracts.Oracle ( Oracle (..) @@ -32,6 +33,7 @@ module Plutus.Contracts.Oracle , useOracle , fromTuple , toTuple + , findOracleValueInTxInputs ) where import Control.Monad hiding (fmap) From 3ebcf1c79c4cb6ba0520d35857672da96cf1566b Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 23 Jun 2021 17:46:15 +0700 Subject: [PATCH 134/169] fix oracle values error throwing --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index acde10826..affd637a4 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -270,8 +270,10 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( actorSpentValue = valueSpentFrom txInfo actor actorRemainderValue = valuePaidTo txInfo actor - oracleValues = maybe (traceError "validateBorrow: Oracles have not been provided") AssocMap.fromList $ - foldrM (\o@(_, _, _, oAsset) acc -> fmap ((: acc) . (oAsset, )) (Oracle.findOracleValueInTxInputs txInfo o)) [] oracles + oracleValues = + case foldrM (\o@(_, _, _, oAsset) acc -> fmap ((: acc) . (oAsset, )) (Oracle.findOracleValueInTxInputs txInfo o)) [] oracles of + Just vs -> AssocMap.fromList vs + _ -> traceError "validateBorrow: Oracles have not been provided" isValidUserConfigsTransformation :: Bool isValidUserConfigsTransformation = From a4f3d25560d4c7999062fc877430a768f088553d Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Wed, 23 Jun 2021 18:28:23 +0700 Subject: [PATCH 135/169] add trusted oracles validation --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index affd637a4..0efb61215 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -97,7 +97,7 @@ data AaveRedeemer = StartRedeemer | DepositRedeemer (AssetClass, PubKeyHash) | WithdrawRedeemer (AssetClass, PubKeyHash) - | BorrowRedeemer (AssetClass, PubKeyHash) [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] -- TODO we need to check amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace + | BorrowRedeemer (AssetClass, PubKeyHash) [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] | RepayRedeemer (AssetClass, PubKeyHash) | ProvideCollateralRedeemer (AssetClass, PubKeyHash) | RevokeCollateralRedeemer (AssetClass, PubKeyHash) AssetClass -- TODO we need to check amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace @@ -169,6 +169,15 @@ doesCollateralCoverDebt :: doesCollateralCoverDebt actor oracles userConfigs = maybe False (\UserConfig{..} -> ucDebt <= ucCollateralizedInvestment) $ totalDebtAndCollateralInLovelace actor oracles userConfigs +{-# INLINABLE areOraclesTrusted #-} +areOraclesTrusted :: [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] + -> AssocMap.Map AssetClass Reserve + -> Bool +areOraclesTrusted oracles reserves = all checkOracle oracles + where + checkOracle o = let oracle = Oracle.fromTuple o in + Just oracle == (Oracle.fromTuple . rTrustedOracle <$> AssocMap.lookup (Oracle.oAsset oracle) reserves) + data AaveScript instance Scripts.ValidatorTypes AaveScript where type instance RedeemerType AaveScript = AaveRedeemer @@ -290,9 +299,8 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( in debtAmount == disbursementAmount && debtAmount > 0 && disbursementAmount > 0 && ucCollateralizedInvestment newState == 0 && maybe True ((== 0) . ucCollateralizedInvestment) oldState --- TODO validate that oracles are trusted validateBorrow aave (ReservesDatum stateToken reserves) ctx userConfigId oracles = - traceIfFalse "validateBorrow: Reserves Datum change is not valid" $ checkNegativeReservesTransformation stateToken reserves ctx userConfigId + traceIfFalse "validateBorrow: Reserves Datum change is not valid" $ checkNegativeReservesTransformation stateToken reserves ctx userConfigId && areOraclesTrusted oracles reserves validateBorrow aave ReserveFundsDatum ctx (reserveId, actor) oracles = traceIfFalse "validateBorrow: Reserve Funds Datum change is not valid" $ checkNegativeFundsTransformation ctx reserveId actor From 67297d2759d05754b4eb03bcc4e0deb54485ed2e Mon Sep 17 00:00:00 2001 From: megakaban Date: Wed, 23 Jun 2021 18:40:18 +0700 Subject: [PATCH 136/169] Add baisc test cases for deposit/withdraw --- .../lending-pool/generate-purs/AaveTypes.hs | 11 +- MetaLamp/lending-pool/plutus-starter.cabal | 43 +++++ .../src/Plutus/Contracts/Endpoints.hs | 14 +- .../lending-pool/src/Plutus/PAB/Simulation.hs | 53 ++++--- MetaLamp/lending-pool/test/Main.hs | 18 +++ MetaLamp/lending-pool/test/Spec/Mock.hs | 62 ++++++++ MetaLamp/lending-pool/test/Spec/Start.hs | 50 ++++++ MetaLamp/lending-pool/test/Spec/User.hs | 147 ++++++++++++++++++ MetaLamp/lending-pool/test/Spec/Utils.hs | 69 ++++++++ 9 files changed, 429 insertions(+), 38 deletions(-) create mode 100644 MetaLamp/lending-pool/test/Main.hs create mode 100644 MetaLamp/lending-pool/test/Spec/Mock.hs create mode 100644 MetaLamp/lending-pool/test/Spec/Start.hs create mode 100644 MetaLamp/lending-pool/test/Spec/User.hs create mode 100644 MetaLamp/lending-pool/test/Spec/Utils.hs diff --git a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs index c5c533fef..ca2ee4469 100644 --- a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs +++ b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs @@ -11,15 +11,6 @@ module AaveTypes where -import Language.PureScript.Bridge (BridgePart, Language (Haskell), SumType, - TypeInfo (TypeInfo), buildBridge, equal, genericShow, - haskType, mkSumType, order, typeModule, typeName, - writePSTypesWith, (^==), PSType, psTypeParameters) -import Data.Proxy (Proxy (Proxy)) -import qualified Plutus.Contracts.Core as Aave -import qualified Plutus.Contracts.Endpoints as Aave -import Plutus.PAB.Simulation (AaveContracts(..)) -import Language.PureScript.Bridge.TypeParameters (A, E) import Control.Monad.Reader (MonadReader) import Data.Proxy (Proxy (Proxy)) import Language.PureScript.Bridge (BridgePart, @@ -36,7 +27,7 @@ import Language.PureScript.Bridge (BridgePart, writePSTypesWith, (^==)) import Language.PureScript.Bridge.Builder (BridgeData) -import Language.PureScript.Bridge.TypeParameters (A) +import Language.PureScript.Bridge.TypeParameters (A, E) import qualified PSGenerator.Common import qualified Plutus.Contracts.Core as Aave import qualified Plutus.Contracts.Endpoints as Aave diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 7fb07a995..2256f0430 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -96,3 +96,46 @@ executable generate-purs plutus-use-cases, plutus-ledger, plutus-tx + +test-suite test + type: exitcode-stdio-1.0 + main-is: Main.hs + hs-source-dirs: test + other-modules: + Spec.Start Spec.Mock Spec.User Spec.Utils + default-language: Haskell2010 + ghc-options: -Wall -Wnoncanonical-monad-instances + -Wincomplete-uni-patterns -Wincomplete-record-updates + -Wredundant-constraints -Widentities -rtsopts + -- See Plutus Tx readme + -fobject-code -fno-ignore-interface-pragmas -fno-omit-interface-pragmas + build-depends: + plutus-core -any, + plutus-tx -any, + plutus-contract -any, + plutus-ledger -any, + plutus-starter, + plutus-ledger-api, + plutus-tx-plugin + build-depends: + base >=4.9 && <5, + aeson -any, + bytestring -any, + containers -any, + data-default -any, + freer-extras -any, + hedgehog -any, + prettyprinter -any, + tasty -any, + tasty-hunit -any, + tasty-hedgehog >=0.2.0.0, + tasty-golden -any, + tasty-quickcheck -any, + text -any, + lens -any, + mtl -any, + row-types -any, + QuickCheck -any, + freer-simple -any, + foldl -any, + streaming -any diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 3a9a84ae3..9f41149e2 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -18,6 +18,7 @@ module Plutus.Contracts.Endpoints where +import qualified Control.Lens as Lens import Control.Monad hiding (fmap) import qualified Data.ByteString as BS import qualified Data.Map as Map @@ -77,11 +78,16 @@ createReserve aave CreateParams {..} = } start :: HasBlockchainActions s => [CreateParams] -> Contract w s Text Aave -start params = do +start = start' $ do pkh <- pubKeyHash <$> ownPubKey - aaveToken <- fmap Currency.currencySymbol $ + fmap Currency.currencySymbol $ mapError (pack . show @Currency.CurrencyError) $ Currency.forgeContract pkh [(Core.aaveProtocolName, 1)] + +start' :: HasBlockchainActions s => Contract w s Text CurrencySymbol -> [CreateParams] -> Contract w s Text Aave +start' getAaveToken params = do + aaveToken <- getAaveToken + pkh <- pubKeyHash <$> ownPubKey let aave = Core.aave aaveToken payment = assetClassValue (Core.aaveProtocolInst aave) 1 let aaveTokenTx = TxUtils.mustPayToScript (Core.aaveInstance aave) pkh (Core.LendingPoolDatum pkh) payment @@ -129,7 +135,7 @@ type AaveOwnerSchema = data OwnerContractState = Started Aave deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) - + ownerEndpoints :: Contract (Last (ContractResponse Text OwnerContractState)) AaveOwnerSchema Void () ownerEndpoints = forever $ handleContract (Proxy @"start") Started start @@ -323,6 +329,8 @@ data UserContractState = | GetPubKeyBalance Value deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) +Lens.makeClassyPrisms ''UserContractState + userEndpoints :: Aave -> Contract (Last (ContractResponse Text UserContractState)) AaveUserSchema Void () userEndpoints aave = forever $ handleContract (Proxy @"deposit") (const Deposited) (deposit aave) diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index c85e49bb2..57eb7f69e 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -39,8 +39,8 @@ import Ledger.Value as Value import Plutus.Contract hiding (when) import qualified Plutus.Contracts.Core as Aave import Plutus.Contracts.Currency as Currency +import Plutus.Contracts.Endpoints (ContractResponse (..)) import qualified Plutus.Contracts.Endpoints as Aave -import Plutus.Contracts.Endpoints (ContractResponse(..)) import qualified Plutus.Contracts.FungibleToken as FungibleToken import Plutus.PAB.Effects.Contract (ContractEffect (..)) import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), @@ -57,25 +57,28 @@ import Prelude hiding (init) import Wallet.Emulator.Types (Wallet (..), walletPubKey) import Wallet.Types (ContractInstanceId) -wallets :: [Wallet] -wallets = [Wallet i | i <- [1 .. 4]] +ownerWallet :: Wallet +ownerWallet = Wallet 1 -testCurrencyNames :: [TokenName] -testCurrencyNames = ["MOGUS", "USD"] +userWallets :: [Wallet] +userWallets = [Wallet i | i <- [2 .. 4]] + +testAssets :: [AssetClass] +testAssets = fmap toAsset ["MOGUS", "USD"] toAsset :: TokenName -> AssetClass toAsset tokenName = assetClass (scriptCurrencySymbol . FungibleToken.makeLiquidityPolicy $ tokenName) tokenName -testAssets :: [AssetClass] -testAssets = fmap toAsset testCurrencyNames - -initContract :: Contract (Maybe (Semigroup.Last Currency.OneShotCurrency)) Currency.CurrencySchema Currency.CurrencyError () -initContract = do +initContract :: + [Wallet] -> + [AssetClass] -> + Contract (Maybe (Semigroup.Last Currency.OneShotCurrency)) Currency.CurrencySchema Currency.CurrencyError () +initContract wallets assets = do ownPK <- pubKeyHash <$> ownPubKey - let testCurrenciesValue = mconcat $ fmap (`assetClassValue` 1000) testAssets + let testCurrenciesValue = mconcat $ fmap (`assetClassValue` 1000) assets policyLookups = mconcat $ - fmap (Constraints.monetaryPolicy . FungibleToken.makeLiquidityPolicy . Prelude.snd . unAssetClass) testAssets + fmap (Constraints.monetaryPolicy . FungibleToken.makeLiquidityPolicy . Prelude.snd . unAssetClass) assets adaValue = lovelaceValueOf amount forM_ wallets $ \w -> do let pkh = pubKeyHash $ walletPubKey w @@ -91,11 +94,11 @@ data ContractIDs = ContractIDs { cidUser :: Map.Map Wallet ContractInstanceId, c activateContracts :: Simulation (Builtin AaveContracts) ContractIDs activateContracts = do - cidInit <- Simulator.activateContract (Wallet 1) Init + cidInit <- Simulator.activateContract ownerWallet Init _ <- Simulator.waitUntilFinished cidInit Simulator.logString @(Builtin AaveContracts) "Initialization finished." - cidStart <- Simulator.activateContract (Wallet 1) AaveStart + cidStart <- Simulator.activateContract ownerWallet AaveStart _ <- Simulator.callEndpointOnInstance cidStart "start" $ fmap Aave.CreateParams testAssets @@ -105,9 +108,9 @@ activateContracts = do Simulator.logString @(Builtin AaveContracts) $ "Aave instance created: " ++ show aa - cidInfo <- Simulator.activateContract (Wallet 1) $ AaveInfo aa + cidInfo <- Simulator.activateContract ownerWallet $ AaveInfo aa - cidUser <- fmap Map.fromList $ forM (tail wallets) $ \w -> do + cidUser <- fmap Map.fromList $ forM userWallets $ \w -> do cid <- Simulator.activateContract w $ AaveUser aa Simulator.logString @(Builtin AaveContracts) $ "Aave user contract started for " ++ show w return (w, cid) @@ -135,7 +138,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do Aave.DepositParams { Aave.dpAsset = head testAssets, Aave.dpOnBehalfOf = sender, Aave.dpAmount = 100 } flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of Success (Monoid.Last (Just (ContractSuccess Aave.Deposited))) -> Just () - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful deposit" _ <- @@ -143,7 +146,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do Aave.WithdrawParams { Aave.wpAsset = head testAssets, Aave.wpUser = sender, Aave.wpAmount = 30 } flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of Success (Monoid.Last (Just (ContractSuccess Aave.Withdrawn))) -> Just () - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful withdraw" let lenderCid = cidUser Map.! Wallet 3 @@ -153,7 +156,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do Aave.DepositParams { Aave.dpAsset = testAssets !! 1, Aave.dpOnBehalfOf = lender, Aave.dpAmount = 200 } flip Simulator.waitForState lenderCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of Success (Monoid.Last (Just (ContractSuccess Aave.Deposited))) -> Just () - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful deposit from lender" _ <- @@ -161,7 +164,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do Aave.BorrowParams { Aave.bpAsset = testAssets !! 1, Aave.bpAmount = 35, Aave.bpOnBehalfOf = sender } flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of Success (Monoid.Last (Just (ContractSuccess Aave.Borrowed))) -> Just () - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful borrow" _ <- @@ -169,7 +172,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do Aave.RepayParams { Aave.rpAsset = testAssets !! 1, Aave.rpAmount = 25, Aave.rpOnBehalfOf = sender } flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of Success (Monoid.Last (Just (ContractSuccess Aave.Repaid))) -> Just () - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful repay" _ <- Simulator.callEndpointOnInstance cidInfo "fundsAt" sender @@ -228,10 +231,10 @@ handleAaveContract = Builtin.handleBuiltin getSchema getContract where AaveStart -> Builtin.endpointsToSchemas @(Aave.AaveOwnerSchema .\\ BlockchainActions) Init -> Builtin.endpointsToSchemas @Empty getContract = \case - AaveInfo aave -> SomeBuiltin $ Aave.infoEndpoints aave - AaveUser aave -> SomeBuiltin $ Aave.userEndpoints aave - AaveStart -> SomeBuiltin Aave.ownerEndpoints - Init -> SomeBuiltin initContract + AaveInfo aave -> SomeBuiltin $ Aave.infoEndpoints aave + AaveUser aave -> SomeBuiltin $ Aave.userEndpoints aave + AaveStart -> SomeBuiltin Aave.ownerEndpoints + Init -> SomeBuiltin $ initContract userWallets testAssets handlers :: SimulatorEffectHandlers (Builtin AaveContracts) handlers = diff --git a/MetaLamp/lending-pool/test/Main.hs b/MetaLamp/lending-pool/test/Main.hs new file mode 100644 index 000000000..db6081643 --- /dev/null +++ b/MetaLamp/lending-pool/test/Main.hs @@ -0,0 +1,18 @@ +module Main(main) where + +import qualified Spec.Start +import qualified Spec.User +import Test.Tasty +import Test.Tasty.Hedgehog (HedgehogTestLimit (..)) + +main :: IO () +main = defaultMain tests + +limit :: HedgehogTestLimit +limit = HedgehogTestLimit (Just 5) + +tests :: TestTree +tests = localOption limit $ testGroup "lending pool tests" [ + Spec.Start.tests, + Spec.User.tests + ] diff --git a/MetaLamp/lending-pool/test/Spec/Mock.hs b/MetaLamp/lending-pool/test/Spec/Mock.hs new file mode 100644 index 000000000..11393f612 --- /dev/null +++ b/MetaLamp/lending-pool/test/Spec/Mock.hs @@ -0,0 +1,62 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} + +module Spec.Mock where + +import Control.Monad (void) +import Data.Text (Text) +import Data.Void (Void) +import qualified Ledger +import qualified Ledger.Constraints as Constraints +import qualified Ledger.Scripts as UntypedScripts +import Ledger.Typed.Scripts (MonetaryPolicy) +import qualified Ledger.Typed.Scripts as Scripts +import Plutus.Contract +import qualified Plutus.Contracts.Core as Aave +import qualified Plutus.Contracts.Endpoints as Aave +import qualified Plutus.Contracts.TxUtils as TxUtils +import Plutus.V1.Ledger.Contexts (ScriptContext) +import qualified Plutus.V1.Ledger.Scripts as Scripts +import Plutus.V1.Ledger.Value (CurrencySymbol, TokenName, Value, + assetClass, assetClassValue) +import qualified PlutusTx +import PlutusTx.Prelude +import qualified Prelude + +{-# INLINABLE validator #-} +validator :: TokenName -> ScriptContext -> Bool +validator _ _ = True + +makeLiquidityPolicy :: TokenName -> MonetaryPolicy +makeLiquidityPolicy tokenName = Scripts.mkMonetaryPolicyScript $ + $$(PlutusTx.compile [|| Scripts.wrapMonetaryPolicy . validator ||]) + `PlutusTx.applyCode` + PlutusTx.liftCode tokenName + +aavePolicy :: MonetaryPolicy +aavePolicy = makeLiquidityPolicy Aave.aaveProtocolName + +aaveSymbol :: CurrencySymbol +aaveSymbol = Ledger.scriptCurrencySymbol aavePolicy + +aaveAddress :: Ledger.Address +aaveAddress = Aave.aaveAddress . Aave.aave $ aaveSymbol + +aave :: Aave.Aave +aave = Aave.aave aaveSymbol + +aaveHash :: Ledger.ValidatorHash +aaveHash = Aave.aaveHash aave + +start :: [Aave.CreateParams] -> Contract () Aave.AaveOwnerSchema Text Aave.Aave +start = Aave.start' $ do + pkh <- Ledger.pubKeyHash <$> ownPubKey + let forgeValue = assetClassValue (assetClass aaveSymbol Aave.aaveProtocolName) 1 + ledgerTx <- + TxUtils.submitTxPair $ + TxUtils.mustForgeValue @Void aavePolicy forgeValue + Prelude.<> (Prelude.mempty, Constraints.mustPayToPubKey pkh forgeValue) + void $ awaitTxConfirmed $ Ledger.txId ledgerTx + pure aaveSymbol diff --git a/MetaLamp/lending-pool/test/Spec/Start.hs b/MetaLamp/lending-pool/test/Spec/Start.hs new file mode 100644 index 000000000..72649ada4 --- /dev/null +++ b/MetaLamp/lending-pool/test/Spec/Start.hs @@ -0,0 +1,50 @@ +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE TypeApplications #-} + +module Spec.Start where + +import Control.Monad (void) +import Data.Text (Text) +import Plutus.Contract +import Plutus.Contract.Test +import qualified Plutus.Contracts.Core as Aave +import qualified Plutus.Contracts.Endpoints as Aave +import Plutus.PAB.Simulation (testAssets) +import qualified Plutus.Trace.Emulator as Trace +import qualified PlutusTx.AssocMap as AssocMap +import qualified Spec.Mock as Mock +import qualified Spec.Utils as TestUtils +import Test.Tasty + +startParams :: [Aave.CreateParams] +startParams = fmap Aave.CreateParams testAssets + +startContract :: Contract () Aave.AaveOwnerSchema Text () +startContract = void $ Mock.start startParams + +ownerWallet :: Wallet +ownerWallet = Wallet 1 + +startTrace :: Trace.EmulatorTrace () +startTrace = do + _ <- Trace.activateContractWallet ownerWallet startContract + _ <- Trace.waitNSlots 5 + pure () + +initSuccess :: [Aave.AaveDatum] -> Bool +initSuccess = TestUtils.allSatisfy . fmap TestUtils.one $ [hasReserves, hasUsers, hasOperator] + where + hasOperator (Aave.LendingPoolDatum _) = True + hasOperator _ = False + hasReserves (Aave.ReservesDatum _ reserves) = + reserves == AssocMap.fromList (fmap (\params -> (Aave.cpAsset params, Aave.createReserve Mock.aave params)) startParams) + hasReserves _ = False + hasUsers (Aave.UserConfigsDatum _ users) = users == AssocMap.empty + hasUsers _ = False + +tests :: TestTree +tests = testGroup "ownerContract" [checkPredicate + "starts a new lending pool" + (assertDone startContract (Trace.walletInstanceTag ownerWallet) (const True) "start contract not done" + .&&. TestUtils.datumsAtAddress Mock.aaveAddress initSuccess) + startTrace] diff --git a/MetaLamp/lending-pool/test/Spec/User.hs b/MetaLamp/lending-pool/test/Spec/User.hs new file mode 100644 index 000000000..b4ed8d389 --- /dev/null +++ b/MetaLamp/lending-pool/test/Spec/User.hs @@ -0,0 +1,147 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeApplications #-} + +module Spec.User where + +import Control.Lens ((^?)) +import Control.Monad (forM, void) +import Control.Monad.Freer.Error (throwError) +import qualified Data.Map as Map +import Data.Monoid (Last (..)) +import Data.Text (Text) +import Data.Void (Void) +import qualified Ledger +import qualified Ledger.Ada as Ada +import Ledger.Constraints (ScriptLookups (..)) +import qualified Ledger.Constraints as Constraints +import Ledger.Scripts (unitRedeemer) +import Ledger.Typed.Scripts as Scripts +import Plutus.Contract hiding (throwError) +import Plutus.Contract.Test +import qualified Plutus.Contracts.AToken as AToken +import qualified Plutus.Contracts.Core as Aave +import Plutus.Contracts.Endpoints (ContractResponse (..)) +import qualified Plutus.Contracts.Endpoints as Aave +import qualified Plutus.Contracts.State as Aave +import Plutus.PAB.Simulation (initContract, toAsset) +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Ada (lovelaceValueOf) +import Plutus.V1.Ledger.Value (AssetClass, TokenName, Value, + assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap +import qualified PlutusTx.Prelude as PlutusTx +import qualified Spec.Mock as Mock +import qualified Spec.Utils as TestUtils +import Test.Tasty + +testAssets :: [AssetClass] +testAssets = fmap toAsset ["MOGUS", "USD"] + +mogus :: AssetClass +mogus = Prelude.head testAssets + +amogus :: AssetClass +amogus = AToken.makeAToken Mock.aaveHash mogus + +usd :: AssetClass +usd = testAssets Prelude.!! 1 + +startParams = fmap Aave.CreateParams testAssets + +startContract :: Contract () Aave.AaveOwnerSchema Text () +startContract = void $ Mock.start startParams + +userContract :: Contract (Last (ContractResponse Text Aave.UserContractState)) Aave.AaveUserSchema Void () +userContract = void $ Aave.userEndpoints Mock.aave + +ownerWallet :: Wallet +ownerWallet = Wallet 1 + +lenderWallet :: Wallet +lenderWallet = Wallet 2 + +borrowerWallet :: Wallet +borrowerWallet = Wallet 3 + +userWallets :: [Wallet] +userWallets = [lenderWallet, borrowerWallet] + +initialFunds :: Value +initialFunds = lovelaceValueOf 1000000 <> mconcat ((`assetClassValue` 1000) <$> testAssets) + +type UserHandle = TestUtils.ContractHandle Text Aave.UserContractState Aave.AaveUserSchema Void + +startTrace :: Trace.EmulatorTrace (Map.Map Wallet UserHandle) +startTrace = do + _ <- Trace.activateContractWallet ownerWallet startContract + _ <- Trace.waitNSlots 5 + _ <- Trace.activateContractWallet ownerWallet $ initContract userWallets testAssets + _ <- Trace.waitNSlots 5 + fmap Map.fromList $ forM userWallets $ \wallet -> do + handle <- Trace.activateContractWallet wallet userContract + pure (wallet, handle) + +getPubKey :: UserHandle -> Trace.EmulatorTrace Ledger.PubKeyHash +getPubKey userHandle = do + _ <- Trace.callEndpoint @"ownPubKey" userHandle () + _ <- Trace.waitNSlots 1 + TestUtils.getState (^? Aave._GetPubKey) userHandle + +deposit :: UserHandle -> AssetClass -> Integer -> Trace.EmulatorTrace () +deposit userHandle asset amount = do + pkh <- getPubKey userHandle + Trace.callEndpoint @"deposit" userHandle $ Aave.DepositParams asset pkh amount + _ <- Trace.waitNSlots 3 + pure () + +withdraw :: UserHandle -> AssetClass -> Integer -> Trace.EmulatorTrace () +withdraw userHandle asset amount = do + pkh <- getPubKey userHandle + Trace.callEndpoint @"withdraw" userHandle $ Aave.WithdrawParams asset pkh amount + _ <- Trace.waitNSlots 3 + pure () + +initialReserves :: AssocMap.Map AssetClass Aave.Reserve +initialReserves = AssocMap.fromList (fmap (\params -> (Aave.cpAsset params, Aave.createReserve Mock.aave params)) startParams) + +modifyAt :: PlutusTx.Eq k => (v -> v) -> k -> AssocMap.Map k v -> AssocMap.Map k v +modifyAt f k m = maybe m (\v -> AssocMap.insert k (f v) m) (AssocMap.lookup k m) + +modifyAmount :: (Integer -> Integer) -> AssetClass -> AssocMap.Map AssetClass Aave.Reserve -> AssocMap.Map AssetClass Aave.Reserve +modifyAmount f = modifyAt (\r -> r { Aave.rAmount = f . Aave.rAmount $ r }) + +reservesChange :: AssocMap.Map AssetClass Aave.Reserve -> TracePredicate +reservesChange reserves = TestUtils.datumsAtAddress Mock.aaveAddress (TestUtils.one check) + where + check (Aave.ReservesDatum _ reserves') = reserves' == reserves + check _ = False + +tests :: TestTree +tests = testGroup "deposit" [ + checkPredicate + "Successful deposit" + (walletFundsChange + lenderWallet + (initialFunds <> + assetClassValue mogus (negate 100) <> assetClassValue amogus 100) + .&&. reservesChange (modifyAmount (+100) mogus initialReserves) + ) + $ do + handles <- startTrace + deposit (handles Map.! lenderWallet) mogus 100, + checkPredicate + "Successful withdraw" + (walletFundsChange + lenderWallet + (initialFunds <> + assetClassValue mogus (negate 100) <> assetClassValue amogus 100 <> + assetClassValue mogus 50 <> assetClassValue amogus (negate 50)) + .&&. reservesChange (modifyAmount (subtract 50 . (+100)) mogus initialReserves) + ) + $ do + handles <- startTrace + deposit (handles Map.! lenderWallet) mogus 100 + withdraw (handles Map.! lenderWallet) mogus 50 + ] diff --git a/MetaLamp/lending-pool/test/Spec/Utils.hs b/MetaLamp/lending-pool/test/Spec/Utils.hs new file mode 100644 index 000000000..f65e3c00b --- /dev/null +++ b/MetaLamp/lending-pool/test/Spec/Utils.hs @@ -0,0 +1,69 @@ +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeApplications #-} + +module Spec.Utils where + +import qualified Control.Foldl as L +import Control.Monad (unless) +import Control.Monad.Freer.Error (throwError) +import Control.Monad.Freer.Writer (tell) +import qualified Data.Aeson as JSON +import Data.Function ((&)) +import qualified Data.Map as Map +import Data.Maybe (mapMaybe) +import Data.Monoid (Last (..)) +import Data.String (fromString) +import Data.Text.Prettyprint.Doc (Doc) +import Data.Void (Void) +import Ledger (Address) +import qualified Ledger +import Ledger.AddressMap (UtxoMap) +import Plutus.Contract (HasBlockchainActions) +import Plutus.Contract.Test (TracePredicate) +import Plutus.Contracts.Endpoints (ContractResponse (..)) +import qualified Plutus.Trace.Emulator as Trace +import Plutus.Trace.Emulator.Types (EmulatorRuntimeError (..)) +import PlutusTx (IsData, fromData) +import qualified Wallet.Emulator.Folds as Folds +import Wallet.Emulator.MultiAgent (EmulatorEvent) + +type ContractHandle e a = Trace.ContractHandle (Last (ContractResponse e a)) + +getState :: (Show a, Show e, HasBlockchainActions s, Trace.ContractConstraints s, JSON.FromJSON e, JSON.FromJSON a, JSON.ToJSON e, JSON.ToJSON a, JSON.FromJSON e') => + (a -> Maybe b) -> + ContractHandle e a s e' -> + Trace.EmulatorTrace b +getState pick userHandle = do + res <- Trace.observableState userHandle + case res of + (Last (Just (ContractSuccess s))) -> maybe (throwError . GenericError $ "Unexpected state") pure (pick s) + (Last (Just (ContractError e))) -> throwError . GenericError .show $ e + s -> throwError . JSONDecodingError $ "Unexpected state: " <> show s + +utxoAtAddress :: Monad m => Address -> (UtxoMap -> m c)-> L.FoldM m EmulatorEvent c +utxoAtAddress address check = Folds.postMapM check (L.generalize $ Folds.utxoAtAddress address) + +datumsAtAddress :: (IsData a, Show a) => Address -> ([a] -> Bool) -> TracePredicate +datumsAtAddress address check = utxoAtAddress address $ \utxo -> do + let datums = getDatums utxo + result = check datums + unless result $ tell @(Doc Void) (fromString $ "Datum check failed: " <> show datums) + pure result + +getDatums :: IsData a => UtxoMap -> [a] +getDatums = mapMaybe findDatum . Map.elems + +findDatum :: PlutusTx.IsData a => Ledger.TxOutTx -> Maybe a +findDatum o = do + hash <- Ledger.txOutDatumHash $ Ledger.txOutTxOut o + (Ledger.Datum e) <- Map.lookup hash $ Ledger.txData $ Ledger.txOutTxTx o + PlutusTx.fromData e + +allSatisfy :: [a -> Bool] -> a -> Bool +allSatisfy fs a = and . fmap (a &) $ fs + +one :: (a -> Bool) -> [a] -> Bool +one f = foldr reducer False + where + reducer cur acc = if acc then not . f $ cur else f cur From cc67ee655548aef0c72cccb075d881841e40d2c7 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 24 Jun 2021 14:59:48 +0700 Subject: [PATCH 137/169] add oracles to revoke collateral --- .../lending-pool/src/Plutus/Contracts/Core.hs | 16 +++++---- .../src/Plutus/Contracts/Endpoints.hs | 34 ++++++++++++------- .../src/Plutus/Contracts/State.hs | 5 +++ 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 0efb61215..906d1c2b7 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -100,7 +100,7 @@ data AaveRedeemer = | BorrowRedeemer (AssetClass, PubKeyHash) [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] | RepayRedeemer (AssetClass, PubKeyHash) | ProvideCollateralRedeemer (AssetClass, PubKeyHash) - | RevokeCollateralRedeemer (AssetClass, PubKeyHash) AssetClass -- TODO we need to check amountOfCollateralNeededLovelace <= userCollateralBalanceLovelace + | RevokeCollateralRedeemer (AssetClass, PubKeyHash) AssetClass [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] deriving Show PlutusTx.unstableMakeIsData ''AaveRedeemer @@ -196,12 +196,13 @@ makeAaveValidator aave datum StartRedeemer ctx = trace "StartRedeemer" $ vali -- TODO ? further validators should check that ReservesDatum & UserConfigsDatum transormation happens one time -- & ReserveFundsDatum transormation happens at least one time -- TODO ? check that reedeemers contain the same data during transformation +-- TODO validate that userConfigId and reserveId are the only datum changed in trasformation and other users datum is not modified makeAaveValidator aave datum (DepositRedeemer userConfigId) ctx = trace "DepositRedeemer" $ validateDeposit aave datum ctx userConfigId makeAaveValidator aave datum (WithdrawRedeemer userConfigId) ctx = trace "WithdrawRedeemer" $ validateWithdraw aave datum ctx userConfigId makeAaveValidator aave datum (BorrowRedeemer userConfigId oracles) ctx = trace "BorrowRedeemer" $ validateBorrow aave datum ctx userConfigId oracles makeAaveValidator aave datum (RepayRedeemer userConfigId) ctx = trace "RepayRedeemer" $ validateRepay aave datum ctx userConfigId makeAaveValidator aave datum (ProvideCollateralRedeemer userConfigId) ctx = trace "ProvideCollateralRedeemer" $ validateProvideCollateral aave datum ctx userConfigId -makeAaveValidator aave datum (RevokeCollateralRedeemer userConfigId aTokenAsset) ctx = trace "RevokeCollateralRedeemer" $ validateRevokeCollateral aave datum ctx userConfigId aTokenAsset +makeAaveValidator aave datum (RevokeCollateralRedeemer userConfigId aTokenAsset oracles) ctx = trace "RevokeCollateralRedeemer" $ validateRevokeCollateral aave datum ctx userConfigId aTokenAsset oracles validateStart :: Aave -> AaveDatum -> ScriptContext -> Bool validateStart aave (LendingPoolDatum operator) ctx = @@ -387,8 +388,8 @@ validateProvideCollateral aave (UserConfigsDatum stateToken userConfigs) ctx us validateProvideCollateral _ _ _ _ = trace "validateProvideCollateral: Lending Pool Datum management is not allowed" False -validateRevokeCollateral :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> AssetClass -> Bool -validateRevokeCollateral aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) aTokenAsset = +validateRevokeCollateral :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> AssetClass -> [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] -> Bool +validateRevokeCollateral aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) aTokenAsset oracles = traceIfFalse "validateRevokeCollateral: User Configs Datum change is not valid" isValidUserConfigsTransformation where txInfo = scriptContextTxInfo ctx @@ -421,11 +422,14 @@ validateRevokeCollateral aave (UserConfigsDatum stateToken userConfigs) ctx use in investmentShrinkedBy == disbursementAmount && investmentShrinkedBy > 0 && disbursementAmount > 0 && newInvestmentAmount >= 0 && (ucDebt newState == ucDebt oldState) -validateRevokeCollateral aave (UserCollateralFundsDatum owner aTokenAsset) ctx (reserveId, actor) revokedAsset = +validateRevokeCollateral aave (UserCollateralFundsDatum owner aTokenAsset) ctx (reserveId, actor) revokedAsset oracles = traceIfFalse "validateRevokeCollateral: UserCollateralFundsDatum change is not valid" $ owner == actor && revokedAsset == aTokenAsset && checkNegativeFundsTransformation ctx aTokenAsset actor -validateRevokeCollateral _ _ _ _ _ = trace "validateRevokeCollateral: Lending Pool Datum management is not allowed" False +validateRevokeCollateral aave (ReservesDatum stateToken reserves) ctx userConfigId revokedAsset oracles = + traceIfFalse "validateRevokeCollateral: Reserves Datum change is not valid" $ areOraclesTrusted oracles reserves + +validateRevokeCollateral _ _ _ _ _ _ = trace "validateRevokeCollateral: Lending Pool Datum management is not allowed" False checkNegativeFundsTransformation :: ScriptContext -> AssetClass -> PubKeyHash -> Bool checkNegativeFundsTransformation ctx asset actor = isValidFundsChange diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 0170b0edd..735e23d67 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -250,7 +250,7 @@ borrow aave BorrowParams {..} = do configsOutput <- State.findAaveUserConfigs aave State.updateUserConfigs aave redeemer $ userConfigs Prelude.<$ configsOutput - (reservesTx, reserves) <- State.updateReserve aave redeemer bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) + (reservesTx, _) <- State.updateReserve aave redeemer bpAsset (reserve { rAmount = rAmount reserve - bpAmount }) oraclesTx <- mconcat <$> forM oracles Oracle.useOracle @@ -363,11 +363,20 @@ PlutusTx.makeLift ''RevokeCollateralParams revokeCollateral :: (HasBlockchainActions s) => Aave -> RevokeCollateralParams -> Contract w s Text () revokeCollateral aave RevokeCollateralParams {..} = do - reserve <- State.findAaveReserve aave rcpUnderlyingAsset - - let aTokenAsset = rAToken reserve + reserves <- ovValue <$> State.findAaveReserves aave + reserve <- maybe (throwError "Reserve not found") pure $ AssocMap.lookup rcpUnderlyingAsset reserves let userConfigId = (rCurrency reserve, rcpOnBehalfOf) - let redeemer = Core.RevokeCollateralRedeemer userConfigId aTokenAsset + userConfigs <- do + userConfigs <- ovValue <$> State.findAaveUserConfigs aave + case AssocMap.lookup userConfigId userConfigs of + Nothing -> + throwError "User does not have any collateral." + Just userConfig -> pure $ + AssocMap.insert userConfigId userConfig { ucCollateralizedInvestment = ucCollateralizedInvestment userConfig - rcpAmount } userConfigs + oracles <- either throwError pure $ findOraclesForUser rcpOnBehalfOf reserves userConfigs + let aTokenAsset = rAToken reserve + let redeemer = Core.RevokeCollateralRedeemer userConfigId aTokenAsset oracles + utxos <- Map.filter (getUsersCollateral aTokenAsset) <$> utxoAt (Core.aaveAddress aave) @@ -379,15 +388,14 @@ revokeCollateral aave RevokeCollateralParams {..} = do TxUtils.mustPayToScript (Core.aaveInstance aave) rcpOnBehalfOf (userDatum aTokenAsset) remainder (userConfigsTx, _) <- do - userConfigs <- ovValue <$> State.findAaveUserConfigs aave - case AssocMap.lookup userConfigId userConfigs of - Nothing -> - throwError "User does not have any collateral." - Just userConfig -> - State.updateUserConfig aave redeemer userConfigId $ - userConfig { ucCollateralizedInvestment = ucCollateralizedInvestment userConfig - rcpAmount } + configsOutput <- State.findAaveUserConfigs aave + State.updateUserConfigs aave redeemer $ userConfigs Prelude.<$ configsOutput + + reservesTx <- State.roundtripReserves aave redeemer + + oraclesTx <- mconcat <$> forM oracles Oracle.useOracle - ledgerTx <- TxUtils.submitTxPair $ fundsUnlockingTx <> userConfigsTx + ledgerTx <- TxUtils.submitTxPair $ fundsUnlockingTx <> userConfigsTx <> reservesTx <> oraclesTx _ <- awaitTxConfirmed $ txId ledgerTx pure () where diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs index c0a68406a..8fefc843a 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs @@ -111,6 +111,11 @@ updateReserve aave redeemer reserveId reserve = do AssocMap.lookup reserveId (ovValue reservesOutput) updateReserves aave redeemer $ Prelude.fmap (AssocMap.insert reserveId reserve) reservesOutput +roundtripReserves :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> Contract w s Text (TxUtils.TxPair AaveScript) +roundtripReserves aave redeemer = do + reservesOutput <- findAaveReserves aave + fst <$> updateReserves aave redeemer reservesOutput + makeUserHandle :: Aave -> (AssocMap.Map (AssetClass, PubKeyHash) UserConfig -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) makeUserHandle aave toRedeemer = let stateToken = userStateToken aave in From 7894f39b8b32a33c03c40100925a4ea549c4df69 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 24 Jun 2021 15:11:28 +0700 Subject: [PATCH 138/169] check that enough collateral remains during revoke --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 906d1c2b7..31528a9a9 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -406,13 +406,18 @@ validateRevokeCollateral aave (UserConfigsDatum stateToken userConfigs) ctx use actorSpentValue = valueSpentFrom txInfo actor actorRemainderValue = valuePaidTo txInfo actor + oracleValues = + case foldrM (\o@(_, _, _, oAsset) acc -> fmap ((: acc) . (oAsset, )) (Oracle.findOracleValueInTxInputs txInfo o)) [] oracles of + Just vs -> AssocMap.fromList vs + _ -> traceError "validateRevokeCollateral: Oracles have not been provided" + isValidUserConfigsTransformation :: Bool isValidUserConfigsTransformation = maybe False checkUserConfigs userConfigsOutputDatum checkUserConfigs :: (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -> Bool checkUserConfigs (newStateToken, newUserConfigs) = - newStateToken == stateToken && + newStateToken == stateToken && doesCollateralCoverDebt actor oracleValues newUserConfigs && fromMaybe False (checkRedeemerConfig <$> (AssocMap.lookup userConfigId userConfigs) <*> (AssocMap.lookup userConfigId newUserConfigs)) checkRedeemerConfig :: UserConfig -> UserConfig -> Bool checkRedeemerConfig oldState newState = From e8d9a39b21a802a5708396ace7ee1f32f34f7a23 Mon Sep 17 00:00:00 2001 From: megakaban Date: Thu, 24 Jun 2021 15:20:32 +0700 Subject: [PATCH 139/169] Cleanup --- .../lending-pool/src/Plutus/PAB/Simulation.hs | 14 +++++++------- MetaLamp/lending-pool/test/Spec/Mock.hs | 3 +-- MetaLamp/lending-pool/test/Spec/User.hs | 11 ++--------- MetaLamp/lending-pool/test/Spec/Utils.hs | 17 ++++++++++++++--- 4 files changed, 24 insertions(+), 21 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 57eb7f69e..e3c59386b 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -94,7 +94,7 @@ data ContractIDs = ContractIDs { cidUser :: Map.Map Wallet ContractInstanceId, c activateContracts :: Simulation (Builtin AaveContracts) ContractIDs activateContracts = do - cidInit <- Simulator.activateContract ownerWallet Init + cidInit <- Simulator.activateContract ownerWallet $ Init userWallets testAssets _ <- Simulator.waitUntilFinished cidInit Simulator.logString @(Builtin AaveContracts) "Initialization finished." @@ -208,7 +208,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do shutdown data AaveContracts = - Init + Init [Wallet] [AssetClass] | AaveStart | AaveInfo Aave.Aave | AaveUser Aave.Aave @@ -229,12 +229,12 @@ handleAaveContract = Builtin.handleBuiltin getSchema getContract where AaveUser _ -> Builtin.endpointsToSchemas @(Aave.AaveUserSchema .\\ BlockchainActions) AaveInfo _ -> Builtin.endpointsToSchemas @(Aave.AaveInfoSchema .\\ BlockchainActions) AaveStart -> Builtin.endpointsToSchemas @(Aave.AaveOwnerSchema .\\ BlockchainActions) - Init -> Builtin.endpointsToSchemas @Empty + Init _ _ -> Builtin.endpointsToSchemas @Empty getContract = \case - AaveInfo aave -> SomeBuiltin $ Aave.infoEndpoints aave - AaveUser aave -> SomeBuiltin $ Aave.userEndpoints aave - AaveStart -> SomeBuiltin Aave.ownerEndpoints - Init -> SomeBuiltin $ initContract userWallets testAssets + AaveInfo aave -> SomeBuiltin $ Aave.infoEndpoints aave + AaveUser aave -> SomeBuiltin $ Aave.userEndpoints aave + AaveStart -> SomeBuiltin Aave.ownerEndpoints + Init wallets assets -> SomeBuiltin $ initContract wallets assets handlers :: SimulatorEffectHandlers (Builtin AaveContracts) handlers = diff --git a/MetaLamp/lending-pool/test/Spec/Mock.hs b/MetaLamp/lending-pool/test/Spec/Mock.hs index 11393f612..e2c3f5e63 100644 --- a/MetaLamp/lending-pool/test/Spec/Mock.hs +++ b/MetaLamp/lending-pool/test/Spec/Mock.hs @@ -10,7 +10,6 @@ import Data.Text (Text) import Data.Void (Void) import qualified Ledger import qualified Ledger.Constraints as Constraints -import qualified Ledger.Scripts as UntypedScripts import Ledger.Typed.Scripts (MonetaryPolicy) import qualified Ledger.Typed.Scripts as Scripts import Plutus.Contract @@ -19,7 +18,7 @@ import qualified Plutus.Contracts.Endpoints as Aave import qualified Plutus.Contracts.TxUtils as TxUtils import Plutus.V1.Ledger.Contexts (ScriptContext) import qualified Plutus.V1.Ledger.Scripts as Scripts -import Plutus.V1.Ledger.Value (CurrencySymbol, TokenName, Value, +import Plutus.V1.Ledger.Value (CurrencySymbol, TokenName, assetClass, assetClassValue) import qualified PlutusTx import PlutusTx.Prelude diff --git a/MetaLamp/lending-pool/test/Spec/User.hs b/MetaLamp/lending-pool/test/Spec/User.hs index b4ed8d389..af2941e78 100644 --- a/MetaLamp/lending-pool/test/Spec/User.hs +++ b/MetaLamp/lending-pool/test/Spec/User.hs @@ -7,29 +7,21 @@ module Spec.User where import Control.Lens ((^?)) import Control.Monad (forM, void) -import Control.Monad.Freer.Error (throwError) import qualified Data.Map as Map import Data.Monoid (Last (..)) import Data.Text (Text) import Data.Void (Void) import qualified Ledger -import qualified Ledger.Ada as Ada -import Ledger.Constraints (ScriptLookups (..)) -import qualified Ledger.Constraints as Constraints -import Ledger.Scripts (unitRedeemer) -import Ledger.Typed.Scripts as Scripts import Plutus.Contract hiding (throwError) import Plutus.Contract.Test import qualified Plutus.Contracts.AToken as AToken import qualified Plutus.Contracts.Core as Aave import Plutus.Contracts.Endpoints (ContractResponse (..)) import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Contracts.State as Aave import Plutus.PAB.Simulation (initContract, toAsset) import qualified Plutus.Trace.Emulator as Trace import Plutus.V1.Ledger.Ada (lovelaceValueOf) -import Plutus.V1.Ledger.Value (AssetClass, TokenName, Value, - assetClassValue) +import Plutus.V1.Ledger.Value (AssetClass, Value, assetClassValue) import qualified PlutusTx.AssocMap as AssocMap import qualified PlutusTx.Prelude as PlutusTx import qualified Spec.Mock as Mock @@ -48,6 +40,7 @@ amogus = AToken.makeAToken Mock.aaveHash mogus usd :: AssetClass usd = testAssets Prelude.!! 1 +startParams :: [Aave.CreateParams] startParams = fmap Aave.CreateParams testAssets startContract :: Contract () Aave.AaveOwnerSchema Text () diff --git a/MetaLamp/lending-pool/test/Spec/Utils.hs b/MetaLamp/lending-pool/test/Spec/Utils.hs index f65e3c00b..0d8e79910 100644 --- a/MetaLamp/lending-pool/test/Spec/Utils.hs +++ b/MetaLamp/lending-pool/test/Spec/Utils.hs @@ -1,4 +1,5 @@ {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MonoLocalBinds #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} @@ -30,14 +31,24 @@ import Wallet.Emulator.MultiAgent (EmulatorEvent) type ContractHandle e a = Trace.ContractHandle (Last (ContractResponse e a)) -getState :: (Show a, Show e, HasBlockchainActions s, Trace.ContractConstraints s, JSON.FromJSON e, JSON.FromJSON a, JSON.ToJSON e, JSON.ToJSON a, JSON.FromJSON e') => - (a -> Maybe b) -> +getState :: + (Show a + , Show e + , HasBlockchainActions s + , Trace.ContractConstraints s + , JSON.FromJSON e + , JSON.FromJSON a + , JSON.ToJSON e + , JSON.ToJSON a + , JSON.FromJSON e' + ) + => (a -> Maybe b) -> ContractHandle e a s e' -> Trace.EmulatorTrace b getState pick userHandle = do res <- Trace.observableState userHandle case res of - (Last (Just (ContractSuccess s))) -> maybe (throwError . GenericError $ "Unexpected state") pure (pick s) + (Last (Just (ContractSuccess s))) -> maybe (throwError . GenericError $ "Unexpected state: " <> show s) pure (pick s) (Last (Just (ContractError e))) -> throwError . GenericError .show $ e s -> throwError . JSONDecodingError $ "Unexpected state: " <> show s From 223396ab1d5a0656b7059b1b2534ce798009f345 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 24 Jun 2021 15:33:11 +0700 Subject: [PATCH 140/169] fix purs types --- MetaLamp/lending-pool/client/src/View/UsersTable.purs | 6 +++--- MetaLamp/lending-pool/generate-purs/AaveTypes.hs | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/MetaLamp/lending-pool/client/src/View/UsersTable.purs b/MetaLamp/lending-pool/client/src/View/UsersTable.purs index 89de6af40..093ec2d50 100644 --- a/MetaLamp/lending-pool/client/src/View/UsersTable.purs +++ b/MetaLamp/lending-pool/client/src/View/UsersTable.purs @@ -18,9 +18,9 @@ poolUsers asset users = ] userInfo :: forall props act. Tuple String UserConfig -> HH.HTML props act -userInfo (Tuple userId (UserConfig { ucDebt, ucUsingAsCollateral })) = +userInfo (Tuple userId (UserConfig { ucDebt, ucCollateralizedInvestment })) = HH.div_ [ HH.div_ [ HH.text $ "User " <> userId ] - , HH.div_ [ HH.text $ "Debt: " <> (show <<< fromMaybe (fromInt 0) $ ucDebt) ] - , HH.div_ [ HH.text $ "Using as collateral: " <> (show ucUsingAsCollateral) ] + , HH.div_ [ HH.text $ "Debt: " <> (show ucDebt) ] + , HH.div_ [ HH.text $ "Collateral: " <> (show ucCollateralizedInvestment) ] ] diff --git a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs index c5c533fef..1dc5756dd 100644 --- a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs +++ b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs @@ -40,6 +40,7 @@ import Language.PureScript.Bridge.TypeParameters (A) import qualified PSGenerator.Common import qualified Plutus.Contracts.Core as Aave import qualified Plutus.Contracts.Endpoints as Aave +import qualified Plutus.Contracts.Oracle as Oracle import Plutus.PAB.Simulation (AaveContracts (..)) import Plutus.V1.Ledger.Value (AssetClass) @@ -57,6 +58,7 @@ psRatio = expand <$> psTypeParameters aaveTypes :: [SumType 'Haskell] aaveTypes = [ (equal <*> (genericShow <*> mkSumType)) (Proxy @AaveContracts) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.Aave) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Oracle.Oracle) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(Aave.ContractResponse E A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.CreateParams) , (order <*> (equal <*> (genericShow <*> mkSumType))) (Proxy @AssetClass) From 7d75e361c197b358af8d24da45adc7c5436ea915 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 24 Jun 2021 15:33:54 +0700 Subject: [PATCH 141/169] fmt haskell --- .../lending-pool/generate-purs/AaveTypes.hs | 13 ++--------- .../lending-pool/src/Plutus/Contracts/Core.hs | 8 +++---- .../src/Plutus/Contracts/Endpoints.hs | 18 +++++++-------- .../src/Plutus/Contracts/Oracle.hs | 22 +++++++++---------- .../src/Plutus/Contracts/TxUtils.hs | 2 +- .../lending-pool/src/Plutus/PAB/Simulation.hs | 16 +++++++------- 6 files changed, 35 insertions(+), 44 deletions(-) diff --git a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs index 1dc5756dd..2a88c22a5 100644 --- a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs +++ b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs @@ -11,15 +11,6 @@ module AaveTypes where -import Language.PureScript.Bridge (BridgePart, Language (Haskell), SumType, - TypeInfo (TypeInfo), buildBridge, equal, genericShow, - haskType, mkSumType, order, typeModule, typeName, - writePSTypesWith, (^==), PSType, psTypeParameters) -import Data.Proxy (Proxy (Proxy)) -import qualified Plutus.Contracts.Core as Aave -import qualified Plutus.Contracts.Endpoints as Aave -import Plutus.PAB.Simulation (AaveContracts(..)) -import Language.PureScript.Bridge.TypeParameters (A, E) import Control.Monad.Reader (MonadReader) import Data.Proxy (Proxy (Proxy)) import Language.PureScript.Bridge (BridgePart, @@ -36,11 +27,11 @@ import Language.PureScript.Bridge (BridgePart, writePSTypesWith, (^==)) import Language.PureScript.Bridge.Builder (BridgeData) -import Language.PureScript.Bridge.TypeParameters (A) +import Language.PureScript.Bridge.TypeParameters (A, E) import qualified PSGenerator.Common import qualified Plutus.Contracts.Core as Aave import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Contracts.Oracle as Oracle +import qualified Plutus.Contracts.Oracle as Oracle import Plutus.PAB.Simulation (AaveContracts (..)) import Plutus.V1.Ledger.Value (AssetClass) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 31528a9a9..474211586 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE TupleSections #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} @@ -12,6 +11,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} @@ -36,6 +36,7 @@ import qualified Ledger.Scripts as UntypedScripts import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract import Plutus.Contract hiding (when) +import qualified Plutus.Contracts.Oracle as Oracle import Plutus.V1.Ledger.Value import qualified PlutusTx import qualified PlutusTx.AssocMap as AssocMap @@ -43,7 +44,6 @@ import PlutusTx.Prelude hiding (Semigroup (..), unless) import Prelude (Semigroup (..)) import qualified Prelude -import qualified Plutus.Contracts.Oracle as Oracle newtype Aave = Aave { aaveProtocolInst :: AssetClass @@ -83,7 +83,7 @@ Lens.makeClassy_ ''Reserve data UserConfig = UserConfig { - ucDebt :: Integer, + ucDebt :: Integer, ucCollateralizedInvestment :: Integer } deriving stock (Prelude.Eq, Show, Generic) @@ -283,7 +283,7 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( oracleValues = case foldrM (\o@(_, _, _, oAsset) acc -> fmap ((: acc) . (oAsset, )) (Oracle.findOracleValueInTxInputs txInfo o)) [] oracles of Just vs -> AssocMap.fromList vs - _ -> traceError "validateBorrow: Oracles have not been provided" + _ -> traceError "validateBorrow: Oracles have not been provided" isValidUserConfigsTransformation :: Bool isValidUserConfigsTransformation = diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 735e23d67..ae1d89eff 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -18,7 +18,7 @@ module Plutus.Contracts.Endpoints where -import Control.Monad (forever, void, forM) +import Control.Monad (forM, forever, void) import qualified Data.ByteString as BS import qualified Data.Map as Map import Data.Monoid (Last (..)) @@ -42,6 +42,7 @@ import Plutus.Contracts.Core (Aave, AaveDatum (..), import qualified Plutus.Contracts.Core as Core import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.FungibleToken as FungibleToken +import qualified Plutus.Contracts.Oracle as Oracle import qualified Plutus.Contracts.State as State import qualified Plutus.Contracts.TxUtils as TxUtils import Plutus.OutputValue (OutputValue (..)) @@ -57,11 +58,10 @@ import Prelude (Monoid (..), Semigroup (..), show, subtract) import qualified Prelude import Text.Printf (printf) -import qualified Plutus.Contracts.Oracle as Oracle data CreateParams = CreateParams - { cpAsset :: AssetClass, + { cpAsset :: AssetClass, cpOracle :: Oracle.Oracle } deriving stock (Prelude.Eq, Show, Generic) @@ -310,9 +310,9 @@ repay aave RepayParams {..} = do data ProvideCollateralParams = ProvideCollateralParams { - pcpUnderlyingAsset :: AssetClass, - pcpAmount :: Integer, - pcpOnBehalfOf :: PubKeyHash + pcpUnderlyingAsset :: AssetClass, + pcpAmount :: Integer, + pcpOnBehalfOf :: PubKeyHash } deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) @@ -351,9 +351,9 @@ provideCollateral aave ProvideCollateralParams {..} = do data RevokeCollateralParams = RevokeCollateralParams { - rcpUnderlyingAsset :: AssetClass, - rcpAmount :: Integer, - rcpOnBehalfOf :: PubKeyHash + rcpUnderlyingAsset :: AssetClass, + rcpAmount :: Integer, + rcpOnBehalfOf :: PubKeyHash } deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs index 2e2eccd79..472f6974a 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs @@ -1,18 +1,18 @@ -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -fno-specialise #-} module Plutus.Contracts.Oracle @@ -42,21 +42,21 @@ import qualified Data.Map as Map import Data.Monoid (Last (..)) import Data.Text (Text, pack) import GHC.Generics (Generic) -import Plutus.Contract as Contract hiding (when) -import qualified PlutusTx -import PlutusTx.Prelude hiding (Semigroup(..), unless) import Ledger hiding (singleton) +import Ledger.Ada as Ada import Ledger.Constraints as Constraints import qualified Ledger.Typed.Scripts as Scripts import Ledger.Value as Value -import Ledger.Ada as Ada +import Plutus.Contract as Contract hiding (when) import Plutus.Contracts.Currency as Currency +import qualified Plutus.Contracts.TxUtils as TxUtils +import Plutus.OutputValue +import qualified Plutus.State.Select as Select +import qualified PlutusTx +import PlutusTx.Prelude hiding (Semigroup (..), unless) import Prelude (Semigroup (..)) import qualified Prelude as Prelude -import Schema ( ToSchema) -import qualified Plutus.State.Select as Select -import qualified Plutus.Contracts.TxUtils as TxUtils -import Plutus.OutputValue +import Schema (ToSchema) data Oracle = Oracle { oSymbol :: CurrencySymbol diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs index ef6d4ccbd..e492a0311 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs @@ -9,7 +9,7 @@ module Plutus.Contracts.TxUtils where -import Control.Lens (review) +import Control.Lens (review) import Control.Monad (void) import Data.ByteString (ByteString) import qualified Data.Map as Map diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 08a3c8412..4fb30aadc 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -39,9 +39,10 @@ import Ledger.Value as Value import Plutus.Contract hiding (when) import qualified Plutus.Contracts.Core as Aave import Plutus.Contracts.Currency as Currency +import Plutus.Contracts.Endpoints (ContractResponse (..)) import qualified Plutus.Contracts.Endpoints as Aave -import Plutus.Contracts.Endpoints (ContractResponse(..)) import qualified Plutus.Contracts.FungibleToken as FungibleToken +import qualified Plutus.Contracts.Oracle as Oracle import Plutus.PAB.Effects.Contract (ContractEffect (..)) import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), type (.\\)) @@ -56,7 +57,6 @@ import Plutus.V1.Ledger.Crypto (getPubKeyHash, pubKeyHash) import Prelude hiding (init) import Wallet.Emulator.Types (Wallet (..), walletPubKey) import Wallet.Types (ContractInstanceId) -import qualified Plutus.Contracts.Oracle as Oracle wallets :: [Wallet] wallets = [Wallet i | i <- [1 .. 4]] @@ -105,7 +105,7 @@ activateContracts = do cidInit <- Simulator.activateContract (Wallet 1) Init oracles <- flip Simulator.waitForState cidInit $ \json -> case (fromJSON json :: Result (Monoid.Last [Oracle.Oracle])) of Success (Monoid.Last (Just res)) -> Just res - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) "Initialization finished." let params = fmap (\o -> Aave.CreateParams (Oracle.oAsset o) o) oracles @@ -146,7 +146,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do Aave.DepositParams { Aave.dpAsset = head testAssets, Aave.dpOnBehalfOf = sender, Aave.dpAmount = 400 } flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of Success (Monoid.Last (Just (ContractSuccess Aave.Deposited))) -> Just () - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful deposit" _ <- @@ -154,7 +154,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do Aave.WithdrawParams { Aave.wpAsset = head testAssets, Aave.wpUser = sender, Aave.wpAmount = 30 } flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of Success (Monoid.Last (Just (ContractSuccess Aave.Withdrawn))) -> Just () - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful withdraw" _ <- @@ -180,7 +180,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do Aave.DepositParams { Aave.dpAsset = testAssets !! 1, Aave.dpOnBehalfOf = lender, Aave.dpAmount = 200 } flip Simulator.waitForState lenderCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of Success (Monoid.Last (Just (ContractSuccess Aave.Deposited))) -> Just () - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful deposit from lender" _ <- @@ -188,7 +188,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do Aave.BorrowParams { Aave.bpAsset = testAssets !! 1, Aave.bpAmount = 35, Aave.bpOnBehalfOf = sender } flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of Success (Monoid.Last (Just (ContractSuccess Aave.Borrowed))) -> Just () - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful borrow" _ <- @@ -196,7 +196,7 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do Aave.RepayParams { Aave.rpAsset = testAssets !! 1, Aave.rpAmount = 25, Aave.rpOnBehalfOf = sender } flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of Success (Monoid.Last (Just (ContractSuccess Aave.Repaid))) -> Just () - _ -> Nothing + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful repay" _ <- Simulator.callEndpointOnInstance cidInfo "fundsAt" sender From 737eca1050326ef9b2af7615afecacb74c5f1b28 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 24 Jun 2021 18:18:20 +0700 Subject: [PATCH 142/169] add client endpoints --- .../client/src/Business/AaveUser.purs | 8 +++- .../client/src/Component/Contract.purs | 44 ++++++++++++++++++- .../lending-pool/generate-purs/AaveTypes.hs | 4 +- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/MetaLamp/lending-pool/client/src/Business/AaveUser.purs b/MetaLamp/lending-pool/client/src/Business/AaveUser.purs index ec8cdb99f..fb0617bc0 100644 --- a/MetaLamp/lending-pool/client/src/Business/AaveUser.purs +++ b/MetaLamp/lending-pool/client/src/Business/AaveUser.purs @@ -7,7 +7,7 @@ import Capability.PollContract (class PollContract, PollError) import Data.Either (Either) import Data.Maybe (Maybe) import Data.Newtype (class Newtype, unwrap) -import Plutus.Contracts.Endpoints (BorrowParams, DepositParams, RepayParams, WithdrawParams, _Borrowed, _Deposited, _GetPubKey, _GetPubKeyBalance, _Repaid, _Withdrawn) +import Plutus.Contracts.Endpoints (BorrowParams, ProvideCollateralParams, RevokeCollateralParams, DepositParams, RepayParams, WithdrawParams, _Borrowed, _Deposited, _GetPubKey, _GetPubKeyBalance, _Repaid, _Withdrawn, _CollateralProvided, _CollateralRevoked) import Plutus.PAB.Simulation (AaveContracts, _AaveUser) import Plutus.PAB.Webserver.Types (ContractInstanceClientState) import Plutus.V1.Ledger.Crypto (PubKeyHash) @@ -33,6 +33,12 @@ borrow = getAaveResponseWith (Endpoint "borrow") _Borrowed <<< unwrap repay :: forall m. PollContract m => UserContractId -> RepayParams -> m (Either PollError Unit) repay = getAaveResponseWith (Endpoint "repay") _Repaid <<< unwrap +provideCollateral :: forall m. PollContract m => UserContractId -> ProvideCollateralParams -> m (Either PollError Unit) +provideCollateral = getAaveResponseWith (Endpoint "provideCollateral") _CollateralProvided <<< unwrap + +revokeCollateral :: forall m. PollContract m => UserContractId -> RevokeCollateralParams -> m (Either PollError Unit) +revokeCollateral = getAaveResponseWith (Endpoint "revokeCollateral") _CollateralRevoked <<< unwrap + ownPubKey :: forall m. PollContract m => UserContractId -> m (Either PollError PubKeyHash) ownPubKey cid = getAaveResponseWith (Endpoint "ownPubKey") _GetPubKey (unwrap cid) ContractUnit diff --git a/MetaLamp/lending-pool/client/src/Component/Contract.purs b/MetaLamp/lending-pool/client/src/Component/Contract.purs index 9857c31f1..d8900b4cb 100644 --- a/MetaLamp/lending-pool/client/src/Component/Contract.purs +++ b/MetaLamp/lending-pool/client/src/Component/Contract.purs @@ -24,7 +24,7 @@ import Halogen as H import Halogen.HTML as HH import Network.RemoteData (RemoteData(..)) import Network.RemoteData as RD -import Plutus.Contracts.Endpoints (BorrowParams(..), DepositParams(..), RepayParams(..), WithdrawParams(..)) +import Plutus.Contracts.Endpoints (BorrowParams(..), DepositParams(..), RepayParams(..), WithdrawParams(..), ProvideCollateralParams(..), RevokeCollateralParams(..)) import Plutus.V1.Ledger.Crypto (PubKeyHash) import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..), Value) import View.FundsTable (fundsTable) @@ -38,6 +38,8 @@ type State , withdraw :: RemoteData String Unit , borrow :: RemoteData String Unit , repay :: RemoteData String Unit + , provideCollateral :: RemoteData String Unit + , revokeCollateral :: RemoteData String Unit , submit :: RemoteData String Unit } @@ -53,6 +55,12 @@ _borrow = prop (SProxy :: SProxy "borrow") _repay :: Lens' State (RemoteData String Unit) _repay = prop (SProxy :: SProxy "repay") +_provideCollateral :: Lens' State (RemoteData String Unit) +_provideCollateral = prop (SProxy :: SProxy "provideCollateral") + +_revokeCollateral :: Lens' State (RemoteData String Unit) +_revokeCollateral = prop (SProxy :: SProxy "revokeCollateral") + _submit :: Lens' State (RemoteData String Unit) _submit = prop (SProxy :: SProxy "submit") @@ -76,6 +84,8 @@ initialState { userFunds, userContractId, walletPubKey, reserves } = , deposit: NotAsked , borrow: NotAsked , repay: NotAsked + , provideCollateral: NotAsked + , revokeCollateral: NotAsked , submit: NotAsked } @@ -84,6 +94,8 @@ data Action | Withdraw { amount :: BigInteger, asset :: AssetClass } | Borrow { amount :: BigInteger, asset :: AssetClass } | Repay { amount :: BigInteger, asset :: AssetClass } + | ProvideCollateral { amount :: BigInteger, asset :: AssetClass } + | RevokeCollateral { amount :: BigInteger, asset :: AssetClass } | OnSubmitAmount SubmitOperation AmountForm.Output -- potentially should be separate actions - just a convenience for now, while they are identical @@ -92,6 +104,8 @@ data SubmitOperation | SubmitWithdraw | SubmitBorrow | SubmitRepay + | SubmitProvideCollateral + | SubmitRevokeCollateral derive instance genericSubmitOperation :: Generic SubmitOperation _ @@ -141,6 +155,18 @@ component = { userContractId, walletPubKey } <- lift H.get lift (AaveUser.repay userContractId $ RepayParams { rpAmount: amount, rpAsset: asset, rpOnBehalfOf: walletPubKey }) >>= either (throwError <<< show) (const <<< lift <<< H.raise $ SubmitSuccess) + ProvideCollateral { amount, asset } -> + runRD _provideCollateral <<< runExceptT + $ do + { userContractId, walletPubKey } <- lift H.get + lift (AaveUser.provideCollateral userContractId $ ProvideCollateralParams { pcpUnderlyingAsset: asset, pcpAmount: amount, pcpOnBehalfOf: walletPubKey }) + >>= either (throwError <<< show) (const <<< lift <<< H.raise $ SubmitSuccess) + RevokeCollateral { amount, asset } -> + runRD _revokeCollateral <<< runExceptT + $ do + { userContractId, walletPubKey } <- lift H.get + lift (AaveUser.revokeCollateral userContractId $ RevokeCollateralParams { rcpUnderlyingAsset: asset, rcpAmount: amount, rcpOnBehalfOf: walletPubKey }) + >>= either (throwError <<< show) (const <<< lift <<< H.raise $ SubmitSuccess) OnSubmitAmount operation (AmountForm.Submit { name, amount }) -> runRD _submit <<< runExceptT $ do @@ -175,6 +201,20 @@ component = (throwError $ "Submit repay failed: " <> show repay) (const <<< pure $ unit) repay + SubmitProvideCollateral -> do + lift $ handleAction (ProvideCollateral { amount, asset }) + { provideCollateral } <- lift H.get + RD.maybe + (throwError $ "Submit provideCollateral failed: " <> show provideCollateral) + (const <<< pure $ unit) + provideCollateral + SubmitRevokeCollateral -> do + lift $ handleAction (RevokeCollateral { amount, asset }) + { revokeCollateral } <- lift H.get + RD.maybe + (throwError $ "Submit revokeCollateral failed: " <> show revokeCollateral) + (const <<< pure $ unit) + revokeCollateral Nothing -> throwError "Asset name not found" render :: State -> H.ComponentHTML Action Slots m @@ -194,7 +234,7 @@ component = , HH.slot _amountForm index AmountForm.component (reservesToAmounts state.reserves) (Just <<< (OnSubmitAmount operation)) ] ) - [ Tuple "Deposit" SubmitDeposit, Tuple "Withdraw" SubmitWithdraw, Tuple "Borrow" SubmitBorrow, Tuple "Repay" SubmitRepay ] + [ Tuple "Deposit" SubmitDeposit, Tuple "Withdraw" SubmitWithdraw, Tuple "Borrow" SubmitBorrow, Tuple "Repay" SubmitRepay, Tuple "ProvideCollateral" SubmitProvideCollateral, Tuple "RevokeCollateral" SubmitRevokeCollateral ] ] reservesToAmounts :: Array { amount :: BigInteger, asset :: AssetClass } -> Array AmountForm.AmountInfo diff --git a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs index 2a88c22a5..9289a39bd 100644 --- a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs +++ b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs @@ -60,4 +60,6 @@ aaveTypes = [ (equal <*> (genericShow <*> mkSumType)) (Proxy @AaveContracts) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.DepositParams) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.WithdrawParams) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.BorrowParams) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.RepayParams) ] + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.RepayParams) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.ProvideCollateralParams) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.RevokeCollateralParams) ] From c3e25dcf97eb5e120293be81ef0accf28716ec2d Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 24 Jun 2021 19:48:35 +0700 Subject: [PATCH 143/169] rm ToSchema instance --- MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs index 474211586..cb1687f15 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs @@ -53,7 +53,6 @@ newtype Aave = Aave PlutusTx.makeLift ''Aave deriving anyclass instance ToSchema Rational -deriving anyclass instance ToSchema (CurrencySymbol, PubKeyHash, Integer, AssetClass) data Reserve = Reserve { rCurrency :: AssetClass, -- reserve id @@ -64,7 +63,7 @@ data Reserve = Reserve rTrustedOracle :: (CurrencySymbol, PubKeyHash, Integer, AssetClass) } deriving stock (Prelude.Eq, Show, Generic) - deriving anyclass (ToJSON, FromJSON, ToSchema) + deriving anyclass (ToJSON, FromJSON) PlutusTx.unstableMakeIsData ''Reserve PlutusTx.makeLift ''Reserve From 903c0e5dbdbc0d02a97a6aa5c3290a1d666db0a5 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Thu, 24 Jun 2021 21:10:01 +0700 Subject: [PATCH 144/169] add code comments --- MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index ae1d89eff..eef45665c 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -320,6 +320,7 @@ data ProvideCollateralParams = PlutusTx.unstableMakeIsData ''ProvideCollateralParams PlutusTx.makeLift ''ProvideCollateralParams +-- | User deposits N amount of aToken as collateral, his investment entry state is increased by N provideCollateral :: (HasBlockchainActions s) => Aave -> ProvideCollateralParams -> Contract w s Text () provideCollateral aave ProvideCollateralParams {..} = do reserve <- State.findAaveReserve aave pcpUnderlyingAsset @@ -361,6 +362,7 @@ data RevokeCollateralParams = PlutusTx.unstableMakeIsData ''RevokeCollateralParams PlutusTx.makeLift ''RevokeCollateralParams +-- | User withdraws N amount of collateralized aToken, his investment entry state is decreased by N revokeCollateral :: (HasBlockchainActions s) => Aave -> RevokeCollateralParams -> Contract w s Text () revokeCollateral aave RevokeCollateralParams {..} = do reserves <- ovValue <$> State.findAaveReserves aave From cc6e88cf5f8c621708624880c717a40e30171fc9 Mon Sep 17 00:00:00 2001 From: megakaban Date: Thu, 24 Jun 2021 21:12:00 +0700 Subject: [PATCH 145/169] Split tests into separate cases, utils and fixtures --- MetaLamp/lending-pool/plutus-starter.cabal | 2 +- MetaLamp/lending-pool/test/Fixtures.hs | 6 + .../test/{Spec/Mock.hs => Fixtures/Aave.hs} | 2 +- MetaLamp/lending-pool/test/Fixtures/Asset.hs | 23 +++ MetaLamp/lending-pool/test/Fixtures/Init.hs | 56 +++++++ MetaLamp/lending-pool/test/Fixtures/Wallet.hs | 15 ++ MetaLamp/lending-pool/test/Main.hs | 6 +- MetaLamp/lending-pool/test/Spec/Deposit.hs | 47 ++++++ MetaLamp/lending-pool/test/Spec/Shared.hs | 31 ++++ MetaLamp/lending-pool/test/Spec/Start.hs | 48 ++---- MetaLamp/lending-pool/test/Spec/User.hs | 140 ------------------ MetaLamp/lending-pool/test/Spec/Withdraw.hs | 52 +++++++ MetaLamp/lending-pool/test/Utils/Data.hs | 22 +++ .../test/{Spec/Utils.hs => Utils/Trace.hs} | 16 +- 14 files changed, 274 insertions(+), 192 deletions(-) create mode 100644 MetaLamp/lending-pool/test/Fixtures.hs rename MetaLamp/lending-pool/test/{Spec/Mock.hs => Fixtures/Aave.hs} (98%) create mode 100644 MetaLamp/lending-pool/test/Fixtures/Asset.hs create mode 100644 MetaLamp/lending-pool/test/Fixtures/Init.hs create mode 100644 MetaLamp/lending-pool/test/Fixtures/Wallet.hs create mode 100644 MetaLamp/lending-pool/test/Spec/Deposit.hs create mode 100644 MetaLamp/lending-pool/test/Spec/Shared.hs delete mode 100644 MetaLamp/lending-pool/test/Spec/User.hs create mode 100644 MetaLamp/lending-pool/test/Spec/Withdraw.hs create mode 100644 MetaLamp/lending-pool/test/Utils/Data.hs rename MetaLamp/lending-pool/test/{Spec/Utils.hs => Utils/Trace.hs} (87%) diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 2256f0430..f2857e947 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -102,7 +102,7 @@ test-suite test main-is: Main.hs hs-source-dirs: test other-modules: - Spec.Start Spec.Mock Spec.User Spec.Utils + Spec.Start Spec.Deposit Spec.Withdraw Spec.Shared Utils.Data Utils.Trace Fixtures Fixtures.Aave Fixtures.Asset Fixtures.Init Fixtures.Wallet default-language: Haskell2010 ghc-options: -Wall -Wnoncanonical-monad-instances -Wincomplete-uni-patterns -Wincomplete-record-updates diff --git a/MetaLamp/lending-pool/test/Fixtures.hs b/MetaLamp/lending-pool/test/Fixtures.hs new file mode 100644 index 000000000..50346037d --- /dev/null +++ b/MetaLamp/lending-pool/test/Fixtures.hs @@ -0,0 +1,6 @@ +module Fixtures (module Fixtures.Aave, module Fixtures.Asset, module Fixtures.Init, module Fixtures.Wallet) where + +import Fixtures.Aave +import Fixtures.Asset +import Fixtures.Init +import Fixtures.Wallet diff --git a/MetaLamp/lending-pool/test/Spec/Mock.hs b/MetaLamp/lending-pool/test/Fixtures/Aave.hs similarity index 98% rename from MetaLamp/lending-pool/test/Spec/Mock.hs rename to MetaLamp/lending-pool/test/Fixtures/Aave.hs index e2c3f5e63..d0f417991 100644 --- a/MetaLamp/lending-pool/test/Spec/Mock.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Aave.hs @@ -3,7 +3,7 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} -module Spec.Mock where +module Fixtures.Aave where import Control.Monad (void) import Data.Text (Text) diff --git a/MetaLamp/lending-pool/test/Fixtures/Asset.hs b/MetaLamp/lending-pool/test/Fixtures/Asset.hs new file mode 100644 index 000000000..e5e206487 --- /dev/null +++ b/MetaLamp/lending-pool/test/Fixtures/Asset.hs @@ -0,0 +1,23 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Fixtures.Asset where + +import qualified Fixtures.Aave as AaveMock +import qualified Plutus.Contracts.AToken as AToken +import Plutus.PAB.Simulation (toAsset) +import Plutus.V1.Ledger.Value (AssetClass) + +mogus :: AssetClass +mogus = toAsset "MOGUS" + +usd :: AssetClass +usd = toAsset "USD" + +defaultAssets :: [AssetClass] +defaultAssets = [mogus, usd] + +amogus :: AssetClass +amogus = AToken.makeAToken AaveMock.aaveHash mogus + +ausd :: AssetClass +ausd = AToken.makeAToken AaveMock.aaveHash usd diff --git a/MetaLamp/lending-pool/test/Fixtures/Init.hs b/MetaLamp/lending-pool/test/Fixtures/Init.hs new file mode 100644 index 000000000..4eb8c5af1 --- /dev/null +++ b/MetaLamp/lending-pool/test/Fixtures/Init.hs @@ -0,0 +1,56 @@ +module Fixtures.Init where + +import Control.Monad (forM, void) +import qualified Data.Map as Map +import Data.Monoid (Last (..)) +import Data.Text (Text) +import Data.Void (Void) +import qualified Fixtures.Aave as AaveMock +import Fixtures.Asset (defaultAssets) +import Fixtures.Wallet (ownerWallet, userWallets) +import Plutus.Contract +import qualified Plutus.Contracts.Core as Aave +import Plutus.Contracts.Endpoints (ContractResponse (..)) +import qualified Plutus.Contracts.Endpoints as Aave +import Plutus.PAB.Simulation (initContract) +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Ada (lovelaceValueOf) +import Plutus.V1.Ledger.Crypto (PubKeyHash) +import Plutus.V1.Ledger.Value (AssetClass, Value, assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap +import Wallet.Emulator.Wallet (Wallet) + +initialReserves :: AssocMap.Map AssetClass Aave.Reserve +initialReserves = AssocMap.fromList (fmap (\params -> (Aave.cpAsset params, Aave.createReserve AaveMock.aave params)) startParams) + +initialUsers :: AssocMap.Map (AssetClass, PubKeyHash) Aave.UserConfig +initialUsers = AssocMap.empty + +initialFunds :: Value +initialFunds = lovelaceValueOf 1000000 <> mconcat ((`assetClassValue` 1000) <$> defaultAssets) + +startParams :: [Aave.CreateParams] +startParams = fmap Aave.CreateParams defaultAssets + +startContract :: Contract () Aave.AaveOwnerSchema Text () +startContract = void $ AaveMock.start startParams + +userContract :: Contract (Last (ContractResponse Text Aave.UserContractState)) Aave.AaveUserSchema Void () +userContract = void $ Aave.userEndpoints AaveMock.aave + +startTrace :: Trace.EmulatorTrace () +startTrace = do + _ <- Trace.activateContractWallet ownerWallet startContract + _ <- Trace.waitNSlots 5 + pure () + +type UserHandle = Trace.ContractHandle (Last (ContractResponse Text Aave.UserContractState)) Aave.AaveUserSchema Void + +initTrace :: Trace.EmulatorTrace (Map.Map Wallet UserHandle) +initTrace = do + _ <- startTrace + _ <- Trace.activateContractWallet ownerWallet $ initContract userWallets defaultAssets + _ <- Trace.waitNSlots 5 + fmap Map.fromList $ forM userWallets $ \wallet -> do + handle <- Trace.activateContractWallet wallet userContract + pure (wallet, handle) diff --git a/MetaLamp/lending-pool/test/Fixtures/Wallet.hs b/MetaLamp/lending-pool/test/Fixtures/Wallet.hs new file mode 100644 index 000000000..c35e258e7 --- /dev/null +++ b/MetaLamp/lending-pool/test/Fixtures/Wallet.hs @@ -0,0 +1,15 @@ +module Fixtures.Wallet where + +import Wallet.Emulator.Wallet (Wallet (..)) + +ownerWallet :: Wallet +ownerWallet = Wallet 1 + +lenderWallet :: Wallet +lenderWallet = Wallet 2 + +borrowerWallet :: Wallet +borrowerWallet = Wallet 3 + +userWallets :: [Wallet] +userWallets = [lenderWallet, borrowerWallet] diff --git a/MetaLamp/lending-pool/test/Main.hs b/MetaLamp/lending-pool/test/Main.hs index db6081643..272088ba3 100644 --- a/MetaLamp/lending-pool/test/Main.hs +++ b/MetaLamp/lending-pool/test/Main.hs @@ -1,7 +1,8 @@ module Main(main) where +import qualified Spec.Deposit import qualified Spec.Start -import qualified Spec.User +import qualified Spec.Withdraw import Test.Tasty import Test.Tasty.Hedgehog (HedgehogTestLimit (..)) @@ -14,5 +15,6 @@ limit = HedgehogTestLimit (Just 5) tests :: TestTree tests = localOption limit $ testGroup "lending pool tests" [ Spec.Start.tests, - Spec.User.tests + Spec.Deposit.tests, + Spec.Withdraw.tests ] diff --git a/MetaLamp/lending-pool/test/Spec/Deposit.hs b/MetaLamp/lending-pool/test/Spec/Deposit.hs new file mode 100644 index 000000000..0b4424982 --- /dev/null +++ b/MetaLamp/lending-pool/test/Spec/Deposit.hs @@ -0,0 +1,47 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeApplications #-} + +module Spec.Deposit where + +import qualified Data.Map as Map +import qualified Fixtures +import Plutus.Contract.Test +import qualified Plutus.Contracts.Endpoints as Aave +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) +import qualified Spec.Shared as Shared +import Test.Tasty +import qualified Utils.Data as Utils + +tests :: TestTree +tests = testGroup "deposit" [ + checkPredicate + "Should succeed if user's wallet balance is sufficient" + (walletFundsChange + Fixtures.lenderWallet + (Fixtures.initialFunds <> + assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.amogus 100) + .&&. Shared.reservesChange (Shared.modifyAmount (+100) Fixtures.mogus Fixtures.initialReserves) + ) + $ do + handles <- Fixtures.initTrace + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.mogus 100, + checkPredicate + "Should fail if user's wallet balance is insufficient" + (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds + .&&. Shared.reservesChange Fixtures.initialReserves + .&&. assertAccumState Fixtures.userContract (Trace.walletInstanceTag Fixtures.lenderWallet) Utils.isLastError "Contract last state is an error" + ) + $ do + handles <- Fixtures.initTrace + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.mogus 10000 + ] + +deposit :: Fixtures.UserHandle -> AssetClass -> Integer -> Trace.EmulatorTrace () +deposit userHandle asset amount = do + pkh <- Shared.getPubKey userHandle + Trace.callEndpoint @"deposit" userHandle $ Aave.DepositParams asset pkh amount + _ <- Trace.waitNSlots 3 + pure () diff --git a/MetaLamp/lending-pool/test/Spec/Shared.hs b/MetaLamp/lending-pool/test/Spec/Shared.hs new file mode 100644 index 000000000..caf00220f --- /dev/null +++ b/MetaLamp/lending-pool/test/Spec/Shared.hs @@ -0,0 +1,31 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE TypeApplications #-} + +module Spec.Shared where + +import Control.Lens ((^?)) +import qualified Fixtures +import qualified Ledger +import Plutus.Contract.Test (TracePredicate) +import qualified Plutus.Contracts.Core as Aave +import qualified Plutus.Contracts.Endpoints as Aave +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Value (AssetClass) +import qualified PlutusTx.AssocMap as AssocMap +import qualified Utils.Data as Utils +import qualified Utils.Trace as Utils + +getPubKey :: Fixtures.UserHandle -> Trace.EmulatorTrace Ledger.PubKeyHash +getPubKey userHandle = do + _ <- Trace.callEndpoint @"ownPubKey" userHandle () + _ <- Trace.waitNSlots 1 + Utils.getState (^? Aave._GetPubKey) userHandle + +reservesChange :: AssocMap.Map AssetClass Aave.Reserve -> TracePredicate +reservesChange reserves = Utils.datumsAtAddress Fixtures.aaveAddress (Utils.one check) + where + check (Aave.ReservesDatum _ reserves') = reserves' == reserves + check _ = False + +modifyAmount :: (Integer -> Integer) -> AssetClass -> AssocMap.Map AssetClass Aave.Reserve -> AssocMap.Map AssetClass Aave.Reserve +modifyAmount f = Utils.modifyAt (\r -> r { Aave.rAmount = f . Aave.rAmount $ r }) diff --git a/MetaLamp/lending-pool/test/Spec/Start.hs b/MetaLamp/lending-pool/test/Spec/Start.hs index 72649ada4..bdcf491e7 100644 --- a/MetaLamp/lending-pool/test/Spec/Start.hs +++ b/MetaLamp/lending-pool/test/Spec/Start.hs @@ -3,48 +3,26 @@ module Spec.Start where -import Control.Monad (void) -import Data.Text (Text) -import Plutus.Contract +import qualified Fixtures import Plutus.Contract.Test -import qualified Plutus.Contracts.Core as Aave -import qualified Plutus.Contracts.Endpoints as Aave -import Plutus.PAB.Simulation (testAssets) -import qualified Plutus.Trace.Emulator as Trace -import qualified PlutusTx.AssocMap as AssocMap -import qualified Spec.Mock as Mock -import qualified Spec.Utils as TestUtils +import qualified Plutus.Contracts.Core as Aave import Test.Tasty +import qualified Utils.Data as Utils +import qualified Utils.Trace as Utils -startParams :: [Aave.CreateParams] -startParams = fmap Aave.CreateParams testAssets - -startContract :: Contract () Aave.AaveOwnerSchema Text () -startContract = void $ Mock.start startParams - -ownerWallet :: Wallet -ownerWallet = Wallet 1 - -startTrace :: Trace.EmulatorTrace () -startTrace = do - _ <- Trace.activateContractWallet ownerWallet startContract - _ <- Trace.waitNSlots 5 - pure () +tests :: TestTree +tests = testGroup "start" [checkPredicate + "Should start a new lending pool with a set of available currencies" + (Utils.datumsAtAddress Fixtures.aaveAddress startDatumValid) + Fixtures.startTrace] -initSuccess :: [Aave.AaveDatum] -> Bool -initSuccess = TestUtils.allSatisfy . fmap TestUtils.one $ [hasReserves, hasUsers, hasOperator] +startDatumValid :: [Aave.AaveDatum] -> Bool +startDatumValid = Utils.allSatisfy . fmap Utils.one $ [hasReserves, hasUsers, hasOperator] where hasOperator (Aave.LendingPoolDatum _) = True hasOperator _ = False hasReserves (Aave.ReservesDatum _ reserves) = - reserves == AssocMap.fromList (fmap (\params -> (Aave.cpAsset params, Aave.createReserve Mock.aave params)) startParams) + reserves == Fixtures.initialReserves hasReserves _ = False - hasUsers (Aave.UserConfigsDatum _ users) = users == AssocMap.empty + hasUsers (Aave.UserConfigsDatum _ users) = users == Fixtures.initialUsers hasUsers _ = False - -tests :: TestTree -tests = testGroup "ownerContract" [checkPredicate - "starts a new lending pool" - (assertDone startContract (Trace.walletInstanceTag ownerWallet) (const True) "start contract not done" - .&&. TestUtils.datumsAtAddress Mock.aaveAddress initSuccess) - startTrace] diff --git a/MetaLamp/lending-pool/test/Spec/User.hs b/MetaLamp/lending-pool/test/Spec/User.hs deleted file mode 100644 index af2941e78..000000000 --- a/MetaLamp/lending-pool/test/Spec/User.hs +++ /dev/null @@ -1,140 +0,0 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE TypeApplications #-} - -module Spec.User where - -import Control.Lens ((^?)) -import Control.Monad (forM, void) -import qualified Data.Map as Map -import Data.Monoid (Last (..)) -import Data.Text (Text) -import Data.Void (Void) -import qualified Ledger -import Plutus.Contract hiding (throwError) -import Plutus.Contract.Test -import qualified Plutus.Contracts.AToken as AToken -import qualified Plutus.Contracts.Core as Aave -import Plutus.Contracts.Endpoints (ContractResponse (..)) -import qualified Plutus.Contracts.Endpoints as Aave -import Plutus.PAB.Simulation (initContract, toAsset) -import qualified Plutus.Trace.Emulator as Trace -import Plutus.V1.Ledger.Ada (lovelaceValueOf) -import Plutus.V1.Ledger.Value (AssetClass, Value, assetClassValue) -import qualified PlutusTx.AssocMap as AssocMap -import qualified PlutusTx.Prelude as PlutusTx -import qualified Spec.Mock as Mock -import qualified Spec.Utils as TestUtils -import Test.Tasty - -testAssets :: [AssetClass] -testAssets = fmap toAsset ["MOGUS", "USD"] - -mogus :: AssetClass -mogus = Prelude.head testAssets - -amogus :: AssetClass -amogus = AToken.makeAToken Mock.aaveHash mogus - -usd :: AssetClass -usd = testAssets Prelude.!! 1 - -startParams :: [Aave.CreateParams] -startParams = fmap Aave.CreateParams testAssets - -startContract :: Contract () Aave.AaveOwnerSchema Text () -startContract = void $ Mock.start startParams - -userContract :: Contract (Last (ContractResponse Text Aave.UserContractState)) Aave.AaveUserSchema Void () -userContract = void $ Aave.userEndpoints Mock.aave - -ownerWallet :: Wallet -ownerWallet = Wallet 1 - -lenderWallet :: Wallet -lenderWallet = Wallet 2 - -borrowerWallet :: Wallet -borrowerWallet = Wallet 3 - -userWallets :: [Wallet] -userWallets = [lenderWallet, borrowerWallet] - -initialFunds :: Value -initialFunds = lovelaceValueOf 1000000 <> mconcat ((`assetClassValue` 1000) <$> testAssets) - -type UserHandle = TestUtils.ContractHandle Text Aave.UserContractState Aave.AaveUserSchema Void - -startTrace :: Trace.EmulatorTrace (Map.Map Wallet UserHandle) -startTrace = do - _ <- Trace.activateContractWallet ownerWallet startContract - _ <- Trace.waitNSlots 5 - _ <- Trace.activateContractWallet ownerWallet $ initContract userWallets testAssets - _ <- Trace.waitNSlots 5 - fmap Map.fromList $ forM userWallets $ \wallet -> do - handle <- Trace.activateContractWallet wallet userContract - pure (wallet, handle) - -getPubKey :: UserHandle -> Trace.EmulatorTrace Ledger.PubKeyHash -getPubKey userHandle = do - _ <- Trace.callEndpoint @"ownPubKey" userHandle () - _ <- Trace.waitNSlots 1 - TestUtils.getState (^? Aave._GetPubKey) userHandle - -deposit :: UserHandle -> AssetClass -> Integer -> Trace.EmulatorTrace () -deposit userHandle asset amount = do - pkh <- getPubKey userHandle - Trace.callEndpoint @"deposit" userHandle $ Aave.DepositParams asset pkh amount - _ <- Trace.waitNSlots 3 - pure () - -withdraw :: UserHandle -> AssetClass -> Integer -> Trace.EmulatorTrace () -withdraw userHandle asset amount = do - pkh <- getPubKey userHandle - Trace.callEndpoint @"withdraw" userHandle $ Aave.WithdrawParams asset pkh amount - _ <- Trace.waitNSlots 3 - pure () - -initialReserves :: AssocMap.Map AssetClass Aave.Reserve -initialReserves = AssocMap.fromList (fmap (\params -> (Aave.cpAsset params, Aave.createReserve Mock.aave params)) startParams) - -modifyAt :: PlutusTx.Eq k => (v -> v) -> k -> AssocMap.Map k v -> AssocMap.Map k v -modifyAt f k m = maybe m (\v -> AssocMap.insert k (f v) m) (AssocMap.lookup k m) - -modifyAmount :: (Integer -> Integer) -> AssetClass -> AssocMap.Map AssetClass Aave.Reserve -> AssocMap.Map AssetClass Aave.Reserve -modifyAmount f = modifyAt (\r -> r { Aave.rAmount = f . Aave.rAmount $ r }) - -reservesChange :: AssocMap.Map AssetClass Aave.Reserve -> TracePredicate -reservesChange reserves = TestUtils.datumsAtAddress Mock.aaveAddress (TestUtils.one check) - where - check (Aave.ReservesDatum _ reserves') = reserves' == reserves - check _ = False - -tests :: TestTree -tests = testGroup "deposit" [ - checkPredicate - "Successful deposit" - (walletFundsChange - lenderWallet - (initialFunds <> - assetClassValue mogus (negate 100) <> assetClassValue amogus 100) - .&&. reservesChange (modifyAmount (+100) mogus initialReserves) - ) - $ do - handles <- startTrace - deposit (handles Map.! lenderWallet) mogus 100, - checkPredicate - "Successful withdraw" - (walletFundsChange - lenderWallet - (initialFunds <> - assetClassValue mogus (negate 100) <> assetClassValue amogus 100 <> - assetClassValue mogus 50 <> assetClassValue amogus (negate 50)) - .&&. reservesChange (modifyAmount (subtract 50 . (+100)) mogus initialReserves) - ) - $ do - handles <- startTrace - deposit (handles Map.! lenderWallet) mogus 100 - withdraw (handles Map.! lenderWallet) mogus 50 - ] diff --git a/MetaLamp/lending-pool/test/Spec/Withdraw.hs b/MetaLamp/lending-pool/test/Spec/Withdraw.hs new file mode 100644 index 000000000..f99017d6a --- /dev/null +++ b/MetaLamp/lending-pool/test/Spec/Withdraw.hs @@ -0,0 +1,52 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeApplications #-} + +module Spec.Withdraw where + +import qualified Data.Map as Map +import qualified Fixtures +import Plutus.Contract.Test +import qualified Plutus.Contracts.Endpoints as Aave +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) +import Spec.Deposit (deposit) +import qualified Spec.Shared as Shared +import Test.Tasty +import qualified Utils.Data as Utils + +tests :: TestTree +tests = testGroup "withdraw" [ + checkPredicate + "Should succeed if user's protocol balance is sufficient" + (walletFundsChange + Fixtures.lenderWallet + (Fixtures.initialFunds <> + assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.amogus 100 <> + assetClassValue Fixtures.mogus 50 <> assetClassValue Fixtures.amogus (negate 50)) + .&&. Shared.reservesChange (Shared.modifyAmount (subtract 50 . (+100)) Fixtures.mogus Fixtures.initialReserves) + ) + $ do + handles <- Fixtures.initTrace + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.mogus 100 + withdraw (handles Map.! Fixtures.lenderWallet) Fixtures.mogus 50, + checkPredicate + "Should fail if user's protocol balance is insufficient" + (walletFundsChange Fixtures.lenderWallet (Fixtures.initialFunds <> + assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.amogus 100) + .&&. Shared.reservesChange (Shared.modifyAmount (+100) Fixtures.mogus Fixtures.initialReserves) + .&&. assertAccumState Fixtures.userContract (Trace.walletInstanceTag Fixtures.lenderWallet) Utils.isLastError "Contract last state is an error" + ) + $ do + handles <- Fixtures.initTrace + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.mogus 100 + withdraw (handles Map.! Fixtures.lenderWallet) Fixtures.mogus 200 + ] + +withdraw :: Fixtures.UserHandle -> AssetClass -> Integer -> Trace.EmulatorTrace () +withdraw userHandle asset amount = do + pkh <- Shared.getPubKey userHandle + Trace.callEndpoint @"withdraw" userHandle $ Aave.WithdrawParams asset pkh amount + _ <- Trace.waitNSlots 3 + pure () diff --git a/MetaLamp/lending-pool/test/Utils/Data.hs b/MetaLamp/lending-pool/test/Utils/Data.hs new file mode 100644 index 000000000..e98c1f510 --- /dev/null +++ b/MetaLamp/lending-pool/test/Utils/Data.hs @@ -0,0 +1,22 @@ +module Utils.Data where + +import Data.Function ((&)) +import qualified PlutusTx.AssocMap as AssocMap +import qualified PlutusTx.Prelude as PlutusTx +import Data.Monoid (Last (..)) +import Plutus.Contracts.Endpoints (ContractResponse (..)) + +allSatisfy :: [a -> Bool] -> a -> Bool +allSatisfy fs a = and . fmap (a &) $ fs + +one :: (a -> Bool) -> [a] -> Bool +one f = foldr reducer False + where + reducer cur acc = if acc then not . f $ cur else f cur + +modifyAt :: PlutusTx.Eq k => (v -> v) -> k -> AssocMap.Map k v -> AssocMap.Map k v +modifyAt f k m = maybe m (\v -> AssocMap.insert k (f v) m) (AssocMap.lookup k m) + +isLastError :: Last (ContractResponse e a) -> Bool +isLastError (Last (Just (ContractError _))) = True +isLastError _ = False diff --git a/MetaLamp/lending-pool/test/Spec/Utils.hs b/MetaLamp/lending-pool/test/Utils/Trace.hs similarity index 87% rename from MetaLamp/lending-pool/test/Spec/Utils.hs rename to MetaLamp/lending-pool/test/Utils/Trace.hs index 0d8e79910..6c8a1d90a 100644 --- a/MetaLamp/lending-pool/test/Spec/Utils.hs +++ b/MetaLamp/lending-pool/test/Utils/Trace.hs @@ -3,14 +3,14 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} -module Spec.Utils where +module Utils.Trace where import qualified Control.Foldl as L import Control.Monad (unless) import Control.Monad.Freer.Error (throwError) import Control.Monad.Freer.Writer (tell) import qualified Data.Aeson as JSON -import Data.Function ((&)) + import qualified Data.Map as Map import Data.Maybe (mapMaybe) import Data.Monoid (Last (..)) @@ -29,8 +29,6 @@ import PlutusTx (IsData, fromData) import qualified Wallet.Emulator.Folds as Folds import Wallet.Emulator.MultiAgent (EmulatorEvent) -type ContractHandle e a = Trace.ContractHandle (Last (ContractResponse e a)) - getState :: (Show a , Show e @@ -43,7 +41,7 @@ getState :: , JSON.FromJSON e' ) => (a -> Maybe b) -> - ContractHandle e a s e' -> + Trace.ContractHandle (Last (ContractResponse e a)) s e' -> Trace.EmulatorTrace b getState pick userHandle = do res <- Trace.observableState userHandle @@ -70,11 +68,3 @@ findDatum o = do hash <- Ledger.txOutDatumHash $ Ledger.txOutTxOut o (Ledger.Datum e) <- Map.lookup hash $ Ledger.txData $ Ledger.txOutTxTx o PlutusTx.fromData e - -allSatisfy :: [a -> Bool] -> a -> Bool -allSatisfy fs a = and . fmap (a &) $ fs - -one :: (a -> Bool) -> [a] -> Bool -one f = foldr reducer False - where - reducer cur acc = if acc then not . f $ cur else f cur From 34239a3967de11e4885f2bebaafeed2e8b45cab9 Mon Sep 17 00:00:00 2001 From: megakaban Date: Sun, 27 Jun 2021 21:30:54 +0700 Subject: [PATCH 146/169] Add tests for the remaning cases --- MetaLamp/lending-pool/plutus-starter.cabal | 2 +- MetaLamp/lending-pool/test/Fixtures/Aave.hs | 17 +--- MetaLamp/lending-pool/test/Fixtures/Init.hs | 19 ++++- MetaLamp/lending-pool/test/Fixtures/Policy.hs | 21 ----- MetaLamp/lending-pool/test/Fixtures/Symbol.hs | 46 +++++++++++ MetaLamp/lending-pool/test/Main.hs | 12 ++- MetaLamp/lending-pool/test/Spec/Borrow.hs | 77 ++++++++++++++++++ MetaLamp/lending-pool/test/Spec/Deposit.hs | 15 ++-- .../test/Spec/ProvideCollateral.hs | 56 +++++++++++++ MetaLamp/lending-pool/test/Spec/Repay.hs | 80 +++++++++++++++++++ .../test/Spec/RevokeCollateral.hs | 58 ++++++++++++++ MetaLamp/lending-pool/test/Spec/Shared.hs | 32 ++++---- MetaLamp/lending-pool/test/Spec/Withdraw.hs | 21 ++--- 13 files changed, 381 insertions(+), 75 deletions(-) delete mode 100644 MetaLamp/lending-pool/test/Fixtures/Policy.hs create mode 100644 MetaLamp/lending-pool/test/Fixtures/Symbol.hs create mode 100644 MetaLamp/lending-pool/test/Spec/Borrow.hs create mode 100644 MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs create mode 100644 MetaLamp/lending-pool/test/Spec/Repay.hs create mode 100644 MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 35714710c..f4b62f512 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -102,7 +102,7 @@ test-suite test main-is: Main.hs hs-source-dirs: test other-modules: - Spec.Start Spec.Deposit Spec.Withdraw Spec.Shared Utils.Data Utils.Trace Fixtures Fixtures.Policy Fixtures.Aave Fixtures.Asset Fixtures.Init Fixtures.Wallet + Spec.Start Spec.Deposit Spec.Withdraw Spec.ProvideCollateral Spec.RevokeCollateral Spec.Borrow Spec.Repay Spec.Shared Utils.Data Utils.Trace Fixtures Fixtures.Symbol Fixtures.Aave Fixtures.Asset Fixtures.Init Fixtures.Wallet default-language: Haskell2010 ghc-options: -Wall -Wnoncanonical-monad-instances -Wincomplete-uni-patterns -Wincomplete-record-updates diff --git a/MetaLamp/lending-pool/test/Fixtures/Aave.hs b/MetaLamp/lending-pool/test/Fixtures/Aave.hs index 6e44f9175..89838c02f 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Aave.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Aave.hs @@ -8,7 +8,7 @@ module Fixtures.Aave where import Control.Monad (void) import Data.Text (Text) import Data.Void (Void) -import Fixtures.Policy (makePolicy) +import Fixtures.Symbol (forgeSymbol, getSymbol) import qualified Ledger import qualified Ledger.Constraints as Constraints import Ledger.Typed.Scripts (MonetaryPolicy) @@ -22,11 +22,8 @@ import qualified PlutusTx import PlutusTx.Prelude import qualified Prelude -aavePolicy :: MonetaryPolicy -aavePolicy = makePolicy Aave.aaveProtocolName - aaveSymbol :: CurrencySymbol -aaveSymbol = Ledger.scriptCurrencySymbol aavePolicy +aaveSymbol = getSymbol Aave.aaveProtocolName aaveAddress :: Ledger.Address aaveAddress = Aave.aaveAddress . Aave.aave $ aaveSymbol @@ -38,12 +35,4 @@ aaveHash :: Ledger.ValidatorHash aaveHash = Aave.aaveHash aave start :: [Aave.CreateParams] -> Contract () Aave.AaveOwnerSchema Text Aave.Aave -start = Aave.start' $ do - pkh <- Ledger.pubKeyHash <$> ownPubKey - let forgeValue = assetClassValue (assetClass aaveSymbol Aave.aaveProtocolName) 1 - ledgerTx <- - TxUtils.submitTxPair $ - TxUtils.mustForgeValue @Void aavePolicy forgeValue - Prelude.<> (Prelude.mempty, Constraints.mustPayToPubKey pkh forgeValue) - void $ awaitTxConfirmed $ Ledger.txId ledgerTx - pure aaveSymbol +start = Aave.start' (forgeSymbol Aave.aaveProtocolName) diff --git a/MetaLamp/lending-pool/test/Fixtures/Init.hs b/MetaLamp/lending-pool/test/Fixtures/Init.hs index 1a9ba1654..33ae9e658 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Init.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Init.hs @@ -9,9 +9,8 @@ import Data.Text (Text) import Data.Void (Void) import qualified Fixtures.Aave as AaveMock import Fixtures.Asset (defaultAssets) -import Fixtures.Policy (makePolicy) +import Fixtures.Symbol (forgeSymbol, getSymbol) import Fixtures.Wallet (ownerWallet, userWallets) -import qualified Ledger import Plutus.Contract import qualified Plutus.Contracts.Core as Aave import Plutus.Contracts.Endpoints (ContractResponse (..)) @@ -31,7 +30,7 @@ oracles = fmap (\asset -> Oracle.Oracle { - Oracle.oSymbol = Ledger.scriptCurrencySymbol . makePolicy . snd . unAssetClass $ asset, + Oracle.oSymbol = getSymbol Oracle.oracleTokenName, Oracle.oOperator = PubKeyHash "mock", Oracle.oFee = 0, Oracle.oAsset = asset }) @@ -67,11 +66,25 @@ startTrace = do _ <- Trace.waitNSlots 5 pure () +startOracles :: Contract () BlockchainActions Text () +startOracles = void $ forM oracles + (\oracle -> do + _ <- forgeSymbol Oracle.oracleTokenName + Oracle.updateOracle oracle 1000000 + ) + +oracleTrace :: Trace.EmulatorTrace () +oracleTrace = do + _ <- Trace.activateContractWallet ownerWallet startOracles + _ <- Trace.waitNSlots 5 + pure () + type UserHandle = Trace.ContractHandle (Last (ContractResponse Text Aave.UserContractState)) Aave.AaveUserSchema Void defaultTrace :: Trace.EmulatorTrace (Map.Map Wallet UserHandle) defaultTrace = do _ <- distributeTrace + _ <- oracleTrace _ <- startTrace fmap Map.fromList $ forM userWallets $ \wallet -> do handle <- Trace.activateContractWallet wallet userContract diff --git a/MetaLamp/lending-pool/test/Fixtures/Policy.hs b/MetaLamp/lending-pool/test/Fixtures/Policy.hs deleted file mode 100644 index 1b5e587e7..000000000 --- a/MetaLamp/lending-pool/test/Fixtures/Policy.hs +++ /dev/null @@ -1,21 +0,0 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE TemplateHaskell #-} - -module Fixtures.Policy where - -import Ledger.Typed.Scripts (MonetaryPolicy) -import qualified Ledger.Typed.Scripts as Scripts -import Plutus.V1.Ledger.Contexts (ScriptContext) -import qualified Plutus.V1.Ledger.Scripts as Scripts -import Plutus.V1.Ledger.Value (TokenName) -import qualified PlutusTx - -{-# INLINABLE validator #-} -validator :: TokenName -> ScriptContext -> Bool -validator _ _ = True - -makePolicy :: TokenName -> MonetaryPolicy -makePolicy tokenName = Scripts.mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| Scripts.wrapMonetaryPolicy . validator ||]) - `PlutusTx.applyCode` - PlutusTx.liftCode tokenName diff --git a/MetaLamp/lending-pool/test/Fixtures/Symbol.hs b/MetaLamp/lending-pool/test/Fixtures/Symbol.hs new file mode 100644 index 000000000..a81055aff --- /dev/null +++ b/MetaLamp/lending-pool/test/Fixtures/Symbol.hs @@ -0,0 +1,46 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} + +module Fixtures.Symbol where + +import Control.Monad (void) +import Data.Text (Text) +import Data.Void (Void) +import qualified Ledger +import qualified Ledger.Constraints as Constraints +import Ledger.Typed.Scripts (MonetaryPolicy) +import qualified Ledger.Typed.Scripts as Scripts +import Plutus.Contract +import qualified Plutus.Contracts.TxUtils as TxUtils +import Plutus.V1.Ledger.Contexts (ScriptContext) +import qualified Plutus.V1.Ledger.Scripts as Scripts +import Plutus.V1.Ledger.Value (CurrencySymbol, TokenName, + assetClass, assetClassValue) +import qualified PlutusTx + +{-# INLINABLE validator #-} +validator :: TokenName -> ScriptContext -> Bool +validator _ _ = True + +makePolicy :: TokenName -> MonetaryPolicy +makePolicy tokenName = Scripts.mkMonetaryPolicyScript $ + $$(PlutusTx.compile [|| Scripts.wrapMonetaryPolicy . validator ||]) + `PlutusTx.applyCode` + PlutusTx.liftCode tokenName + +getSymbol :: TokenName -> CurrencySymbol +getSymbol = Ledger.scriptCurrencySymbol . makePolicy + +forgeSymbol :: HasBlockchainActions s => TokenName -> Contract () s Text CurrencySymbol +forgeSymbol tokenName = do + pkh <- Ledger.pubKeyHash <$> ownPubKey + let symbol = getSymbol tokenName + forgeValue = assetClassValue (assetClass symbol tokenName) 1 + ledgerTx <- + TxUtils.submitTxPair $ + TxUtils.mustForgeValue @Void (makePolicy tokenName) forgeValue + <> (mempty, Constraints.mustPayToPubKey pkh forgeValue) + void $ awaitTxConfirmed $ Ledger.txId ledgerTx + pure symbol diff --git a/MetaLamp/lending-pool/test/Main.hs b/MetaLamp/lending-pool/test/Main.hs index 272088ba3..f3e4fcfb4 100644 --- a/MetaLamp/lending-pool/test/Main.hs +++ b/MetaLamp/lending-pool/test/Main.hs @@ -1,10 +1,14 @@ module Main(main) where +import qualified Spec.Borrow import qualified Spec.Deposit +import qualified Spec.ProvideCollateral +import qualified Spec.Repay +import qualified Spec.RevokeCollateral import qualified Spec.Start import qualified Spec.Withdraw import Test.Tasty -import Test.Tasty.Hedgehog (HedgehogTestLimit (..)) +import Test.Tasty.Hedgehog (HedgehogTestLimit (..)) main :: IO () main = defaultMain tests @@ -16,5 +20,9 @@ tests :: TestTree tests = localOption limit $ testGroup "lending pool tests" [ Spec.Start.tests, Spec.Deposit.tests, - Spec.Withdraw.tests + Spec.Withdraw.tests, + Spec.ProvideCollateral.tests, + Spec.RevokeCollateral.tests, + Spec.Borrow.tests, + Spec.Repay.tests ] diff --git a/MetaLamp/lending-pool/test/Spec/Borrow.hs b/MetaLamp/lending-pool/test/Spec/Borrow.hs new file mode 100644 index 000000000..a98ebd546 --- /dev/null +++ b/MetaLamp/lending-pool/test/Spec/Borrow.hs @@ -0,0 +1,77 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeApplications #-} + +module Spec.Borrow where + +import Control.Lens (over) +import qualified Data.Map as Map +import qualified Fixtures +import Plutus.Contract.Test +import qualified Plutus.Contracts.Core as Aave +import qualified Plutus.Contracts.Endpoints as Aave +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap +import Spec.Deposit (deposit) +import Spec.ProvideCollateral (provideCollateral) +import qualified Spec.Shared as Shared +import Test.Tasty +import qualified Utils.Data as Utils + +tests :: TestTree +tests = testGroup "borrow" [ + checkPredicate + "Should succeed if user's collateral is sufficient" + (walletFundsChange + Fixtures.lenderWallet + (Fixtures.initialFunds <> + assetClassValue Fixtures.usd (negate 100) <> assetClassValue Fixtures.ausd 100) + .&&. + walletFundsChange + Fixtures.borrowerWallet + (Fixtures.initialFunds <> + assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.usd 50) + .&&. Shared.reservesChange ( + Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus + . Utils.modifyAt (over Aave._rAmount (subtract 50 . (+100))) Fixtures.usd $ Fixtures.initialReserves) + .&&. Shared.userConfigsChange + ( + AssocMap.insert + (Fixtures.usd, Shared.getPubKey Fixtures.borrowerWallet) + (Aave.UserConfig { Aave.ucDebt = 50, Aave.ucCollateralizedInvestment = 0 }) + . + AssocMap.insert + (Fixtures.mogus, Shared.getPubKey Fixtures.borrowerWallet) + (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 100 }) + . + AssocMap.insert + (Fixtures.usd, Shared.getPubKey Fixtures.lenderWallet) + (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 0 }) + $ Fixtures.initialUsers + ) + ) + $ do + handles <- Fixtures.defaultTrace + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.usd 100 + + deposit (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.mogus 100 + provideCollateral (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.mogus 100 + borrow (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.usd 50, + checkPredicate + "Should fail if user's collateral is insufficient" + (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds + .&&. Shared.reservesChange Fixtures.initialReserves + .&&. assertAccumState Fixtures.userContract (Trace.walletInstanceTag Fixtures.lenderWallet) Utils.isLastError "Contract last state is an error" + ) + $ do + handles <- Fixtures.defaultTrace + borrow (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.usd 100 + ] + +borrow :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () +borrow userHandle wallet asset amount = do + Trace.callEndpoint @"borrow" userHandle $ Aave.BorrowParams asset amount (Shared.getPubKey wallet) + _ <- Trace.waitNSlots 3 + pure () diff --git a/MetaLamp/lending-pool/test/Spec/Deposit.hs b/MetaLamp/lending-pool/test/Spec/Deposit.hs index 1e741fb39..f956a4310 100644 --- a/MetaLamp/lending-pool/test/Spec/Deposit.hs +++ b/MetaLamp/lending-pool/test/Spec/Deposit.hs @@ -5,9 +5,11 @@ module Spec.Deposit where +import Control.Lens (over) import qualified Data.Map as Map import qualified Fixtures import Plutus.Contract.Test +import qualified Plutus.Contracts.Core as Aave import qualified Plutus.Contracts.Endpoints as Aave import qualified Plutus.Trace.Emulator as Trace import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) @@ -23,11 +25,11 @@ tests = testGroup "deposit" [ Fixtures.lenderWallet (Fixtures.initialFunds <> assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.amogus 100) - .&&. Shared.reservesChange (Shared.modifyAmount (+100) Fixtures.mogus Fixtures.initialReserves) + .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus Fixtures.initialReserves) ) $ do handles <- Fixtures.defaultTrace - deposit (handles Map.! Fixtures.lenderWallet) Fixtures.mogus 100, + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100, checkPredicate "Should fail if user's wallet balance is insufficient" (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds @@ -36,12 +38,11 @@ tests = testGroup "deposit" [ ) $ do handles <- Fixtures.defaultTrace - deposit (handles Map.! Fixtures.lenderWallet) Fixtures.mogus 10000 + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 10000 ] -deposit :: Fixtures.UserHandle -> AssetClass -> Integer -> Trace.EmulatorTrace () -deposit userHandle asset amount = do - pkh <- Shared.getPubKey userHandle - Trace.callEndpoint @"deposit" userHandle $ Aave.DepositParams asset pkh amount +deposit :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () +deposit userHandle wallet asset amount = do + Trace.callEndpoint @"deposit" userHandle $ Aave.DepositParams asset (Shared.getPubKey wallet) amount _ <- Trace.waitNSlots 3 pure () diff --git a/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs b/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs new file mode 100644 index 000000000..eeac7e617 --- /dev/null +++ b/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs @@ -0,0 +1,56 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeApplications #-} + +module Spec.ProvideCollateral where + +import Control.Lens (over) +import qualified Data.Map as Map +import qualified Fixtures +import Plutus.Contract.Test +import qualified Plutus.Contracts.Core as Aave +import qualified Plutus.Contracts.Endpoints as Aave +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap +import Spec.Deposit (deposit) +import qualified Spec.Shared as Shared +import Test.Tasty +import qualified Utils.Data as Utils + +tests :: TestTree +tests = testGroup "provideCollateral" [ + checkPredicate + "Should succeed if user's aToken balance is sufficient" + (walletFundsChange + Fixtures.lenderWallet + (Fixtures.initialFunds <> + assetClassValue Fixtures.mogus (negate 100)) + .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus Fixtures.initialReserves) + .&&. Shared.userConfigsChange + (AssocMap.insert + (Fixtures.mogus, Shared.getPubKey Fixtures.lenderWallet) + (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 100 }) + Fixtures.initialUsers) + ) + $ do + handles <- Fixtures.defaultTrace + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 + provideCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100, + checkPredicate + "Should fail if user's aToken balance is insufficient" + (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds + .&&. Shared.reservesChange Fixtures.initialReserves + .&&. assertAccumState Fixtures.userContract (Trace.walletInstanceTag Fixtures.lenderWallet) Utils.isLastError "Contract last state is an error" + ) + $ do + handles <- Fixtures.defaultTrace + provideCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 + ] + +provideCollateral :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () +provideCollateral userHandle wallet asset amount = do + Trace.callEndpoint @"provideCollateral" userHandle $ Aave.ProvideCollateralParams asset amount (Shared.getPubKey wallet) + _ <- Trace.waitNSlots 3 + pure () diff --git a/MetaLamp/lending-pool/test/Spec/Repay.hs b/MetaLamp/lending-pool/test/Spec/Repay.hs new file mode 100644 index 000000000..8d3016208 --- /dev/null +++ b/MetaLamp/lending-pool/test/Spec/Repay.hs @@ -0,0 +1,80 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeApplications #-} + +module Spec.Repay where + +import Control.Lens (over) +import qualified Data.Map as Map +import qualified Fixtures +import Plutus.Contract.Test +import qualified Plutus.Contracts.Core as Aave +import qualified Plutus.Contracts.Endpoints as Aave +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap +import Spec.Borrow (borrow) +import Spec.Deposit (deposit) +import Spec.ProvideCollateral (provideCollateral) +import qualified Spec.Shared as Shared +import Test.Tasty +import qualified Utils.Data as Utils + +tests :: TestTree +tests = testGroup "repay" [ + checkPredicate + "Should succeed if user has a debt and funds to pay" + (walletFundsChange + Fixtures.lenderWallet + (Fixtures.initialFunds <> + assetClassValue Fixtures.usd (negate 100) <> assetClassValue Fixtures.ausd 100) + .&&. + walletFundsChange + Fixtures.borrowerWallet + (Fixtures.initialFunds <> + assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.usd (50 - 25)) + .&&. Shared.reservesChange ( + Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus + . Utils.modifyAt (over Aave._rAmount ((+25) . subtract 50 . (+100))) Fixtures.usd $ Fixtures.initialReserves) + .&&. Shared.userConfigsChange + ( + AssocMap.insert + (Fixtures.usd, Shared.getPubKey Fixtures.borrowerWallet) + (Aave.UserConfig { Aave.ucDebt = 50 - 25, Aave.ucCollateralizedInvestment = 0 }) + . + AssocMap.insert + (Fixtures.mogus, Shared.getPubKey Fixtures.borrowerWallet) + (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 100 }) + . + AssocMap.insert + (Fixtures.usd, Shared.getPubKey Fixtures.lenderWallet) + (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 0 }) + $ Fixtures.initialUsers + ) + ) + $ do + handles <- Fixtures.defaultTrace + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.usd 100 + + deposit (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.mogus 100 + provideCollateral (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.mogus 100 + borrow (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.usd 50 + repay (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.usd 25 + , + checkPredicate + "Should fail if user has no debt" + (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds + .&&. Shared.reservesChange Fixtures.initialReserves + .&&. assertAccumState Fixtures.userContract (Trace.walletInstanceTag Fixtures.lenderWallet) Utils.isLastError "Contract last state is an error" + ) + $ do + handles <- Fixtures.defaultTrace + repay (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.usd 100 + ] + +repay :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () +repay userHandle wallet asset amount = do + Trace.callEndpoint @"repay" userHandle $ Aave.RepayParams asset amount (Shared.getPubKey wallet) + _ <- Trace.waitNSlots 3 + pure () diff --git a/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs b/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs new file mode 100644 index 000000000..82a44c33d --- /dev/null +++ b/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs @@ -0,0 +1,58 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE TypeApplications #-} + +module Spec.RevokeCollateral where + +import Control.Lens (over) +import qualified Data.Map as Map +import qualified Fixtures +import Plutus.Contract.Test +import qualified Plutus.Contracts.Core as Aave +import qualified Plutus.Contracts.Endpoints as Aave +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap +import Spec.Deposit (deposit) +import Spec.ProvideCollateral (provideCollateral) +import qualified Spec.Shared as Shared +import Test.Tasty +import qualified Utils.Data as Utils + +tests :: TestTree +tests = testGroup "revokeCollateral" [ + checkPredicate + "Should succeed if user's investment is sufficient" + (walletFundsChange + Fixtures.lenderWallet + (Fixtures.initialFunds <> + assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.amogus (100 - 100 + 50)) + .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus Fixtures.initialReserves) + .&&. Shared.userConfigsChange + (AssocMap.insert + (Fixtures.mogus, Shared.getPubKey Fixtures.lenderWallet) + (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 50 }) + Fixtures.initialUsers) + ) + $ do + handles <- Fixtures.defaultTrace + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 + provideCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 + revokeCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 50, + checkPredicate + "Should fail if user's investment is insufficient" + (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds + .&&. Shared.reservesChange Fixtures.initialReserves + .&&. assertAccumState Fixtures.userContract (Trace.walletInstanceTag Fixtures.lenderWallet) Utils.isLastError "Contract last state is an error" + ) + $ do + handles <- Fixtures.defaultTrace + revokeCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 + ] + +revokeCollateral :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () +revokeCollateral userHandle wallet asset amount = do + Trace.callEndpoint @"revokeCollateral" userHandle $ Aave.RevokeCollateralParams asset amount (Shared.getPubKey wallet) + _ <- Trace.waitNSlots 3 + pure () diff --git a/MetaLamp/lending-pool/test/Spec/Shared.hs b/MetaLamp/lending-pool/test/Spec/Shared.hs index caf00220f..b94631e40 100644 --- a/MetaLamp/lending-pool/test/Spec/Shared.hs +++ b/MetaLamp/lending-pool/test/Spec/Shared.hs @@ -3,23 +3,18 @@ module Spec.Shared where -import Control.Lens ((^?)) import qualified Fixtures -import qualified Ledger -import Plutus.Contract.Test (TracePredicate) -import qualified Plutus.Contracts.Core as Aave -import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Trace.Emulator as Trace -import Plutus.V1.Ledger.Value (AssetClass) -import qualified PlutusTx.AssocMap as AssocMap -import qualified Utils.Data as Utils -import qualified Utils.Trace as Utils +import Plutus.Contract.Test (TracePredicate) +import qualified Plutus.Contracts.Core as Aave +import Plutus.V1.Ledger.Crypto (PubKeyHash, pubKeyHash) +import Plutus.V1.Ledger.Value (AssetClass) +import qualified PlutusTx.AssocMap as AssocMap +import qualified Utils.Data as Utils +import qualified Utils.Trace as Utils +import Wallet.Emulator.Wallet (Wallet, walletPubKey) -getPubKey :: Fixtures.UserHandle -> Trace.EmulatorTrace Ledger.PubKeyHash -getPubKey userHandle = do - _ <- Trace.callEndpoint @"ownPubKey" userHandle () - _ <- Trace.waitNSlots 1 - Utils.getState (^? Aave._GetPubKey) userHandle +getPubKey :: Wallet -> PubKeyHash +getPubKey = pubKeyHash . walletPubKey reservesChange :: AssocMap.Map AssetClass Aave.Reserve -> TracePredicate reservesChange reserves = Utils.datumsAtAddress Fixtures.aaveAddress (Utils.one check) @@ -27,5 +22,8 @@ reservesChange reserves = Utils.datumsAtAddress Fixtures.aaveAddress (Utils.one check (Aave.ReservesDatum _ reserves') = reserves' == reserves check _ = False -modifyAmount :: (Integer -> Integer) -> AssetClass -> AssocMap.Map AssetClass Aave.Reserve -> AssocMap.Map AssetClass Aave.Reserve -modifyAmount f = Utils.modifyAt (\r -> r { Aave.rAmount = f . Aave.rAmount $ r }) +userConfigsChange :: AssocMap.Map (AssetClass, PubKeyHash) Aave.UserConfig -> TracePredicate +userConfigsChange configs = Utils.datumsAtAddress Fixtures.aaveAddress (Utils.one check) + where + check (Aave.UserConfigsDatum _ configs') = configs' == configs + check _ = False diff --git a/MetaLamp/lending-pool/test/Spec/Withdraw.hs b/MetaLamp/lending-pool/test/Spec/Withdraw.hs index 55343e96d..d1cd35e3b 100644 --- a/MetaLamp/lending-pool/test/Spec/Withdraw.hs +++ b/MetaLamp/lending-pool/test/Spec/Withdraw.hs @@ -5,9 +5,11 @@ module Spec.Withdraw where +import Control.Lens (over) import qualified Data.Map as Map import qualified Fixtures import Plutus.Contract.Test +import qualified Plutus.Contracts.Core as Aave import qualified Plutus.Contracts.Endpoints as Aave import qualified Plutus.Trace.Emulator as Trace import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) @@ -24,28 +26,27 @@ tests = testGroup "withdraw" [ Fixtures.lenderWallet (Fixtures.initialFunds <> assetClassValue Fixtures.mogus (negate 100 + 50) <> assetClassValue Fixtures.amogus (100 - 50)) - .&&. Shared.reservesChange (Shared.modifyAmount (subtract 50 . (+100)) Fixtures.mogus Fixtures.initialReserves) + .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (subtract 50 . (+100))) Fixtures.mogus Fixtures.initialReserves) ) $ do handles <- Fixtures.defaultTrace - deposit (handles Map.! Fixtures.lenderWallet) Fixtures.mogus 100 - withdraw (handles Map.! Fixtures.lenderWallet) Fixtures.mogus 50, + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 + withdraw (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 50, checkPredicate "Should fail if user's protocol balance is insufficient" (walletFundsChange Fixtures.lenderWallet (Fixtures.initialFunds <> assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.amogus 100) - .&&. Shared.reservesChange (Shared.modifyAmount (+100) Fixtures.mogus Fixtures.initialReserves) + .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus Fixtures.initialReserves) .&&. assertAccumState Fixtures.userContract (Trace.walletInstanceTag Fixtures.lenderWallet) Utils.isLastError "Contract last state is an error" ) $ do handles <- Fixtures.defaultTrace - deposit (handles Map.! Fixtures.lenderWallet) Fixtures.mogus 100 - withdraw (handles Map.! Fixtures.lenderWallet) Fixtures.mogus 200 + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 + withdraw (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 200 ] -withdraw :: Fixtures.UserHandle -> AssetClass -> Integer -> Trace.EmulatorTrace () -withdraw userHandle asset amount = do - pkh <- Shared.getPubKey userHandle - Trace.callEndpoint @"withdraw" userHandle $ Aave.WithdrawParams asset pkh amount +withdraw :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () +withdraw userHandle wallet asset amount = do + Trace.callEndpoint @"withdraw" userHandle $ Aave.WithdrawParams asset (Shared.getPubKey wallet) amount _ <- Trace.waitNSlots 3 pure () From 88129b99dca56f67c72c0aaa820083cff9da4b48 Mon Sep 17 00:00:00 2001 From: megakaban Date: Mon, 28 Jun 2021 14:49:49 +0700 Subject: [PATCH 147/169] Move getPubKey --- MetaLamp/lending-pool/test/Fixtures/Aave.hs | 9 +-------- MetaLamp/lending-pool/test/Fixtures/Init.hs | 7 ++++--- MetaLamp/lending-pool/test/Fixtures/Symbol.hs | 1 + MetaLamp/lending-pool/test/Spec/Borrow.hs | 8 ++++---- MetaLamp/lending-pool/test/Spec/Deposit.hs | 2 +- MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs | 4 ++-- MetaLamp/lending-pool/test/Spec/Repay.hs | 8 ++++---- MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs | 4 ++-- MetaLamp/lending-pool/test/Spec/Shared.hs | 6 +----- MetaLamp/lending-pool/test/Spec/Withdraw.hs | 2 +- MetaLamp/lending-pool/test/Utils/Data.hs | 5 +++++ 11 files changed, 26 insertions(+), 30 deletions(-) diff --git a/MetaLamp/lending-pool/test/Fixtures/Aave.hs b/MetaLamp/lending-pool/test/Fixtures/Aave.hs index 89838c02f..4b5ea3be9 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Aave.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Aave.hs @@ -5,22 +5,15 @@ module Fixtures.Aave where -import Control.Monad (void) import Data.Text (Text) -import Data.Void (Void) import Fixtures.Symbol (forgeSymbol, getSymbol) import qualified Ledger -import qualified Ledger.Constraints as Constraints -import Ledger.Typed.Scripts (MonetaryPolicy) import Plutus.Contract import qualified Plutus.Contracts.Core as Aave import qualified Plutus.Contracts.Endpoints as Aave import qualified Plutus.Contracts.TxUtils as TxUtils -import Plutus.V1.Ledger.Value (CurrencySymbol, TokenName, - assetClass, assetClassValue) -import qualified PlutusTx +import Plutus.V1.Ledger.Value (CurrencySymbol) import PlutusTx.Prelude -import qualified Prelude aaveSymbol :: CurrencySymbol aaveSymbol = getSymbol Aave.aaveProtocolName diff --git a/MetaLamp/lending-pool/test/Fixtures/Init.hs b/MetaLamp/lending-pool/test/Fixtures/Init.hs index 33ae9e658..cc4bf6a5d 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Init.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Init.hs @@ -2,7 +2,7 @@ module Fixtures.Init where -import Control.Monad (forM, void) +import Control.Monad (forM_, void) import qualified Data.Map as Map import Data.Monoid (Last (..)) import Data.Text (Text) @@ -23,6 +23,7 @@ import Plutus.V1.Ledger.Crypto (PubKeyHash (..)) import Plutus.V1.Ledger.Value (AssetClass (..), Value, assetClassValue) import qualified PlutusTx.AssocMap as AssocMap +import Utils.Data (getPubKey) import Wallet.Emulator.Wallet (Wallet) oracles :: [Oracle.Oracle] @@ -31,7 +32,7 @@ oracles = fmap Oracle.Oracle { Oracle.oSymbol = getSymbol Oracle.oracleTokenName, - Oracle.oOperator = PubKeyHash "mock", + Oracle.oOperator = getPubKey ownerWallet, Oracle.oFee = 0, Oracle.oAsset = asset }) defaultAssets @@ -67,7 +68,7 @@ startTrace = do pure () startOracles :: Contract () BlockchainActions Text () -startOracles = void $ forM oracles +startOracles = forM_ oracles (\oracle -> do _ <- forgeSymbol Oracle.oracleTokenName Oracle.updateOracle oracle 1000000 diff --git a/MetaLamp/lending-pool/test/Fixtures/Symbol.hs b/MetaLamp/lending-pool/test/Fixtures/Symbol.hs index a81055aff..f7112a897 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Symbol.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Symbol.hs @@ -1,5 +1,6 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MonoLocalBinds #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} diff --git a/MetaLamp/lending-pool/test/Spec/Borrow.hs b/MetaLamp/lending-pool/test/Spec/Borrow.hs index a98ebd546..f88f9f572 100644 --- a/MetaLamp/lending-pool/test/Spec/Borrow.hs +++ b/MetaLamp/lending-pool/test/Spec/Borrow.hs @@ -39,15 +39,15 @@ tests = testGroup "borrow" [ .&&. Shared.userConfigsChange ( AssocMap.insert - (Fixtures.usd, Shared.getPubKey Fixtures.borrowerWallet) + (Fixtures.usd, Utils.getPubKey Fixtures.borrowerWallet) (Aave.UserConfig { Aave.ucDebt = 50, Aave.ucCollateralizedInvestment = 0 }) . AssocMap.insert - (Fixtures.mogus, Shared.getPubKey Fixtures.borrowerWallet) + (Fixtures.mogus, Utils.getPubKey Fixtures.borrowerWallet) (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 100 }) . AssocMap.insert - (Fixtures.usd, Shared.getPubKey Fixtures.lenderWallet) + (Fixtures.usd, Utils.getPubKey Fixtures.lenderWallet) (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 0 }) $ Fixtures.initialUsers ) @@ -72,6 +72,6 @@ tests = testGroup "borrow" [ borrow :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () borrow userHandle wallet asset amount = do - Trace.callEndpoint @"borrow" userHandle $ Aave.BorrowParams asset amount (Shared.getPubKey wallet) + Trace.callEndpoint @"borrow" userHandle $ Aave.BorrowParams asset amount (Utils.getPubKey wallet) _ <- Trace.waitNSlots 3 pure () diff --git a/MetaLamp/lending-pool/test/Spec/Deposit.hs b/MetaLamp/lending-pool/test/Spec/Deposit.hs index f956a4310..21b198301 100644 --- a/MetaLamp/lending-pool/test/Spec/Deposit.hs +++ b/MetaLamp/lending-pool/test/Spec/Deposit.hs @@ -43,6 +43,6 @@ tests = testGroup "deposit" [ deposit :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () deposit userHandle wallet asset amount = do - Trace.callEndpoint @"deposit" userHandle $ Aave.DepositParams asset (Shared.getPubKey wallet) amount + Trace.callEndpoint @"deposit" userHandle $ Aave.DepositParams asset (Utils.getPubKey wallet) amount _ <- Trace.waitNSlots 3 pure () diff --git a/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs b/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs index eeac7e617..2411919b7 100644 --- a/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs +++ b/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs @@ -30,7 +30,7 @@ tests = testGroup "provideCollateral" [ .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus Fixtures.initialReserves) .&&. Shared.userConfigsChange (AssocMap.insert - (Fixtures.mogus, Shared.getPubKey Fixtures.lenderWallet) + (Fixtures.mogus, Utils.getPubKey Fixtures.lenderWallet) (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 100 }) Fixtures.initialUsers) ) @@ -51,6 +51,6 @@ tests = testGroup "provideCollateral" [ provideCollateral :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () provideCollateral userHandle wallet asset amount = do - Trace.callEndpoint @"provideCollateral" userHandle $ Aave.ProvideCollateralParams asset amount (Shared.getPubKey wallet) + Trace.callEndpoint @"provideCollateral" userHandle $ Aave.ProvideCollateralParams asset amount (Utils.getPubKey wallet) _ <- Trace.waitNSlots 3 pure () diff --git a/MetaLamp/lending-pool/test/Spec/Repay.hs b/MetaLamp/lending-pool/test/Spec/Repay.hs index 8d3016208..e85321519 100644 --- a/MetaLamp/lending-pool/test/Spec/Repay.hs +++ b/MetaLamp/lending-pool/test/Spec/Repay.hs @@ -40,15 +40,15 @@ tests = testGroup "repay" [ .&&. Shared.userConfigsChange ( AssocMap.insert - (Fixtures.usd, Shared.getPubKey Fixtures.borrowerWallet) + (Fixtures.usd, Utils.getPubKey Fixtures.borrowerWallet) (Aave.UserConfig { Aave.ucDebt = 50 - 25, Aave.ucCollateralizedInvestment = 0 }) . AssocMap.insert - (Fixtures.mogus, Shared.getPubKey Fixtures.borrowerWallet) + (Fixtures.mogus, Utils.getPubKey Fixtures.borrowerWallet) (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 100 }) . AssocMap.insert - (Fixtures.usd, Shared.getPubKey Fixtures.lenderWallet) + (Fixtures.usd, Utils.getPubKey Fixtures.lenderWallet) (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 0 }) $ Fixtures.initialUsers ) @@ -75,6 +75,6 @@ tests = testGroup "repay" [ repay :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () repay userHandle wallet asset amount = do - Trace.callEndpoint @"repay" userHandle $ Aave.RepayParams asset amount (Shared.getPubKey wallet) + Trace.callEndpoint @"repay" userHandle $ Aave.RepayParams asset amount (Utils.getPubKey wallet) _ <- Trace.waitNSlots 3 pure () diff --git a/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs b/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs index 82a44c33d..ebbf6f7a8 100644 --- a/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs +++ b/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs @@ -31,7 +31,7 @@ tests = testGroup "revokeCollateral" [ .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus Fixtures.initialReserves) .&&. Shared.userConfigsChange (AssocMap.insert - (Fixtures.mogus, Shared.getPubKey Fixtures.lenderWallet) + (Fixtures.mogus, Utils.getPubKey Fixtures.lenderWallet) (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 50 }) Fixtures.initialUsers) ) @@ -53,6 +53,6 @@ tests = testGroup "revokeCollateral" [ revokeCollateral :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () revokeCollateral userHandle wallet asset amount = do - Trace.callEndpoint @"revokeCollateral" userHandle $ Aave.RevokeCollateralParams asset amount (Shared.getPubKey wallet) + Trace.callEndpoint @"revokeCollateral" userHandle $ Aave.RevokeCollateralParams asset amount (Utils.getPubKey wallet) _ <- Trace.waitNSlots 3 pure () diff --git a/MetaLamp/lending-pool/test/Spec/Shared.hs b/MetaLamp/lending-pool/test/Spec/Shared.hs index b94631e40..19bb98e98 100644 --- a/MetaLamp/lending-pool/test/Spec/Shared.hs +++ b/MetaLamp/lending-pool/test/Spec/Shared.hs @@ -6,15 +6,11 @@ module Spec.Shared where import qualified Fixtures import Plutus.Contract.Test (TracePredicate) import qualified Plutus.Contracts.Core as Aave -import Plutus.V1.Ledger.Crypto (PubKeyHash, pubKeyHash) +import Plutus.V1.Ledger.Crypto (PubKeyHash) import Plutus.V1.Ledger.Value (AssetClass) import qualified PlutusTx.AssocMap as AssocMap import qualified Utils.Data as Utils import qualified Utils.Trace as Utils -import Wallet.Emulator.Wallet (Wallet, walletPubKey) - -getPubKey :: Wallet -> PubKeyHash -getPubKey = pubKeyHash . walletPubKey reservesChange :: AssocMap.Map AssetClass Aave.Reserve -> TracePredicate reservesChange reserves = Utils.datumsAtAddress Fixtures.aaveAddress (Utils.one check) diff --git a/MetaLamp/lending-pool/test/Spec/Withdraw.hs b/MetaLamp/lending-pool/test/Spec/Withdraw.hs index d1cd35e3b..a1655eef2 100644 --- a/MetaLamp/lending-pool/test/Spec/Withdraw.hs +++ b/MetaLamp/lending-pool/test/Spec/Withdraw.hs @@ -47,6 +47,6 @@ tests = testGroup "withdraw" [ withdraw :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () withdraw userHandle wallet asset amount = do - Trace.callEndpoint @"withdraw" userHandle $ Aave.WithdrawParams asset (Shared.getPubKey wallet) amount + Trace.callEndpoint @"withdraw" userHandle $ Aave.WithdrawParams asset (Utils.getPubKey wallet) amount _ <- Trace.waitNSlots 3 pure () diff --git a/MetaLamp/lending-pool/test/Utils/Data.hs b/MetaLamp/lending-pool/test/Utils/Data.hs index 7564e8145..1e5f01832 100644 --- a/MetaLamp/lending-pool/test/Utils/Data.hs +++ b/MetaLamp/lending-pool/test/Utils/Data.hs @@ -3,8 +3,10 @@ module Utils.Data where import Data.Function ((&)) import Data.Monoid (Last (..)) import Plutus.Contracts.Endpoints (ContractResponse (..)) +import Plutus.V1.Ledger.Crypto (PubKeyHash, pubKeyHash) import qualified PlutusTx.AssocMap as AssocMap import qualified PlutusTx.Prelude as PlutusTx +import Wallet.Emulator.Wallet (Wallet, walletPubKey) allSatisfy :: [a -> Bool] -> a -> Bool allSatisfy fs a = and . fmap (a &) $ fs @@ -20,3 +22,6 @@ modifyAt f k m = maybe m (\v -> AssocMap.insert k (f v) m) (AssocMap.lookup k m) isLastError :: Last (ContractResponse e a) -> Bool isLastError (Last (Just (ContractError _))) = True isLastError _ = False + +getPubKey :: Wallet -> PubKeyHash +getPubKey = pubKeyHash . walletPubKey From 939c7a598b3a48ad7454aab229c764b7343fea29 Mon Sep 17 00:00:00 2001 From: Stanislav Zhdanovich Date: Mon, 28 Jun 2021 15:07:14 +0700 Subject: [PATCH 148/169] add forM import --- MetaLamp/lending-pool/test/Fixtures/Init.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/test/Fixtures/Init.hs b/MetaLamp/lending-pool/test/Fixtures/Init.hs index cc4bf6a5d..e7cdce8a0 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Init.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Init.hs @@ -2,7 +2,7 @@ module Fixtures.Init where -import Control.Monad (forM_, void) +import Control.Monad (forM_, forM, void) import qualified Data.Map as Map import Data.Monoid (Last (..)) import Data.Text (Text) From 05e3da43e2c44fede7b43b5fd70466c4db4035b1 Mon Sep 17 00:00:00 2001 From: megakaban Date: Mon, 28 Jun 2021 18:08:19 +0700 Subject: [PATCH 149/169] Add user config and borrower wallet checks --- MetaLamp/lending-pool/test/Fixtures/Init.hs | 2 +- MetaLamp/lending-pool/test/Spec/Borrow.hs | 2 ++ MetaLamp/lending-pool/test/Spec/Deposit.hs | 9 +++++++++ .../lending-pool/test/Spec/ProvideCollateral.hs | 1 + MetaLamp/lending-pool/test/Spec/Repay.hs | 2 ++ .../lending-pool/test/Spec/RevokeCollateral.hs | 1 + MetaLamp/lending-pool/test/Spec/Withdraw.hs | 15 +++++++++++++++ 7 files changed, 31 insertions(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/test/Fixtures/Init.hs b/MetaLamp/lending-pool/test/Fixtures/Init.hs index e7cdce8a0..d7a4e2c32 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Init.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Init.hs @@ -2,7 +2,7 @@ module Fixtures.Init where -import Control.Monad (forM_, forM, void) +import Control.Monad (forM, forM_, void) import qualified Data.Map as Map import Data.Monoid (Last (..)) import Data.Text (Text) diff --git a/MetaLamp/lending-pool/test/Spec/Borrow.hs b/MetaLamp/lending-pool/test/Spec/Borrow.hs index f88f9f572..4e9ce0878 100644 --- a/MetaLamp/lending-pool/test/Spec/Borrow.hs +++ b/MetaLamp/lending-pool/test/Spec/Borrow.hs @@ -62,7 +62,9 @@ tests = testGroup "borrow" [ checkPredicate "Should fail if user's collateral is insufficient" (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds + .&&. walletFundsChange Fixtures.borrowerWallet Fixtures.initialFunds .&&. Shared.reservesChange Fixtures.initialReserves + .&&. Shared.userConfigsChange Fixtures.initialUsers .&&. assertAccumState Fixtures.userContract (Trace.walletInstanceTag Fixtures.lenderWallet) Utils.isLastError "Contract last state is an error" ) $ do diff --git a/MetaLamp/lending-pool/test/Spec/Deposit.hs b/MetaLamp/lending-pool/test/Spec/Deposit.hs index 21b198301..8b1912c08 100644 --- a/MetaLamp/lending-pool/test/Spec/Deposit.hs +++ b/MetaLamp/lending-pool/test/Spec/Deposit.hs @@ -13,6 +13,7 @@ import qualified Plutus.Contracts.Core as Aave import qualified Plutus.Contracts.Endpoints as Aave import qualified Plutus.Trace.Emulator as Trace import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap import qualified Spec.Shared as Shared import Test.Tasty import qualified Utils.Data as Utils @@ -26,6 +27,13 @@ tests = testGroup "deposit" [ (Fixtures.initialFunds <> assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.amogus 100) .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus Fixtures.initialReserves) + .&&. Shared.userConfigsChange + ( + AssocMap.insert + (Fixtures.mogus, Utils.getPubKey Fixtures.lenderWallet) + (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 0 }) + $ Fixtures.initialUsers + ) ) $ do handles <- Fixtures.defaultTrace @@ -34,6 +42,7 @@ tests = testGroup "deposit" [ "Should fail if user's wallet balance is insufficient" (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds .&&. Shared.reservesChange Fixtures.initialReserves + .&&. Shared.userConfigsChange Fixtures.initialUsers .&&. assertAccumState Fixtures.userContract (Trace.walletInstanceTag Fixtures.lenderWallet) Utils.isLastError "Contract last state is an error" ) $ do diff --git a/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs b/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs index 2411919b7..2781bf2c0 100644 --- a/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs +++ b/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs @@ -42,6 +42,7 @@ tests = testGroup "provideCollateral" [ "Should fail if user's aToken balance is insufficient" (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds .&&. Shared.reservesChange Fixtures.initialReserves + .&&. Shared.userConfigsChange Fixtures.initialUsers .&&. assertAccumState Fixtures.userContract (Trace.walletInstanceTag Fixtures.lenderWallet) Utils.isLastError "Contract last state is an error" ) $ do diff --git a/MetaLamp/lending-pool/test/Spec/Repay.hs b/MetaLamp/lending-pool/test/Spec/Repay.hs index e85321519..d6a4c3993 100644 --- a/MetaLamp/lending-pool/test/Spec/Repay.hs +++ b/MetaLamp/lending-pool/test/Spec/Repay.hs @@ -65,7 +65,9 @@ tests = testGroup "repay" [ checkPredicate "Should fail if user has no debt" (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds + .&&. walletFundsChange Fixtures.borrowerWallet Fixtures.initialFunds .&&. Shared.reservesChange Fixtures.initialReserves + .&&. Shared.userConfigsChange Fixtures.initialUsers .&&. assertAccumState Fixtures.userContract (Trace.walletInstanceTag Fixtures.lenderWallet) Utils.isLastError "Contract last state is an error" ) $ do diff --git a/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs b/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs index ebbf6f7a8..481b47f78 100644 --- a/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs +++ b/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs @@ -44,6 +44,7 @@ tests = testGroup "revokeCollateral" [ "Should fail if user's investment is insufficient" (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds .&&. Shared.reservesChange Fixtures.initialReserves + .&&. Shared.userConfigsChange Fixtures.initialUsers .&&. assertAccumState Fixtures.userContract (Trace.walletInstanceTag Fixtures.lenderWallet) Utils.isLastError "Contract last state is an error" ) $ do diff --git a/MetaLamp/lending-pool/test/Spec/Withdraw.hs b/MetaLamp/lending-pool/test/Spec/Withdraw.hs index a1655eef2..a130ae3e3 100644 --- a/MetaLamp/lending-pool/test/Spec/Withdraw.hs +++ b/MetaLamp/lending-pool/test/Spec/Withdraw.hs @@ -13,6 +13,7 @@ import qualified Plutus.Contracts.Core as Aave import qualified Plutus.Contracts.Endpoints as Aave import qualified Plutus.Trace.Emulator as Trace import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap import Spec.Deposit (deposit) import qualified Spec.Shared as Shared import Test.Tasty @@ -27,6 +28,13 @@ tests = testGroup "withdraw" [ (Fixtures.initialFunds <> assetClassValue Fixtures.mogus (negate 100 + 50) <> assetClassValue Fixtures.amogus (100 - 50)) .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (subtract 50 . (+100))) Fixtures.mogus Fixtures.initialReserves) + .&&. Shared.userConfigsChange + ( + AssocMap.insert + (Fixtures.mogus, Utils.getPubKey Fixtures.lenderWallet) + (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 0 }) + $ Fixtures.initialUsers + ) ) $ do handles <- Fixtures.defaultTrace @@ -37,6 +45,13 @@ tests = testGroup "withdraw" [ (walletFundsChange Fixtures.lenderWallet (Fixtures.initialFunds <> assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.amogus 100) .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus Fixtures.initialReserves) + .&&. Shared.userConfigsChange + ( + AssocMap.insert + (Fixtures.mogus, Utils.getPubKey Fixtures.lenderWallet) + (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 0 }) + $ Fixtures.initialUsers + ) .&&. assertAccumState Fixtures.userContract (Trace.walletInstanceTag Fixtures.lenderWallet) Utils.isLastError "Contract last state is an error" ) $ do From 6eece47d5bd5f6a5b95100da3eb8840081f006b3 Mon Sep 17 00:00:00 2001 From: megakaban Date: Tue, 29 Jun 2021 16:08:39 +0700 Subject: [PATCH 150/169] Add preloader for submit forms, remove logs for submit --- .../client/src/Component/Contract.purs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/MetaLamp/lending-pool/client/src/Component/Contract.purs b/MetaLamp/lending-pool/client/src/Component/Contract.purs index d8900b4cb..a93727fd8 100644 --- a/MetaLamp/lending-pool/client/src/Component/Contract.purs +++ b/MetaLamp/lending-pool/client/src/Component/Contract.purs @@ -28,6 +28,7 @@ import Plutus.Contracts.Endpoints (BorrowParams(..), DepositParams(..), RepayPar import Plutus.V1.Ledger.Crypto (PubKeyHash) import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..), Value) import View.FundsTable (fundsTable) +import Utils.WithRemoteData (runRDWith) type State = { userContractId :: UserContractId @@ -168,7 +169,7 @@ component = lift (AaveUser.revokeCollateral userContractId $ RevokeCollateralParams { rcpUnderlyingAsset: asset, rcpAmount: amount, rcpOnBehalfOf: walletPubKey }) >>= either (throwError <<< show) (const <<< lift <<< H.raise $ SubmitSuccess) OnSubmitAmount operation (AmountForm.Submit { name, amount }) -> - runRD _submit <<< runExceptT + void $ runRDWith _submit <<< runExceptT $ do { reserves } <- lift H.get case find (\r -> getAssetName r.asset == name) reserves of @@ -177,46 +178,46 @@ component = lift $ handleAction (Deposit { amount, asset }) { deposit } <- lift H.get RD.maybe - (throwError $ "Submit deposit failed: " <> show deposit) + (throwError $ "Submit deposit failed") (const <<< pure $ unit) deposit SubmitWithdraw -> do lift $ handleAction (Withdraw { amount, asset }) { withdraw } <- lift H.get RD.maybe - (throwError $ "Submit withdraw failed: " <> show withdraw) + (throwError $ "Submit withdraw failed") (const <<< pure $ unit) withdraw SubmitBorrow -> do lift $ handleAction (Borrow { amount, asset }) { borrow } <- lift H.get RD.maybe - (throwError $ "Submit borrow failed: " <> show borrow) + (throwError $ "Submit borrow failed") (const <<< pure $ unit) borrow SubmitRepay -> do lift $ handleAction (Repay { amount, asset }) { repay } <- lift H.get RD.maybe - (throwError $ "Submit repay failed: " <> show repay) + (throwError $ "Submit repay failed") (const <<< pure $ unit) repay SubmitProvideCollateral -> do lift $ handleAction (ProvideCollateral { amount, asset }) { provideCollateral } <- lift H.get RD.maybe - (throwError $ "Submit provideCollateral failed: " <> show provideCollateral) + (throwError $ "Submit provideCollateral failed") (const <<< pure $ unit) provideCollateral SubmitRevokeCollateral -> do lift $ handleAction (RevokeCollateral { amount, asset }) { revokeCollateral } <- lift H.get RD.maybe - (throwError $ "Submit revokeCollateral failed: " <> show revokeCollateral) + (throwError $ "Submit revokeCollateral failed") (const <<< pure $ unit) revokeCollateral Nothing -> throwError "Asset name not found" - + render :: State -> H.ComponentHTML Action Slots m render state = HH.div_ @@ -224,9 +225,11 @@ component = , case state.submit of NotAsked -> HH.div_ [] Loading -> HH.div_ [] - Failure e -> HH.div_ [ HH.text $ "Error: " <> show e ] + Failure e -> HH.h4_ [ HH.text e ] Success _ -> HH.div_ [] - , HH.div_ + , case state.submit of + Loading -> HH.div_ [ HH.text "Loading..." ] + _ -> HH.div_ $ mapWithIndex ( \index (Tuple title operation) -> HH.h2_ From 291164f5083b1e4a873ddbd676d909566f465ddb Mon Sep 17 00:00:00 2001 From: megakaban Date: Tue, 29 Jun 2021 18:24:01 +0700 Subject: [PATCH 151/169] Remove Last monoid from contract Writer type --- .../src/Plutus/Contracts/Endpoints.hs | 21 +++-- .../lending-pool/src/Plutus/PAB/Simulation.hs | 78 +++++++++---------- MetaLamp/lending-pool/test/Fixtures/Init.hs | 5 +- MetaLamp/lending-pool/test/Utils/Data.hs | 7 +- MetaLamp/lending-pool/test/Utils/Trace.hs | 6 +- 5 files changed, 61 insertions(+), 56 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs index 18d584f0a..8c3bb8610 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs @@ -115,18 +115,25 @@ data ContractResponse e a = ContractSuccess a | ContractError e | ContractPendin deriving stock (Prelude.Eq, Show, Generic) deriving anyclass (ToJSON, FromJSON) +instance Semigroup (ContractResponse e a) where + a <> b = b + +instance Monoid (ContractResponse e a) where + mempty = ContractPending + mappend = (<>) + handleContract :: forall l a p r s. HasEndpoint l p s => Proxy l -> (a -> r) - -> (p -> Contract (Last (ContractResponse Text r)) s Text a) - -> Contract (Last (ContractResponse Text r)) s Void () + -> (p -> Contract (ContractResponse Text r) s Text a) + -> Contract (ContractResponse Text r) s Void () handleContract _ g c = do e <- runError $ do p <- endpoint @l - _ <- tell $ Last $ Just ContractPending + _ <- tell ContractPending errorHandler `handleError` c p - tell $ Last $ Just $ case e of + tell $ case e of Left err -> ContractError err Right a -> ContractSuccess $ g a where @@ -141,7 +148,7 @@ type AaveOwnerSchema = data OwnerContractState = Started Aave deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) -ownerEndpoints :: Contract (Last (ContractResponse Text OwnerContractState)) AaveOwnerSchema Void () +ownerEndpoints :: Contract (ContractResponse Text OwnerContractState) AaveOwnerSchema Void () ownerEndpoints = forever $ handleContract (Proxy @"start") Started start -- | Gets current Lending Pool reserves state @@ -458,7 +465,7 @@ data UserContractState = Lens.makeClassyPrisms ''UserContractState -- TODO ? add repayWithCollateral -userEndpoints :: Aave -> Contract (Last (ContractResponse Text UserContractState)) AaveUserSchema Void () +userEndpoints :: Aave -> Contract (ContractResponse Text UserContractState) AaveUserSchema Void () userEndpoints aave = forever $ handleContract (Proxy @"deposit") (const Deposited) (deposit aave) `select` handleContract (Proxy @"withdraw") (const Withdrawn) (withdraw aave) @@ -483,7 +490,7 @@ data InfoContractState = | Users (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) -infoEndpoints :: Aave -> Contract (Last (ContractResponse Text InfoContractState)) AaveInfoSchema Void () +infoEndpoints :: Aave -> Contract (ContractResponse Text InfoContractState) AaveInfoSchema Void () infoEndpoints aave = forever $ handleContract (Proxy @"fundsAt") FundsAt fundsAt `select` handleContract (Proxy @"poolFunds") PoolFunds (const $ poolFunds aave) diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 8bc8ab263..0d0519225 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -121,9 +121,9 @@ activateContracts = do cidStart <- Simulator.activateContract ownerWallet AaveStart _ <- Simulator.callEndpointOnInstance cidStart "start" $ fmap (\o -> Aave.CreateParams (Oracle.oAsset o) o) oracles - aa <- flip Simulator.waitForState cidStart $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.OwnerContractState))) of - Success (Monoid.Last (Just (ContractSuccess (Aave.Started aa)))) -> Just aa - _ -> Nothing + aa <- flip Simulator.waitForState cidStart $ \json -> case (fromJSON json :: Result (ContractResponse Text Aave.OwnerContractState)) of + Success (ContractSuccess (Aave.Started aa)) -> Just aa + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Aave instance created: " ++ show aa cidInfo <- Simulator.activateContract ownerWallet $ AaveInfo aa @@ -155,33 +155,33 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do _ <- Simulator.callEndpointOnInstance userCid "deposit" $ Aave.DepositParams { Aave.dpAsset = head testAssets, Aave.dpOnBehalfOf = sender, Aave.dpAmount = 400 } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of - Success (Monoid.Last (Just (ContractSuccess Aave.Deposited))) -> Just () - _ -> Nothing + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (ContractResponse Text Aave.UserContractState)) of + Success (ContractSuccess Aave.Deposited) -> Just () + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful deposit" _ <- Simulator.callEndpointOnInstance userCid "withdraw" $ Aave.WithdrawParams { Aave.wpAsset = head testAssets, Aave.wpUser = sender, Aave.wpAmount = 30 } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of - Success (Monoid.Last (Just (ContractSuccess Aave.Withdrawn))) -> Just () - _ -> Nothing + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (ContractResponse Text Aave.UserContractState)) of + Success (ContractSuccess Aave.Withdrawn) -> Just () + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful withdraw" _ <- Simulator.callEndpointOnInstance userCid "provideCollateral" $ Aave.ProvideCollateralParams { Aave.pcpUnderlyingAsset = head testAssets, Aave.pcpOnBehalfOf = sender, Aave.pcpAmount = 200 } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of - Success (Monoid.Last (Just (ContractSuccess Aave.CollateralProvided))) -> Just () - _ -> Nothing + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (ContractResponse Text Aave.UserContractState)) of + Success (ContractSuccess Aave.CollateralProvided) -> Just () + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful provideCollateral" _ <- Simulator.callEndpointOnInstance userCid "revokeCollateral" $ Aave.RevokeCollateralParams { Aave.rcpUnderlyingAsset = head testAssets, Aave.rcpOnBehalfOf = sender, Aave.rcpAmount = 50 } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of - Success (Monoid.Last (Just (ContractSuccess Aave.CollateralRevoked))) -> Just () - _ -> Nothing + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (ContractResponse Text Aave.UserContractState)) of + Success (ContractSuccess Aave.CollateralRevoked) -> Just () + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful revokeCollateral" let lenderCid = cidUser Map.! Wallet 3 @@ -189,55 +189,55 @@ runLendingPoolSimulation = void $ Simulator.runSimulationWith handlers $ do _ <- Simulator.callEndpointOnInstance lenderCid "deposit" $ Aave.DepositParams { Aave.dpAsset = testAssets !! 1, Aave.dpOnBehalfOf = lender, Aave.dpAmount = 200 } - flip Simulator.waitForState lenderCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of - Success (Monoid.Last (Just (ContractSuccess Aave.Deposited))) -> Just () - _ -> Nothing + flip Simulator.waitForState lenderCid $ \json -> case (fromJSON json :: Result (ContractResponse Text Aave.UserContractState)) of + Success (ContractSuccess Aave.Deposited) -> Just () + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful deposit from lender" _ <- Simulator.callEndpointOnInstance userCid "borrow" $ Aave.BorrowParams { Aave.bpAsset = testAssets !! 1, Aave.bpAmount = 35, Aave.bpOnBehalfOf = sender } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of - Success (Monoid.Last (Just (ContractSuccess Aave.Borrowed))) -> Just () - _ -> Nothing + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (ContractResponse Text Aave.UserContractState)) of + Success (ContractSuccess Aave.Borrowed) -> Just () + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful borrow" _ <- Simulator.callEndpointOnInstance userCid "repay" $ Aave.RepayParams { Aave.rpAsset = testAssets !! 1, Aave.rpAmount = 25, Aave.rpOnBehalfOf = sender } - flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.UserContractState))) of - Success (Monoid.Last (Just (ContractSuccess Aave.Repaid))) -> Just () - _ -> Nothing + flip Simulator.waitForState userCid $ \json -> case (fromJSON json :: Result (ContractResponse Text Aave.UserContractState)) of + Success (ContractSuccess Aave.Repaid) -> Just () + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Successful repay" _ <- Simulator.callEndpointOnInstance cidInfo "fundsAt" sender - v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.InfoContractState))) of - Success (Monoid.Last (Just (ContractSuccess (Aave.FundsAt v)))) -> Just v - _ -> Nothing + v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (ContractResponse Text Aave.InfoContractState)) of + Success (ContractSuccess (Aave.FundsAt v)) -> Just v + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final user funds: " <> show v _ <- Simulator.callEndpointOnInstance cidInfo "fundsAt" lender - v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.InfoContractState))) of - Success (Monoid.Last (Just (ContractSuccess (Aave.FundsAt v)))) -> Just v - _ -> Nothing + v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (ContractResponse Text Aave.InfoContractState)) of + Success (ContractSuccess (Aave.FundsAt v)) -> Just v + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final lender funds: " <> show v _ <- Simulator.callEndpointOnInstance cidInfo "reserves" () - reserves <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.InfoContractState))) of - Success (Monoid.Last (Just (ContractSuccess (Aave.Reserves reserves)))) -> Just reserves - _ -> Nothing + reserves <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (ContractResponse Text Aave.InfoContractState)) of + Success (ContractSuccess (Aave.Reserves reserves)) -> Just reserves + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final reserves: " <> show reserves _ <- Simulator.callEndpointOnInstance cidInfo "poolFunds" () - v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.InfoContractState))) of - Success (Monoid.Last (Just (ContractSuccess (Aave.PoolFunds v)))) -> Just v - _ -> Nothing + v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (ContractResponse Text Aave.InfoContractState)) of + Success (ContractSuccess (Aave.PoolFunds v)) -> Just v + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final pool funds: " <> show v _ <- Simulator.callEndpointOnInstance cidInfo "users" () - v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (Monoid.Last (ContractResponse Text Aave.InfoContractState))) of - Success (Monoid.Last (Just (ContractSuccess (Aave.Users v)))) -> Just v - _ -> Nothing + v <- flip Simulator.waitForState cidInfo $ \json -> case (fromJSON json :: Result (ContractResponse Text Aave.InfoContractState)) of + Success (ContractSuccess (Aave.Users v)) -> Just v + _ -> Nothing Simulator.logString @(Builtin AaveContracts) $ "Final users: " <> show v _ <- liftIO getLine shutdown diff --git a/MetaLamp/lending-pool/test/Fixtures/Init.hs b/MetaLamp/lending-pool/test/Fixtures/Init.hs index d7a4e2c32..5d1d50684 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Init.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Init.hs @@ -4,7 +4,6 @@ module Fixtures.Init where import Control.Monad (forM, forM_, void) import qualified Data.Map as Map -import Data.Monoid (Last (..)) import Data.Text (Text) import Data.Void (Void) import qualified Fixtures.Aave as AaveMock @@ -52,7 +51,7 @@ initialFunds = lovelaceValueOf 1000000 <> mconcat ((`assetClassValue` 1000) <$> startContract :: Contract () Aave.AaveOwnerSchema Text () startContract = void $ AaveMock.start startParams -userContract :: Contract (Last (ContractResponse Text Aave.UserContractState)) Aave.AaveUserSchema Void () +userContract :: Contract (ContractResponse Text Aave.UserContractState) Aave.AaveUserSchema Void () userContract = void $ Aave.userEndpoints AaveMock.aave distributeTrace :: Trace.EmulatorTrace () @@ -80,7 +79,7 @@ oracleTrace = do _ <- Trace.waitNSlots 5 pure () -type UserHandle = Trace.ContractHandle (Last (ContractResponse Text Aave.UserContractState)) Aave.AaveUserSchema Void +type UserHandle = Trace.ContractHandle (ContractResponse Text Aave.UserContractState) Aave.AaveUserSchema Void defaultTrace :: Trace.EmulatorTrace (Map.Map Wallet UserHandle) defaultTrace = do diff --git a/MetaLamp/lending-pool/test/Utils/Data.hs b/MetaLamp/lending-pool/test/Utils/Data.hs index 1e5f01832..8fa6693de 100644 --- a/MetaLamp/lending-pool/test/Utils/Data.hs +++ b/MetaLamp/lending-pool/test/Utils/Data.hs @@ -1,7 +1,6 @@ module Utils.Data where import Data.Function ((&)) -import Data.Monoid (Last (..)) import Plutus.Contracts.Endpoints (ContractResponse (..)) import Plutus.V1.Ledger.Crypto (PubKeyHash, pubKeyHash) import qualified PlutusTx.AssocMap as AssocMap @@ -19,9 +18,9 @@ one f = foldr reducer False modifyAt :: PlutusTx.Eq k => (v -> v) -> k -> AssocMap.Map k v -> AssocMap.Map k v modifyAt f k m = maybe m (\v -> AssocMap.insert k (f v) m) (AssocMap.lookup k m) -isLastError :: Last (ContractResponse e a) -> Bool -isLastError (Last (Just (ContractError _))) = True -isLastError _ = False +isLastError :: ContractResponse e a -> Bool +isLastError (ContractError _) = True +isLastError _ = False getPubKey :: Wallet -> PubKeyHash getPubKey = pubKeyHash . walletPubKey diff --git a/MetaLamp/lending-pool/test/Utils/Trace.hs b/MetaLamp/lending-pool/test/Utils/Trace.hs index 6c8a1d90a..8f9c73412 100644 --- a/MetaLamp/lending-pool/test/Utils/Trace.hs +++ b/MetaLamp/lending-pool/test/Utils/Trace.hs @@ -41,13 +41,13 @@ getState :: , JSON.FromJSON e' ) => (a -> Maybe b) -> - Trace.ContractHandle (Last (ContractResponse e a)) s e' -> + Trace.ContractHandle (ContractResponse e a) s e' -> Trace.EmulatorTrace b getState pick userHandle = do res <- Trace.observableState userHandle case res of - (Last (Just (ContractSuccess s))) -> maybe (throwError . GenericError $ "Unexpected state: " <> show s) pure (pick s) - (Last (Just (ContractError e))) -> throwError . GenericError .show $ e + ContractSuccess s -> maybe (throwError . GenericError $ "Unexpected state: " <> show s) pure (pick s) + ContractError e -> throwError . GenericError . show $ e s -> throwError . JSONDecodingError $ "Unexpected state: " <> show s utxoAtAddress :: Monad m => Address -> (UtxoMap -> m c)-> L.FoldM m EmulatorEvent c From 7d5ef7ae362a0892105b1baeed07ae8cc5f60267 Mon Sep 17 00:00:00 2001 From: megakaban Date: Thu, 1 Jul 2021 16:09:59 +0700 Subject: [PATCH 152/169] Change folder structure --- .../client/src/Business/Aave.purs | 2 +- .../client/src/Business/AaveInfo.purs | 4 +- .../client/src/Business/AaveUser.purs | 2 +- .../client/src/Component/Contract.purs | 2 +- .../client/src/Component/MainPage.purs | 2 +- .../client/src/View/ReserveInfo.purs | 2 +- .../client/src/View/UsersTable.purs | 2 +- .../lending-pool/generate-purs/AaveTypes.hs | 50 +-- MetaLamp/lending-pool/plutus-starter.cabal | 2 +- .../src/Ext/Plutus/Ledger/Value.hs | 10 + .../src/Plutus/Abstract/ContractResponse.hs | 91 +++++ .../src/Plutus/{ => Abstract}/OutputValue.hs | 2 +- .../lending-pool/src/Plutus/Abstract/State.hs | 6 + .../src/Plutus/{ => Abstract}/State/Select.hs | 4 +- .../src/Plutus/{ => Abstract}/State/Update.hs | 6 +- .../Plutus/{Contracts => Abstract}/TxUtils.hs | 53 +-- .../src/Plutus/Contracts/AToken.hs | 122 ------- .../Contracts/LendingPool/OffChain/AToken.hs | 83 +++++ .../Contracts/LendingPool/OffChain/Info.hs | 104 ++++++ .../Contracts/LendingPool/OffChain/Owner.hs | 128 +++++++ .../{ => LendingPool/OffChain}/State.hs | 87 ++--- .../OffChain/User.hs} | 259 ++++---------- .../Contracts/LendingPool/OnChain/AToken.hs | 94 +++++ .../Contracts/LendingPool/OnChain/Core.hs | 78 +++++ .../LendingPool/OnChain/Core/Logic.hs | 210 +++++++++++ .../LendingPool/OnChain/Core/Script.hs | 126 +++++++ .../OnChain/Core/Validator.hs} | 330 ++++-------------- .../Contracts/{ => Service}/FungibleToken.hs | 2 +- .../Plutus/Contracts/{ => Service}/Oracle.hs | 41 ++- .../lending-pool/src/Plutus/PAB/Simulation.hs | 95 ++--- MetaLamp/lending-pool/test/Fixtures.hs | 10 +- MetaLamp/lending-pool/test/Fixtures/Aave.hs | 13 +- MetaLamp/lending-pool/test/Fixtures/Asset.hs | 8 +- MetaLamp/lending-pool/test/Fixtures/Init.hs | 46 +-- MetaLamp/lending-pool/test/Fixtures/Symbol.hs | 2 +- MetaLamp/lending-pool/test/Spec/Borrow.hs | 23 +- MetaLamp/lending-pool/test/Spec/Deposit.hs | 19 +- .../test/Spec/ProvideCollateral.hs | 21 +- MetaLamp/lending-pool/test/Spec/Repay.hs | 25 +- .../test/Spec/RevokeCollateral.hs | 23 +- MetaLamp/lending-pool/test/Spec/Shared.hs | 14 +- MetaLamp/lending-pool/test/Spec/Start.hs | 6 +- MetaLamp/lending-pool/test/Spec/Withdraw.hs | 21 +- MetaLamp/lending-pool/test/Utils/Data.hs | 12 +- MetaLamp/lending-pool/test/Utils/Trace.hs | 42 +-- 45 files changed, 1397 insertions(+), 887 deletions(-) create mode 100644 MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Value.hs create mode 100644 MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs rename MetaLamp/lending-pool/src/Plutus/{ => Abstract}/OutputValue.hs (92%) create mode 100644 MetaLamp/lending-pool/src/Plutus/Abstract/State.hs rename MetaLamp/lending-pool/src/Plutus/{ => Abstract}/State/Select.hs (96%) rename MetaLamp/lending-pool/src/Plutus/{ => Abstract}/State/Update.hs (97%) rename MetaLamp/lending-pool/src/Plutus/{Contracts => Abstract}/TxUtils.hs (56%) delete mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Owner.hs rename MetaLamp/lending-pool/src/Plutus/Contracts/{ => LendingPool/OffChain}/State.hs (65%) rename MetaLamp/lending-pool/src/Plutus/Contracts/{Endpoints.hs => LendingPool/OffChain/User.hs} (63%) create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/AToken.hs create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core.hs create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs create mode 100644 MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Script.hs rename MetaLamp/lending-pool/src/Plutus/Contracts/{Core.hs => LendingPool/OnChain/Core/Validator.hs} (59%) rename MetaLamp/lending-pool/src/Plutus/Contracts/{ => Service}/FungibleToken.hs (93%) rename MetaLamp/lending-pool/src/Plutus/Contracts/{ => Service}/Oracle.hs (88%) diff --git a/MetaLamp/lending-pool/client/src/Business/Aave.purs b/MetaLamp/lending-pool/client/src/Business/Aave.purs index c17cc0ffa..8b4c56cec 100644 --- a/MetaLamp/lending-pool/client/src/Business/Aave.purs +++ b/MetaLamp/lending-pool/client/src/Business/Aave.purs @@ -10,7 +10,7 @@ import Data.Lens (Prism', preview) import Data.Maybe (Maybe, maybe) import Data.RawJson (RawJson(..)) import Foreign.Generic (class Decode, class Encode, decodeJSON) -import Plutus.Contracts.Endpoints (ContractResponse(..)) +import Plutus.Abstract.ContractResponse (ContractResponse(..)) import Plutus.PAB.Events.ContractInstanceState (PartiallyDecodedResponse(..)) import Plutus.PAB.Simulation (AaveContracts) import Plutus.PAB.Webserver.Types (ContractInstanceClientState(..)) diff --git a/MetaLamp/lending-pool/client/src/Business/AaveInfo.purs b/MetaLamp/lending-pool/client/src/Business/AaveInfo.purs index 881cf3859..6c5875051 100644 --- a/MetaLamp/lending-pool/client/src/Business/AaveInfo.purs +++ b/MetaLamp/lending-pool/client/src/Business/AaveInfo.purs @@ -8,8 +8,8 @@ import Data.Either (Either) import Data.Json.JsonTuple (JsonTuple) import Data.Maybe (Maybe) import Data.Newtype (class Newtype, unwrap) -import Plutus.Contracts.Core (Reserve, UserConfig) -import Plutus.Contracts.Endpoints (_FundsAt, _PoolFunds, _Reserves, _Users) +import Plutus.Contracts.LendingPool.OnChain.Core (Reserve, UserConfig) +import Plutus.Contracts.LendingPool.OffChain.Info (_FundsAt, _PoolFunds, _Reserves, _Users) import Plutus.PAB.Simulation (AaveContracts, _AaveInfo) import Plutus.PAB.Webserver.Types (ContractInstanceClientState) import Plutus.V1.Ledger.Crypto (PubKeyHash) diff --git a/MetaLamp/lending-pool/client/src/Business/AaveUser.purs b/MetaLamp/lending-pool/client/src/Business/AaveUser.purs index fb0617bc0..16ef137c1 100644 --- a/MetaLamp/lending-pool/client/src/Business/AaveUser.purs +++ b/MetaLamp/lending-pool/client/src/Business/AaveUser.purs @@ -7,7 +7,7 @@ import Capability.PollContract (class PollContract, PollError) import Data.Either (Either) import Data.Maybe (Maybe) import Data.Newtype (class Newtype, unwrap) -import Plutus.Contracts.Endpoints (BorrowParams, ProvideCollateralParams, RevokeCollateralParams, DepositParams, RepayParams, WithdrawParams, _Borrowed, _Deposited, _GetPubKey, _GetPubKeyBalance, _Repaid, _Withdrawn, _CollateralProvided, _CollateralRevoked) +import Plutus.Contracts.LendingPool.OffChain.User (BorrowParams, ProvideCollateralParams, RevokeCollateralParams, DepositParams, RepayParams, WithdrawParams, _Borrowed, _Deposited, _GetPubKey, _GetPubKeyBalance, _Repaid, _Withdrawn, _CollateralProvided, _CollateralRevoked) import Plutus.PAB.Simulation (AaveContracts, _AaveUser) import Plutus.PAB.Webserver.Types (ContractInstanceClientState) import Plutus.V1.Ledger.Crypto (PubKeyHash) diff --git a/MetaLamp/lending-pool/client/src/Component/Contract.purs b/MetaLamp/lending-pool/client/src/Component/Contract.purs index a93727fd8..9d2c778f6 100644 --- a/MetaLamp/lending-pool/client/src/Component/Contract.purs +++ b/MetaLamp/lending-pool/client/src/Component/Contract.purs @@ -24,7 +24,7 @@ import Halogen as H import Halogen.HTML as HH import Network.RemoteData (RemoteData(..)) import Network.RemoteData as RD -import Plutus.Contracts.Endpoints (BorrowParams(..), DepositParams(..), RepayParams(..), WithdrawParams(..), ProvideCollateralParams(..), RevokeCollateralParams(..)) +import Plutus.Contracts.LendingPool.OffChain.User (BorrowParams(..), DepositParams(..), RepayParams(..), WithdrawParams(..), ProvideCollateralParams(..), RevokeCollateralParams(..)) import Plutus.V1.Ledger.Crypto (PubKeyHash) import Plutus.V1.Ledger.Value (AssetClass(..), TokenName(..), Value) import View.FundsTable (fundsTable) diff --git a/MetaLamp/lending-pool/client/src/Component/MainPage.purs b/MetaLamp/lending-pool/client/src/Component/MainPage.purs index c1f505b9b..8891cccf9 100644 --- a/MetaLamp/lending-pool/client/src/Component/MainPage.purs +++ b/MetaLamp/lending-pool/client/src/Component/MainPage.purs @@ -28,7 +28,7 @@ import Halogen.HTML.Properties (classes) import Network.RemoteData (RemoteData(..)) import Network.RemoteData as RD import Network.RemoteData as RemoteData -import Plutus.Contracts.Core (Reserve(..), UserConfig) +import Plutus.Contracts.LendingPool.OnChain.Core (Reserve(..), UserConfig) import Plutus.PAB.Simulation (AaveContracts) import Plutus.PAB.Webserver.Types (ContractInstanceClientState) import Plutus.V1.Ledger.Crypto (PubKeyHash) diff --git a/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs b/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs index c60a78003..67cdc9585 100644 --- a/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs +++ b/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs @@ -3,7 +3,7 @@ module View.ReserveInfo where import Prelude import Data.BigInteger (BigInteger) import Halogen.HTML as HH -import Plutus.Contracts.Core (Reserve(..)) +import Plutus.Contracts.LendingPool.OnChain.Core (Reserve(..)) import Plutus.V1.Ledger.Value (AssetClass) import View.Utils (assetName) diff --git a/MetaLamp/lending-pool/client/src/View/UsersTable.purs b/MetaLamp/lending-pool/client/src/View/UsersTable.purs index 093ec2d50..9a13aae10 100644 --- a/MetaLamp/lending-pool/client/src/View/UsersTable.purs +++ b/MetaLamp/lending-pool/client/src/View/UsersTable.purs @@ -6,7 +6,7 @@ import Data.BigInteger (fromInt) import Data.Maybe (fromMaybe) import Data.Tuple (Tuple(..)) import Halogen.HTML as HH -import Plutus.Contracts.Core (UserConfig(..)) +import Plutus.Contracts.LendingPool.OnChain.Core (UserConfig(..)) import Plutus.V1.Ledger.Value (AssetClass) import View.Utils (assetName) diff --git a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs index 9289a39bd..47cc56afd 100644 --- a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs +++ b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs @@ -11,29 +11,33 @@ module AaveTypes where -import Control.Monad.Reader (MonadReader) -import Data.Proxy (Proxy (Proxy)) -import Language.PureScript.Bridge (BridgePart, - Language (Haskell), - PSType, SumType, - TypeInfo (TypeInfo), - buildBridge, equal, - genericShow, - haskType, mkSumType, - order, - psTypeParameters, - typeModule, - typeName, - writePSTypesWith, - (^==)) -import Language.PureScript.Bridge.Builder (BridgeData) -import Language.PureScript.Bridge.TypeParameters (A, E) +import Control.Monad.Reader (MonadReader) +import Data.Proxy (Proxy (Proxy)) +import Language.PureScript.Bridge (BridgePart, + Language (Haskell), + PSType, SumType, + TypeInfo (TypeInfo), + buildBridge, + equal, + genericShow, + haskType, + mkSumType, order, + psTypeParameters, + typeModule, + typeName, + writePSTypesWith, + (^==)) +import Language.PureScript.Bridge.Builder (BridgeData) +import Language.PureScript.Bridge.TypeParameters (A, E) import qualified PSGenerator.Common -import qualified Plutus.Contracts.Core as Aave -import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Contracts.Oracle as Oracle -import Plutus.PAB.Simulation (AaveContracts (..)) -import Plutus.V1.Ledger.Value (AssetClass) +import Plutus.Abstract.ContractResponse (ContractResponse) +import qualified Plutus.Contracts.LendingPool.OffChain.Info as Aave +import qualified Plutus.Contracts.LendingPool.OffChain.Owner as Aave +import qualified Plutus.Contracts.LendingPool.OffChain.User as Aave +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave +import qualified Plutus.Contracts.Service.Oracle as Oracle +import Plutus.PAB.Simulation (AaveContracts (..)) +import Plutus.V1.Ledger.Value (AssetClass) ratioBridge :: BridgePart ratioBridge = do @@ -50,7 +54,7 @@ aaveTypes :: [SumType 'Haskell] aaveTypes = [ (equal <*> (genericShow <*> mkSumType)) (Proxy @AaveContracts) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.Aave) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Oracle.Oracle) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @(Aave.ContractResponse E A)) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractResponse E A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.CreateParams) , (order <*> (equal <*> (genericShow <*> mkSumType))) (Proxy @AssetClass) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.UserContractState) diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index f4b62f512..919955258 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -23,7 +23,7 @@ maintainer: Your email library exposed-modules: - Plutus.Contracts.Endpoints Plutus.Contracts.FungibleToken Plutus.Contracts.AToken Plutus.Contracts.Core Plutus.Contracts.Oracle Plutus.Contracts.State Plutus.State.Select Plutus.State.Update Plutus.Contracts.TxUtils Plutus.OutputValue Ext.Plutus.Ledger.Contexts Plutus.PAB.Simulation + Plutus.Abstract.State Plutus.Abstract.State.Select Plutus.Abstract.State.Update Plutus.Abstract.ContractResponse Plutus.Abstract.OutputValue Plutus.Abstract.TxUtils Plutus.Contracts.Service.FungibleToken Plutus.Contracts.Service.Oracle Plutus.Contracts.LendingPool.OnChain.Core Plutus.Contracts.LendingPool.OnChain.Core.Script Plutus.Contracts.LendingPool.OnChain.Core.Validator Plutus.Contracts.LendingPool.OnChain.Core.Logic Plutus.Contracts.LendingPool.OnChain.AToken Plutus.Contracts.LendingPool.OffChain.AToken Plutus.Contracts.LendingPool.OffChain.Info Plutus.Contracts.LendingPool.OffChain.Owner Plutus.Contracts.LendingPool.OffChain.State Plutus.Contracts.LendingPool.OffChain.User Plutus.PAB.Simulation Ext.Plutus.Ledger.Value Ext.Plutus.Ledger.Contexts build-depends: base >= 4.9 && < 5, aeson, diff --git a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Value.hs b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Value.hs new file mode 100644 index 000000000..591245d65 --- /dev/null +++ b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Value.hs @@ -0,0 +1,10 @@ +module Ext.Plutus.Ledger.Value where + +import qualified Data.Map as Map +import Ledger (TxOut (txOutValue), + TxOutTx (txOutTxOut), Value) +import Ledger.AddressMap (UtxoMap) +import Plutus.V1.Ledger.Value (Value) + +utxoValue :: UtxoMap -> Value +utxoValue = foldMap (txOutValue . txOutTxOut . snd) . Map.toList diff --git a/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs new file mode 100644 index 000000000..cfde04d7a --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs @@ -0,0 +1,91 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + +module Plutus.Abstract.ContractResponse where + +import qualified Control.Lens as Lens +import Control.Monad hiding (fmap) +import qualified Data.ByteString as BS +import qualified Data.Map as Map +import Data.Monoid (Last (..)) +import Data.Proxy (Proxy (..)) +import Data.Text (Text, pack) +import qualified Data.Text as Text +import Data.Void (Void) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as Scripts +import qualified Ledger.Typed.Scripts as Scripts +import Playground.Contract +import Plutus.Abstract.OutputValue (OutputValue (..)) +import qualified Plutus.Abstract.TxUtils as TxUtils +import Plutus.Contract hiding (when) +import Plutus.Contracts.Currency as Currency +import Plutus.Contracts.LendingPool.OnChain.Core (Aave, + AaveDatum (..), + AaveRedeemer (..), + Reserve (..), + UserConfig (..)) +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Core +import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken +import Plutus.V1.Ledger.Ada (adaValueOf, + lovelaceValueOf) +import qualified Plutus.V1.Ledger.Address as Addr +import Plutus.V1.Ledger.Value as Value +import qualified PlutusTx +import qualified PlutusTx.AssocMap as AssocMap +import PlutusTx.Prelude hiding (Monoid (..), + Semigroup (..), + mconcat, unless) +import Prelude (Monoid (..), + Semigroup (..), + show, subtract) +import qualified Prelude +import Text.Printf (printf) + +data ContractResponse e a = ContractSuccess a | ContractError e | ContractPending + deriving stock (Prelude.Eq, Show, Generic) + deriving anyclass (ToJSON, FromJSON) + +instance Semigroup (ContractResponse e a) where + a <> b = b + +instance Monoid (ContractResponse e a) where + mempty = ContractPending + mappend = (<>) + +withContractResponse :: forall l a p r s. + HasEndpoint l p s + => Proxy l + -> (a -> r) + -> (p -> Contract (ContractResponse Text r) s Text a) + -> Contract (ContractResponse Text r) s Void () +withContractResponse _ g c = do + e <- runError $ do + p <- endpoint @l + _ <- tell ContractPending + errorHandler `handleError` c p + tell $ case e of + Left err -> ContractError err + Right a -> ContractSuccess $ g a + where + errorHandler e = do + logInfo @Text ("Error submiting the transaction: " <> e) + throwError e diff --git a/MetaLamp/lending-pool/src/Plutus/OutputValue.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/OutputValue.hs similarity index 92% rename from MetaLamp/lending-pool/src/Plutus/OutputValue.hs rename to MetaLamp/lending-pool/src/Plutus/Abstract/OutputValue.hs index c95a9ffa8..96fafabac 100644 --- a/MetaLamp/lending-pool/src/Plutus/OutputValue.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/OutputValue.hs @@ -3,7 +3,7 @@ {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE TemplateHaskell #-} -module Plutus.OutputValue where +module Plutus.Abstract.OutputValue where import Control.Lens (makeClassy_) import Ledger (TxOutRef, TxOutTx) diff --git a/MetaLamp/lending-pool/src/Plutus/Abstract/State.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/State.hs new file mode 100644 index 000000000..0d18d0c37 --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/State.hs @@ -0,0 +1,6 @@ +module Plutus.Abstract.State (module Export) + +where + +import Plutus.Abstract.State.Select as Export +import Plutus.Abstract.State.Update as Export diff --git a/MetaLamp/lending-pool/src/Plutus/State/Select.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/State/Select.hs similarity index 96% rename from MetaLamp/lending-pool/src/Plutus/State/Select.hs rename to MetaLamp/lending-pool/src/Plutus/Abstract/State/Select.hs index 784bbdf4d..eabb0146a 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Select.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/State/Select.hs @@ -7,7 +7,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} -module Plutus.State.Select where +module Plutus.Abstract.State.Select where import Control.Monad hiding (fmap) import qualified Data.ByteString as BS @@ -22,8 +22,8 @@ import Ledger.Constraints.TxConstraints as Constraints import qualified Ledger.Scripts as Scripts import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract +import Plutus.Abstract.OutputValue (OutputValue (..)) import Plutus.Contract hiding (when) -import Plutus.OutputValue (OutputValue (..)) import Plutus.V1.Ledger.Value import qualified PlutusTx import PlutusTx.Prelude hiding (Semigroup (..), diff --git a/MetaLamp/lending-pool/src/Plutus/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/State/Update.hs similarity index 97% rename from MetaLamp/lending-pool/src/Plutus/State/Update.hs rename to MetaLamp/lending-pool/src/Plutus/Abstract/State/Update.hs index 4c03e1ac5..b25c0d736 100644 --- a/MetaLamp/lending-pool/src/Plutus/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/State/Update.hs @@ -14,7 +14,7 @@ {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} -module Plutus.State.Update where +module Plutus.Abstract.State.Update where import Control.Monad hiding (fmap) import qualified Data.ByteString as BS @@ -31,9 +31,9 @@ import qualified Ledger.Scripts as UntypedScripts import Ledger.Typed.Scripts (DatumType, RedeemerType) import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract +import Plutus.Abstract.OutputValue (OutputValue (..)) +import qualified Plutus.Abstract.TxUtils as TxUtils import Plutus.Contract hiding (when) -import qualified Plutus.Contracts.TxUtils as TxUtils -import Plutus.OutputValue (OutputValue (..)) import Plutus.V1.Ledger.Value import PlutusTx (IsData) import qualified PlutusTx diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs similarity index 56% rename from MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs rename to MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs index e492a0311..a542e5dbd 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs @@ -7,34 +7,37 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} -module Plutus.Contracts.TxUtils where +module Plutus.Abstract.TxUtils where -import Control.Lens (review) -import Control.Monad (void) -import Data.ByteString (ByteString) -import qualified Data.Map as Map -import Data.Text (Text) -import Data.Void (Void) -import Ledger hiding (singleton) -import qualified Ledger.Constraints as Constraints -import qualified Ledger.Constraints.OnChain as Constraints -import qualified Ledger.Constraints.TxConstraints as Constraints -import Ledger.Typed.Scripts (DatumType, MonetaryPolicy, - RedeemerType, TypedValidator) -import qualified Ledger.Typed.Scripts as Scripts +import Control.Lens (review) +import Control.Monad (void) +import Data.ByteString (ByteString) +import qualified Data.Map as Map +import Data.Text (Text) +import Data.Void (Void) +import Ledger hiding (singleton) +import qualified Ledger.Constraints as Constraints +import qualified Ledger.Constraints.OnChain as Constraints +import qualified Ledger.Constraints.TxConstraints as Constraints +import Ledger.Typed.Scripts (DatumType, + MonetaryPolicy, + RedeemerType, + TypedValidator) +import qualified Ledger.Typed.Scripts as Scripts +import Plutus.Abstract.OutputValue (OutputValue (..)) import Plutus.Contract -import qualified Plutus.Contracts.FungibleToken as FungibleToken -import Plutus.OutputValue (OutputValue (..)) -import Plutus.V1.Ledger.Contexts (ScriptContext, - scriptCurrencySymbol) -import qualified Plutus.V1.Ledger.Scripts as Scripts -import Plutus.V1.Ledger.Value (AssetClass (unAssetClass), - TokenName (..), assetClass, - assetClassValue, - assetClassValueOf) +import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken +import Plutus.V1.Ledger.Contexts (ScriptContext, + scriptCurrencySymbol) +import qualified Plutus.V1.Ledger.Scripts as Scripts +import Plutus.V1.Ledger.Value (AssetClass (unAssetClass), + TokenName (..), + assetClass, + assetClassValue, + assetClassValueOf) import qualified PlutusTx -import PlutusTx.Prelude hiding (Semigroup (..)) -import Prelude (Semigroup (..)) +import PlutusTx.Prelude hiding (Semigroup (..)) +import Prelude (Semigroup (..)) import qualified Prelude type TxPair a = (Constraints.ScriptLookups a, Constraints.TxConstraints (RedeemerType a) (DatumType a)) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs deleted file mode 100644 index 583e14108..000000000 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/AToken.hs +++ /dev/null @@ -1,122 +0,0 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} - -module Plutus.Contracts.AToken where - -import Control.Monad (void) -import Data.ByteString (ByteString) -import qualified Data.Map as Map -import Data.Text (Text) -import Data.Void (Void) -import Ext.Plutus.Ledger.Contexts (scriptInputsAt) -import Ledger hiding (singleton) -import Ledger.Constraints as Constraints -import Ledger.Constraints.OnChain as Constraints -import Ledger.Constraints.TxConstraints as Constraints -import Ledger.Typed.Scripts (MonetaryPolicy) -import qualified Ledger.Typed.Scripts as Scripts -import Plutus.Contract -import Plutus.Contracts.Core (Aave, AaveScript, - Reserve (..)) -import qualified Plutus.Contracts.Core as Core -import qualified Plutus.Contracts.FungibleToken as FungibleToken -import qualified Plutus.Contracts.State as State -import qualified Plutus.Contracts.TxUtils as TxUtils -import Plutus.OutputValue (OutputValue (..)) -import Plutus.V1.Ledger.Contexts (ScriptContext, - scriptCurrencySymbol) -import qualified Plutus.V1.Ledger.Scripts as Scripts -import Plutus.V1.Ledger.Value (AssetClass (..), - TokenName (..), assetClass, - assetClassValue, - assetClassValueOf) -import qualified PlutusTx -import PlutusTx.Prelude hiding (Semigroup (..)) -import qualified PlutusTx.Semigroup as Semigroup -import Prelude (Semigroup (..)) -import qualified Prelude - -{-# INLINABLE validator #-} -validator :: ValidatorHash -> AssetClass -> TokenName -> ScriptContext -> Bool -validator aaveScript underlyingAsset aTokenName ctx = - traceIfFalse "Aave tokens mint forbidden" $ amountMinted /= 0 && amountScriptAsset == amountMinted - where - txInfo :: TxInfo - txInfo = scriptContextTxInfo ctx - aTokenCurrency :: AssetClass - aTokenCurrency = assetClass (ownCurrencySymbol ctx) aTokenName - amountAsset :: Value -> Integer - amountAsset = flip assetClassValueOf underlyingAsset - - amountMinted :: Integer - amountMinted = assetClassValueOf (txInfoForge txInfo) aTokenCurrency - - amountScriptAsset :: Integer - amountScriptAsset = - let outputValue = foldMap snd $ scriptOutputsAt aaveScript txInfo - inputValue = foldMap snd $ scriptInputsAt aaveScript txInfo - in amountAsset outputValue - amountAsset inputValue - -makeLiquidityPolicy :: ValidatorHash -> AssetClass -> MonetaryPolicy -makeLiquidityPolicy aaveScript asset = Scripts.mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| \s a t -> Scripts.wrapMonetaryPolicy $ validator s a t||]) - `PlutusTx.applyCode` - PlutusTx.liftCode aaveScript - `PlutusTx.applyCode` - PlutusTx.liftCode asset - `PlutusTx.applyCode` - PlutusTx.liftCode aToken - where - aToken = aTokenName asset - -makeAToken :: ValidatorHash -> AssetClass -> AssetClass -makeAToken aaveScript asset = assetClass (scriptCurrencySymbol $ makeLiquidityPolicy aaveScript asset) (aTokenName asset) - -{-# INLINABLE aTokenName #-} -aTokenName :: AssetClass -> TokenName -aTokenName asset = TokenName $ "a" Semigroup.<> case asset of - AssetClass (_,TokenName n) -> n - -forgeATokensFrom :: forall w s. (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text (TxUtils.TxPair AaveScript) -forgeATokensFrom aave reserve pkh amount = do - let policy = makeLiquidityPolicy (Core.aaveHash aave) (rCurrency reserve) - aTokenAmount = amount -- / rLiquidityIndex reserve -- TODO: how should we divide? - forgeValue = assetClassValue (rAToken reserve) aTokenAmount - let payment = assetClassValue (rCurrency reserve) amount - pure $ - TxUtils.mustForgeValue @AaveScript policy forgeValue - <> (Prelude.mempty, mustPayToPubKey pkh forgeValue) - <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.ReserveFundsDatum payment - -burnATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text (TxUtils.TxPair AaveScript) -burnATokensFrom aave reserve pkh amount = do - let asset = rCurrency reserve - let userConfigId = (asset, pkh) - utxos <- - Map.filter ((> 0) . flip assetClassValueOf asset . txOutValue . txOutTxOut) - <$> utxoAt (Core.aaveAddress aave) - let balance = mconcat . fmap (txOutValue . txOutTxOut) . map snd . Map.toList $ utxos - aTokenAmount = amount - remainder = assetClassValueOf balance asset - aTokenAmount - policy = makeLiquidityPolicy (Core.aaveHash aave) asset - burnValue = negate $ assetClassValue (rAToken reserve) aTokenAmount - spendInputs = (\(ref, tx) -> OutputValue ref tx (Core.WithdrawRedeemer userConfigId)) <$> Map.toList utxos - pure $ - TxUtils.mustForgeValue policy burnValue - <> TxUtils.mustSpendFromScript (Core.aaveInstance aave) spendInputs pkh (assetClassValue asset aTokenAmount) - <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.ReserveFundsDatum (assetClassValue asset remainder) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs new file mode 100644 index 000000000..fcc3d6bc6 --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs @@ -0,0 +1,83 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + +module Plutus.Contracts.LendingPool.OffChain.AToken where + +import Control.Monad (void) +import Data.ByteString (ByteString) +import qualified Data.Map as Map +import Data.Text (Text) +import Data.Void (Void) +import Ext.Plutus.Ledger.Contexts (scriptInputsAt) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import Ledger.Typed.Scripts (MonetaryPolicy) +import qualified Ledger.Typed.Scripts as Scripts +import Plutus.Abstract.OutputValue (OutputValue (..)) +import qualified Plutus.Abstract.TxUtils as TxUtils +import Plutus.Contract +import Plutus.Contracts.LendingPool.OnChain.AToken (makeLiquidityPolicy) +import Plutus.Contracts.LendingPool.OnChain.Core (Aave, AaveScript, + Reserve (..)) +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Core +import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken +import Plutus.V1.Ledger.Contexts (ScriptContext, + scriptCurrencySymbol) +import qualified Plutus.V1.Ledger.Scripts as Scripts +import Plutus.V1.Ledger.Value (AssetClass (..), + TokenName (..), + assetClass, + assetClassValue, + assetClassValueOf) +import qualified PlutusTx +import PlutusTx.Prelude hiding + (Semigroup (..)) +import qualified PlutusTx.Semigroup as Semigroup +import Prelude (Semigroup (..)) +import qualified Prelude + +forgeATokensFrom :: forall w s. (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text (TxUtils.TxPair AaveScript) +forgeATokensFrom aave reserve pkh amount = do + let policy = makeLiquidityPolicy (Core.aaveHash aave) (rCurrency reserve) + aTokenAmount = amount -- / rLiquidityIndex reserve -- TODO: how should we divide? + forgeValue = assetClassValue (rAToken reserve) aTokenAmount + let payment = assetClassValue (rCurrency reserve) amount + pure $ + TxUtils.mustForgeValue @AaveScript policy forgeValue + <> (Prelude.mempty, mustPayToPubKey pkh forgeValue) + <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.ReserveFundsDatum payment + +burnATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text (TxUtils.TxPair AaveScript) +burnATokensFrom aave reserve pkh amount = do + let asset = rCurrency reserve + let userConfigId = (asset, pkh) + utxos <- + Map.filter ((> 0) . flip assetClassValueOf asset . txOutValue . txOutTxOut) + <$> utxoAt (Core.aaveAddress aave) + let balance = mconcat . fmap (txOutValue . txOutTxOut) . map snd . Map.toList $ utxos + aTokenAmount = amount + remainder = assetClassValueOf balance asset - aTokenAmount + policy = makeLiquidityPolicy (Core.aaveHash aave) asset + burnValue = negate $ assetClassValue (rAToken reserve) aTokenAmount + spendInputs = (\(ref, tx) -> OutputValue ref tx (Core.WithdrawRedeemer userConfigId)) <$> Map.toList utxos + pure $ + TxUtils.mustForgeValue policy burnValue + <> TxUtils.mustSpendFromScript (Core.aaveInstance aave) spendInputs pkh (assetClassValue asset aTokenAmount) + <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.ReserveFundsDatum (assetClassValue asset remainder) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs new file mode 100644 index 000000000..78d3135dd --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs @@ -0,0 +1,104 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + +module Plutus.Contracts.LendingPool.OffChain.Info where + +import qualified Control.Lens as Lens +import Control.Monad hiding (fmap) +import qualified Data.ByteString as BS +import qualified Data.Map as Map +import Data.Monoid (Last (..)) +import Data.Proxy (Proxy (..)) +import Data.Text (Text, pack) +import qualified Data.Text as Text +import Data.Void (Void) +import Ext.Plutus.Ledger.Value (utxoValue) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as Scripts +import qualified Ledger.Typed.Scripts as Scripts +import Playground.Contract +import Plutus.Abstract.ContractResponse (ContractResponse, + withContractResponse) +import Plutus.Abstract.OutputValue (OutputValue (..)) +import qualified Plutus.Abstract.TxUtils as TxUtils +import Plutus.Contract hiding (when) +import Plutus.Contracts.Currency as Currency +import qualified Plutus.Contracts.LendingPool.OffChain.AToken as AToken +import qualified Plutus.Contracts.LendingPool.OffChain.State as State +import Plutus.Contracts.LendingPool.OnChain.Core (Aave, + AaveDatum (..), + AaveRedeemer (..), + Reserve (..), + UserConfig (..)) +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Core +import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken +import qualified Plutus.Contracts.Service.Oracle as Oracle +import Plutus.V1.Ledger.Ada (adaValueOf, + lovelaceValueOf) +import qualified Plutus.V1.Ledger.Address as Addr +import Plutus.V1.Ledger.Value as Value +import qualified PlutusTx +import qualified PlutusTx.AssocMap as AssocMap +import PlutusTx.Prelude hiding + (Monoid (..), + Semigroup (..), + mconcat, unless) +import Prelude (Monoid (..), + Semigroup (..), + show, subtract) +import qualified Prelude +import Text.Printf (printf) + +-- | Gets current Lending Pool reserves state +reserves :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map AssetClass Reserve) +reserves aave = ovValue <$> State.findAaveReserves aave + +-- | Gets current Lending Pool user configs state +users :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) +users aave = ovValue <$> State.findAaveUserConfigs aave + +fundsAt :: HasBlockchainActions s => PubKeyHash -> Contract w s Text Value +fundsAt pkh = utxoValue <$> utxoAt (pubKeyHashAddress pkh) + +-- | Gets all UTxOs belonging to the Lending Pool script and concats them into one Value +poolFunds :: HasBlockchainActions s => Aave -> Contract w s Text Value +poolFunds aave = utxoValue <$> utxoAt (Core.aaveAddress aave) + +type AaveInfoSchema = + BlockchainActions + .\/ Endpoint "fundsAt" PubKeyHash + .\/ Endpoint "poolFunds" () + .\/ Endpoint "reserves" () + .\/ Endpoint "users" () + +data InfoContractState = + FundsAt Value + | PoolFunds Value + | Reserves (AssocMap.Map AssetClass Reserve) + | Users (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) + deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) + +infoEndpoints :: Aave -> Contract (ContractResponse Text InfoContractState) AaveInfoSchema Void () +infoEndpoints aave = forever $ + withContractResponse (Proxy @"fundsAt") FundsAt fundsAt + `select` withContractResponse (Proxy @"poolFunds") PoolFunds (const $ poolFunds aave) + `select` withContractResponse (Proxy @"reserves") Reserves (const $ reserves aave) + `select` withContractResponse (Proxy @"users") Users (const $ users aave) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Owner.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Owner.hs new file mode 100644 index 000000000..ca2cb309f --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Owner.hs @@ -0,0 +1,128 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + +module Plutus.Contracts.LendingPool.OffChain.Owner where + +import qualified Control.Lens as Lens +import Control.Monad hiding (fmap) +import qualified Data.ByteString as BS +import qualified Data.Map as Map +import Data.Monoid (Last (..)) +import Data.Proxy (Proxy (..)) +import Data.Text (Text, pack) +import qualified Data.Text as Text +import Data.Void (Void) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as Scripts +import qualified Ledger.Typed.Scripts as Scripts +import Playground.Contract +import Plutus.Abstract.ContractResponse (ContractResponse, + withContractResponse) +import Plutus.Abstract.OutputValue (OutputValue (..)) +import qualified Plutus.Abstract.TxUtils as TxUtils +import Plutus.Contract hiding (when) +import Plutus.Contracts.Currency as Currency +import qualified Plutus.Contracts.LendingPool.OffChain.State as State +import qualified Plutus.Contracts.LendingPool.OnChain.AToken as AToken +import Plutus.Contracts.LendingPool.OnChain.Core (Aave, + AaveDatum (..), + AaveRedeemer (..), + Reserve (..), + UserConfig (..)) +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Core +import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken +import qualified Plutus.Contracts.Service.Oracle as Oracle +import Plutus.V1.Ledger.Ada (adaValueOf, + lovelaceValueOf) +import qualified Plutus.V1.Ledger.Address as Addr +import Plutus.V1.Ledger.Value as Value +import qualified PlutusTx +import qualified PlutusTx.AssocMap as AssocMap +import PlutusTx.Prelude hiding + (Monoid (..), + Semigroup (..), + mconcat, unless) +import Prelude (Monoid (..), + Semigroup (..), + show, subtract) +import qualified Prelude +import Text.Printf (printf) + +data CreateParams = + CreateParams + { cpAsset :: AssetClass, + cpOracle :: Oracle.Oracle + } + deriving stock (Prelude.Eq, Show, Generic) + deriving anyclass (FromJSON, ToJSON, ToSchema) + +PlutusTx.makeLift ''CreateParams + +createReserve :: Aave -> CreateParams -> Reserve +createReserve aave CreateParams {..} = + Reserve + { rCurrency = cpAsset, + rAmount = 0, + rAToken = AToken.makeAToken (Core.aaveHash aave) cpAsset, + rLiquidityIndex = 1, + rCurrentStableBorrowRate = 11 % 10, -- TODO configure borrow rate when lending core will be ready + rTrustedOracle = Oracle.toTuple cpOracle + } + +-- | Starts the Lending Pool protocol: minting pool NFTs, creating empty user configuration state and all specified liquidity reserves +start :: HasBlockchainActions s => [CreateParams] -> Contract w s Text Aave +start = start' $ do + pkh <- pubKeyHash <$> ownPubKey + fmap Currency.currencySymbol $ + mapError (pack . show @Currency.CurrencyError) $ + Currency.forgeContract pkh [(Core.aaveProtocolName, 1)] + +start' :: HasBlockchainActions s => Contract w s Text CurrencySymbol -> [CreateParams] -> Contract w s Text Aave +start' getAaveToken params = do + aaveToken <- getAaveToken + pkh <- pubKeyHash <$> ownPubKey + let aave = Core.aave aaveToken + payment = assetClassValue (Core.aaveProtocolInst aave) 1 + let aaveTokenTx = TxUtils.mustPayToScript (Core.aaveInstance aave) pkh (Core.LendingPoolDatum pkh) payment + -- TODO how to ensure that newly minted owner token is paid to the script before someone else spends it? + ledgerTx <- TxUtils.submitTxPair aaveTokenTx + void $ awaitTxConfirmed $ txId ledgerTx + + let reserveMap = AssocMap.fromList $ fmap (\params -> (cpAsset params, createReserve aave params)) params + reservesTx <- State.putReserves aave Core.StartRedeemer reserveMap + ledgerTx <- TxUtils.submitTxPair reservesTx + void $ awaitTxConfirmed $ txId ledgerTx + userConfigsTx <- State.putUserConfigs aave Core.StartRedeemer AssocMap.empty + ledgerTx <- TxUtils.submitTxPair userConfigsTx + void $ awaitTxConfirmed $ txId ledgerTx + + logInfo @Prelude.String $ printf "started Aave %s at address %s" (show aave) (show $ Core.aaveAddress aave) + pure aave + +type AaveOwnerSchema = + BlockchainActions + .\/ Endpoint "start" [CreateParams] + +data OwnerContractState = Started Aave + deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) + +ownerEndpoints :: Contract (ContractResponse Text OwnerContractState) AaveOwnerSchema Void () +ownerEndpoints = forever $ withContractResponse (Proxy @"start") Started start diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/State.hs similarity index 65% rename from MetaLamp/lending-pool/src/Plutus/Contracts/State.hs rename to MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/State.hs index 8fefc843a..4a4211b5e 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/State.hs @@ -8,59 +8,64 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} -module Plutus.Contracts.State where +module Plutus.Contracts.LendingPool.OffChain.State where import Control.Lens -import Control.Monad hiding (fmap) -import qualified Data.ByteString as BS -import qualified Data.Map as Map -import Data.Monoid (Last (..)) -import Data.Proxy (Proxy (..)) -import Data.Text (Text, pack) -import qualified Data.Text as Text -import Data.Void (Void) -import Ledger hiding (singleton) -import Ledger.Constraints as Constraints -import Ledger.Constraints.OnChain as Constraints -import Ledger.Constraints.TxConstraints as Constraints -import qualified Ledger.Scripts as Scripts -import qualified Ledger.Typed.Scripts as Scripts +import Control.Monad hiding (fmap) +import qualified Data.ByteString as BS +import qualified Data.Map as Map +import Data.Monoid (Last (..)) +import Data.Proxy (Proxy (..)) +import Data.Text (Text, pack) +import qualified Data.Text as Text +import Data.Void (Void) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as Scripts +import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract -import Plutus.Contract hiding (when) -import Plutus.Contracts.Core (Aave (..), AaveDatum (..), - AaveRedeemer (..), - AaveScript, Reserve (..), - UserConfig (..)) -import qualified Plutus.Contracts.Core as Core -import Plutus.Contracts.Currency as Currency -import qualified Plutus.Contracts.FungibleToken as FungibleToken -import qualified Plutus.Contracts.TxUtils as TxUtils -import Plutus.OutputValue (OutputValue (..), _ovValue) -import qualified Plutus.State.Select as Select -import Plutus.State.Update (PutStateHandle (..), - StateHandle (..)) -import qualified Plutus.State.Update as Update -import Plutus.V1.Ledger.Ada (adaValueOf, lovelaceValueOf) -import Plutus.V1.Ledger.Value as Value +import Plutus.Abstract.OutputValue (OutputValue (..), + _ovValue) +import qualified Plutus.Abstract.State as State +import Plutus.Abstract.State.Update (PutStateHandle (..), + StateHandle (..)) +import qualified Plutus.Abstract.TxUtils as TxUtils +import Plutus.Contract hiding (when) +import Plutus.Contracts.Currency as Currency +import Plutus.Contracts.LendingPool.OnChain.Core (Aave (..), + AaveDatum (..), + AaveRedeemer (..), + AaveScript, + Reserve (..), + UserConfig (..)) +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Core +import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken +import Plutus.V1.Ledger.Ada (adaValueOf, + lovelaceValueOf) +import Plutus.V1.Ledger.Value as Value import qualified PlutusTx -import qualified PlutusTx.AssocMap as AssocMap -import PlutusTx.Prelude hiding (Functor (..), - Semigroup (..), unless) -import Prelude (Semigroup (..), fmap) +import qualified PlutusTx.AssocMap as AssocMap +import PlutusTx.Prelude hiding (Functor (..), + Semigroup (..), + unless) +import Prelude (Semigroup (..), + fmap) import qualified Prelude findOutputsBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text [OutputValue a] -findOutputsBy aave = Select.findOutputsBy (Core.aaveAddress aave) +findOutputsBy aave = State.findOutputsBy (Core.aaveAddress aave) findOutputBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text (OutputValue a) -findOutputBy aave = Select.findOutputBy (Core.aaveAddress aave) +findOutputBy aave = State.findOutputBy (Core.aaveAddress aave) findAaveOwnerToken :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue PubKeyHash) findAaveOwnerToken aave@Aave{..} = findOutputBy aave aaveProtocolInst (^? Core._LendingPoolDatum) reserveStateToken, userStateToken :: Aave -> AssetClass -reserveStateToken aave = Update.makeStateToken (Core.aaveHash aave) (aaveProtocolInst aave) "aaveReserve" -userStateToken aave = Update.makeStateToken (Core.aaveHash aave) (aaveProtocolInst aave) "aaveUser" +reserveStateToken aave = State.makeStateToken (Core.aaveHash aave) (aaveProtocolInst aave) "aaveReserve" +userStateToken aave = State.makeStateToken (Core.aaveHash aave) (aaveProtocolInst aave) "aaveUser" findAaveReserves :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map AssetClass Reserve)) findAaveReserves aave = findOutputBy aave (reserveStateToken aave) (^? Core._ReservesDatum . _2) @@ -81,13 +86,13 @@ findAaveUserConfig aave userConfigId = do putState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> a -> Contract w s Text (TxUtils.TxPair AaveScript) putState aave stateHandle newState = do ownerTokenOutput <- fmap Core.LendingPoolDatum <$> findAaveOwnerToken aave - Update.putState + State.putState PutStateHandle { script = Core.aaveInstance aave, ownerToken = aaveProtocolInst aave, ownerTokenOutput = ownerTokenOutput } stateHandle newState updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> OutputValue a -> Contract w s Text (TxUtils.TxPair AaveScript, a) -updateState aave = Update.updateState (Core.aaveInstance aave) +updateState aave = State.updateState (Core.aaveInstance aave) makeReserveHandle :: Aave -> (AssocMap.Map AssetClass Reserve -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map AssetClass Reserve) makeReserveHandle aave toRedeemer = diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs similarity index 63% rename from MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs rename to MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs index 8c3bb8610..b2c97dc9b 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Endpoints.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs @@ -16,170 +16,56 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} -module Plutus.Contracts.Endpoints where - -import qualified Control.Lens as Lens -import Control.Monad hiding (fmap) -import qualified Data.ByteString as BS -import qualified Data.Map as Map -import Data.Monoid (Last (..)) -import Data.Proxy (Proxy (..)) -import Data.Text (Text, pack) -import qualified Data.Text as Text -import Data.Void (Void) -import Ledger hiding (singleton) -import Ledger.Constraints as Constraints -import Ledger.Constraints.OnChain as Constraints -import Ledger.Constraints.TxConstraints as Constraints -import qualified Ledger.Scripts as Scripts -import qualified Ledger.Typed.Scripts as Scripts +module Plutus.Contracts.LendingPool.OffChain.User where + +import qualified Control.Lens as Lens +import Control.Monad hiding (fmap) +import qualified Data.ByteString as BS +import qualified Data.Map as Map +import Data.Monoid (Last (..)) +import Data.Proxy (Proxy (..)) +import Data.Text (Text, pack) +import qualified Data.Text as Text +import Data.Void (Void) +import Ext.Plutus.Ledger.Value (utxoValue) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as Scripts +import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract -import Plutus.Contract hiding (when) -import qualified Plutus.Contracts.AToken as AToken -import Plutus.Contracts.Core (Aave, AaveDatum (..), - AaveRedeemer (..), - Reserve (..), - UserConfig (..)) -import qualified Plutus.Contracts.Core as Core -import Plutus.Contracts.Currency as Currency -import qualified Plutus.Contracts.FungibleToken as FungibleToken -import qualified Plutus.Contracts.Oracle as Oracle -import qualified Plutus.Contracts.State as State -import qualified Plutus.Contracts.TxUtils as TxUtils -import Plutus.OutputValue (OutputValue (..)) -import Plutus.V1.Ledger.Ada (adaValueOf, lovelaceValueOf) -import qualified Plutus.V1.Ledger.Address as Addr -import Plutus.V1.Ledger.Value as Value +import Plutus.Abstract.ContractResponse (ContractResponse, + withContractResponse) +import Plutus.Abstract.OutputValue (OutputValue (..)) +import qualified Plutus.Abstract.TxUtils as TxUtils +import Plutus.Contract hiding (when) +import Plutus.Contracts.Currency as Currency +import qualified Plutus.Contracts.LendingPool.OffChain.AToken as AToken +import qualified Plutus.Contracts.LendingPool.OffChain.State as State +import Plutus.Contracts.LendingPool.OnChain.Core (Aave, + AaveDatum (..), + AaveRedeemer (..), + Reserve (..), + UserConfig (..)) +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Core +import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken +import qualified Plutus.Contracts.Service.Oracle as Oracle +import Plutus.V1.Ledger.Ada (adaValueOf, + lovelaceValueOf) +import qualified Plutus.V1.Ledger.Address as Addr +import Plutus.V1.Ledger.Value as Value import qualified PlutusTx -import qualified PlutusTx.AssocMap as AssocMap -import PlutusTx.Prelude hiding (Monoid (..), - Semigroup (..), mconcat, - unless) -import Prelude (Monoid (..), Semigroup (..), - show, subtract) +import qualified PlutusTx.AssocMap as AssocMap +import PlutusTx.Prelude hiding + (Monoid (..), + Semigroup (..), + mconcat, unless) +import Prelude (Monoid (..), + Semigroup (..), + show, subtract) import qualified Prelude -import Text.Printf (printf) - -data CreateParams = - CreateParams - { cpAsset :: AssetClass, - cpOracle :: Oracle.Oracle - } - deriving stock (Prelude.Eq, Show, Generic) - deriving anyclass (FromJSON, ToJSON, ToSchema) - -PlutusTx.makeLift ''CreateParams - -createReserve :: Aave -> CreateParams -> Reserve -createReserve aave CreateParams {..} = - Reserve - { rCurrency = cpAsset, - rAmount = 0, - rAToken = AToken.makeAToken (Core.aaveHash aave) cpAsset, - rLiquidityIndex = 1, - rCurrentStableBorrowRate = 11 % 10, -- TODO configure borrow rate when lending core will be ready - rTrustedOracle = Oracle.toTuple cpOracle - } - --- | Starts the Lending Pool protocol: minting pool NFTs, creating empty user configuration state and all specified liquidity reserves -start :: HasBlockchainActions s => [CreateParams] -> Contract w s Text Aave -start = start' $ do - pkh <- pubKeyHash <$> ownPubKey - fmap Currency.currencySymbol $ - mapError (pack . show @Currency.CurrencyError) $ - Currency.forgeContract pkh [(Core.aaveProtocolName, 1)] - -start' :: HasBlockchainActions s => Contract w s Text CurrencySymbol -> [CreateParams] -> Contract w s Text Aave -start' getAaveToken params = do - aaveToken <- getAaveToken - pkh <- pubKeyHash <$> ownPubKey - let aave = Core.aave aaveToken - payment = assetClassValue (Core.aaveProtocolInst aave) 1 - let aaveTokenTx = TxUtils.mustPayToScript (Core.aaveInstance aave) pkh (Core.LendingPoolDatum pkh) payment - -- TODO how to ensure that newly minted owner token is paid to the script before someone else spends it? - ledgerTx <- TxUtils.submitTxPair aaveTokenTx - void $ awaitTxConfirmed $ txId ledgerTx - - let reserveMap = AssocMap.fromList $ fmap (\params -> (cpAsset params, createReserve aave params)) params - reservesTx <- State.putReserves aave Core.StartRedeemer reserveMap - ledgerTx <- TxUtils.submitTxPair reservesTx - void $ awaitTxConfirmed $ txId ledgerTx - userConfigsTx <- State.putUserConfigs aave Core.StartRedeemer AssocMap.empty - ledgerTx <- TxUtils.submitTxPair userConfigsTx - void $ awaitTxConfirmed $ txId ledgerTx - - logInfo @Prelude.String $ printf "started Aave %s at address %s" (show aave) (show $ Core.aaveAddress aave) - pure aave - -data ContractResponse e a = ContractSuccess a | ContractError e | ContractPending - deriving stock (Prelude.Eq, Show, Generic) - deriving anyclass (ToJSON, FromJSON) - -instance Semigroup (ContractResponse e a) where - a <> b = b - -instance Monoid (ContractResponse e a) where - mempty = ContractPending - mappend = (<>) - -handleContract :: forall l a p r s. - HasEndpoint l p s - => Proxy l - -> (a -> r) - -> (p -> Contract (ContractResponse Text r) s Text a) - -> Contract (ContractResponse Text r) s Void () -handleContract _ g c = do - e <- runError $ do - p <- endpoint @l - _ <- tell ContractPending - errorHandler `handleError` c p - tell $ case e of - Left err -> ContractError err - Right a -> ContractSuccess $ g a - where - errorHandler e = do - logInfo @Text ("Error submiting the transaction: " <> e) - throwError e - -type AaveOwnerSchema = - BlockchainActions - .\/ Endpoint "start" [CreateParams] - -data OwnerContractState = Started Aave - deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) - -ownerEndpoints :: Contract (ContractResponse Text OwnerContractState) AaveOwnerSchema Void () -ownerEndpoints = forever $ handleContract (Proxy @"start") Started start - --- | Gets current Lending Pool reserves state -reserves :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map AssetClass Reserve) -reserves aave = ovValue <$> State.findAaveReserves aave - --- | Gets current Lending Pool user configs state -users :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -users aave = ovValue <$> State.findAaveUserConfigs aave - -valueAt :: HasBlockchainActions s => Address -> Contract w s Text Value -valueAt address = do - os <- map snd . Map.toList <$> utxoAt address - pure $ mconcat [txOutValue $ txOutTxOut o | o <- os] - -getOwnPubKey :: HasBlockchainActions s => Contract w s Text PubKeyHash -getOwnPubKey = pubKeyHash <$> ownPubKey - --- | Gets all UTxOs belonging to a user and concats them into one Value -fundsAt :: HasBlockchainActions s => PubKeyHash -> Contract w s Text Value -fundsAt pkh = valueAt (pubKeyHashAddress pkh) - -balanceAt :: HasBlockchainActions s => PubKeyHash -> AssetClass -> Contract w s Text Integer -balanceAt pkh asset = flip assetClassValueOf asset <$> fundsAt pkh - --- | Gets all UTxOs belonging to the Lending Pool script and concats them into one Value -poolFunds :: HasBlockchainActions s => Aave -> Contract w s Text Value -poolFunds aave = valueAt (Core.aaveAddress aave) - -ownPubKeyBalance :: HasBlockchainActions s => Contract w s Text Value -ownPubKeyBalance = getOwnPubKey >>= fundsAt +import Text.Printf (printf) data DepositParams = DepositParams { @@ -355,6 +241,13 @@ data ProvideCollateralParams = PlutusTx.unstableMakeIsData ''ProvideCollateralParams PlutusTx.makeLift ''ProvideCollateralParams +-- | Gets all UTxOs belonging to a user and concats them into one Value +fundsAt :: HasBlockchainActions s => PubKeyHash -> Contract w s Text Value +fundsAt pkh = utxoValue <$> utxoAt (pubKeyHashAddress pkh) + +balanceAt :: HasBlockchainActions s => PubKeyHash -> AssetClass -> Contract w s Text Integer +balanceAt pkh asset = flip assetClassValueOf asset <$> fundsAt pkh + -- | User deposits N amount of aToken as collateral, his investment entry state is increased by N provideCollateral :: (HasBlockchainActions s) => Aave -> ProvideCollateralParams -> Contract w s Text () provideCollateral aave ProvideCollateralParams {..} = do @@ -440,6 +333,13 @@ revokeCollateral aave RevokeCollateralParams {..} = do getUsersCollateral :: AssetClass -> TxOutTx -> Bool getUsersCollateral asset tx = ((> 0) . flip assetClassValueOf asset . txOutValue . txOutTxOut $ tx) && (txOutDatumHash . txOutTxOut $ tx) == Just (datumHash . Datum . PlutusTx.toData $ userDatum asset) + +getOwnPubKey :: HasBlockchainActions s => Contract w s Text PubKeyHash +getOwnPubKey = pubKeyHash <$> ownPubKey + +ownPubKeyBalance :: HasBlockchainActions s => Contract w s Text Value +ownPubKeyBalance = getOwnPubKey >>= fundsAt + type AaveUserSchema = BlockchainActions .\/ Endpoint "deposit" DepositParams @@ -467,32 +367,11 @@ Lens.makeClassyPrisms ''UserContractState -- TODO ? add repayWithCollateral userEndpoints :: Aave -> Contract (ContractResponse Text UserContractState) AaveUserSchema Void () userEndpoints aave = forever $ - handleContract (Proxy @"deposit") (const Deposited) (deposit aave) - `select` handleContract (Proxy @"withdraw") (const Withdrawn) (withdraw aave) - `select` handleContract (Proxy @"borrow") (const Borrowed) (borrow aave) - `select` handleContract (Proxy @"repay") (const Repaid) (repay aave) - `select` handleContract (Proxy @"provideCollateral") (const CollateralProvided) (provideCollateral aave) - `select` handleContract (Proxy @"revokeCollateral") (const CollateralRevoked) (revokeCollateral aave) - `select` handleContract (Proxy @"ownPubKey") GetPubKey (const getOwnPubKey) - `select` handleContract (Proxy @"ownPubKeyBalance") GetPubKeyBalance (const ownPubKeyBalance) - -type AaveInfoSchema = - BlockchainActions - .\/ Endpoint "fundsAt" PubKeyHash - .\/ Endpoint "poolFunds" () - .\/ Endpoint "reserves" () - .\/ Endpoint "users" () - -data InfoContractState = - FundsAt Value - | PoolFunds Value - | Reserves (AssocMap.Map AssetClass Reserve) - | Users (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) - deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) - -infoEndpoints :: Aave -> Contract (ContractResponse Text InfoContractState) AaveInfoSchema Void () -infoEndpoints aave = forever $ - handleContract (Proxy @"fundsAt") FundsAt fundsAt - `select` handleContract (Proxy @"poolFunds") PoolFunds (const $ poolFunds aave) - `select` handleContract (Proxy @"reserves") Reserves (const $ reserves aave) - `select` handleContract (Proxy @"users") Users (const $ users aave) + withContractResponse (Proxy @"deposit") (const Deposited) (deposit aave) + `select` withContractResponse (Proxy @"withdraw") (const Withdrawn) (withdraw aave) + `select` withContractResponse (Proxy @"borrow") (const Borrowed) (borrow aave) + `select` withContractResponse (Proxy @"repay") (const Repaid) (repay aave) + `select` withContractResponse (Proxy @"provideCollateral") (const CollateralProvided) (provideCollateral aave) + `select` withContractResponse (Proxy @"revokeCollateral") (const CollateralRevoked) (revokeCollateral aave) + `select` withContractResponse (Proxy @"ownPubKey") GetPubKey (const getOwnPubKey) + `select` withContractResponse (Proxy @"ownPubKeyBalance") GetPubKeyBalance (const ownPubKeyBalance) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/AToken.hs new file mode 100644 index 000000000..16f883817 --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/AToken.hs @@ -0,0 +1,94 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} + +module Plutus.Contracts.LendingPool.OnChain.AToken where + +import Control.Monad (void) +import Data.ByteString (ByteString) +import qualified Data.Map as Map +import Data.Text (Text) +import Data.Void (Void) +import Ext.Plutus.Ledger.Contexts (scriptInputsAt) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import Ledger.Typed.Scripts (MonetaryPolicy) +import qualified Ledger.Typed.Scripts as Scripts +import Plutus.Abstract.OutputValue (OutputValue (..)) +import qualified Plutus.Abstract.TxUtils as TxUtils +import Plutus.Contract +import Plutus.Contracts.LendingPool.OnChain.Core (Aave, AaveScript, + Reserve (..)) +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Core +import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken +import Plutus.V1.Ledger.Contexts (ScriptContext, + scriptCurrencySymbol) +import qualified Plutus.V1.Ledger.Scripts as Scripts +import Plutus.V1.Ledger.Value (AssetClass (..), + TokenName (..), + assetClass, + assetClassValue, + assetClassValueOf) +import qualified PlutusTx +import PlutusTx.Prelude hiding + (Semigroup (..)) +import qualified PlutusTx.Semigroup as Semigroup +import Prelude (Semigroup (..)) +import qualified Prelude + +{-# INLINABLE validator #-} +validator :: ValidatorHash -> AssetClass -> TokenName -> ScriptContext -> Bool +validator aaveScript underlyingAsset aTokenName ctx = + traceIfFalse "Aave tokens mint forbidden" $ amountMinted /= 0 && amountScriptAsset == amountMinted + where + txInfo :: TxInfo + txInfo = scriptContextTxInfo ctx + aTokenCurrency :: AssetClass + aTokenCurrency = assetClass (ownCurrencySymbol ctx) aTokenName + amountAsset :: Value -> Integer + amountAsset = flip assetClassValueOf underlyingAsset + + amountMinted :: Integer + amountMinted = assetClassValueOf (txInfoForge txInfo) aTokenCurrency + + amountScriptAsset :: Integer + amountScriptAsset = + let outputValue = foldMap snd $ scriptOutputsAt aaveScript txInfo + inputValue = foldMap snd $ scriptInputsAt aaveScript txInfo + in amountAsset outputValue - amountAsset inputValue + +makeLiquidityPolicy :: ValidatorHash -> AssetClass -> MonetaryPolicy +makeLiquidityPolicy aaveScript asset = Scripts.mkMonetaryPolicyScript $ + $$(PlutusTx.compile [|| \s a t -> Scripts.wrapMonetaryPolicy $ validator s a t||]) + `PlutusTx.applyCode` + PlutusTx.liftCode aaveScript + `PlutusTx.applyCode` + PlutusTx.liftCode asset + `PlutusTx.applyCode` + PlutusTx.liftCode aToken + where + aToken = aTokenName asset + +makeAToken :: ValidatorHash -> AssetClass -> AssetClass +makeAToken aaveScript asset = assetClass (scriptCurrencySymbol $ makeLiquidityPolicy aaveScript asset) (aTokenName asset) + +{-# INLINABLE aTokenName #-} +aTokenName :: AssetClass -> TokenName +aTokenName asset = TokenName $ "a" Semigroup.<> case asset of + AssetClass (_,TokenName n) -> n diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core.hs new file mode 100644 index 000000000..250f67611 --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core.hs @@ -0,0 +1,78 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# OPTIONS_GHC -fno-specialise #-} +{-# OPTIONS_GHC -fno-strictness #-} +{-# OPTIONS_GHC -fno-ignore-interface-pragmas #-} +{-# OPTIONS_GHC -fno-omit-interface-pragmas #-} +{-# OPTIONS_GHC -fobject-code #-} + +module Plutus.Contracts.LendingPool.OnChain.Core (module Plutus.Contracts.LendingPool.OnChain.Core, module Export, Aave(..), aaveInstance) where + +import Control.Lens ((^?)) +import qualified Control.Lens as Lens +import Control.Monad hiding + (fmap) +import qualified Data.ByteString as BS +import qualified Data.Map as Map +import Data.Text (Text, + pack) +import Data.Void (Void) +import Ext.Plutus.Ledger.Contexts (findOnlyOneDatumHashByValue, + findValueByDatumHash, + parseDatum, + scriptInputsAt, + valueSpentFrom) +import Ledger hiding + (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as UntypedScripts +import qualified Ledger.Typed.Scripts as Scripts +import Playground.Contract +import Plutus.Contract hiding + (when) +import Plutus.Contracts.LendingPool.OnChain.Core.Script (AaveDatum, + AaveRedeemer, + AaveScript) +import Plutus.Contracts.LendingPool.OnChain.Core.Script as Export +import Plutus.Contracts.LendingPool.OnChain.Core.Validator (Aave (..), + aaveInstance) +import qualified Plutus.Contracts.Service.Oracle as Oracle +import Plutus.V1.Ledger.Value +import qualified PlutusTx +import qualified PlutusTx.AssocMap as AssocMap +import PlutusTx.Prelude hiding + (Semigroup (..), + unless) +import Prelude (Semigroup (..)) +import qualified Prelude + +aaveProtocolName :: TokenName +aaveProtocolName = "Aave" + +aaveValidator :: Aave -> Validator +aaveValidator = Scripts.validatorScript . aaveInstance + +aaveHash :: Aave -> Ledger.ValidatorHash +aaveHash = UntypedScripts.validatorHash . aaveValidator + +aaveAddress :: Aave -> Ledger.Address +aaveAddress = Ledger.scriptAddress . aaveValidator + +aave :: CurrencySymbol -> Aave +aave protocol = Aave (assetClass protocol aaveProtocolName) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs new file mode 100644 index 000000000..6312a575d --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs @@ -0,0 +1,210 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# OPTIONS_GHC -fno-specialise #-} +{-# OPTIONS_GHC -fno-strictness #-} +{-# OPTIONS_GHC -fno-ignore-interface-pragmas #-} +{-# OPTIONS_GHC -fno-omit-interface-pragmas #-} +{-# OPTIONS_GHC -fobject-code #-} + +module Plutus.Contracts.LendingPool.OnChain.Core.Logic where + +import Control.Lens ((^?)) +import qualified Control.Lens as Lens +import Control.Monad hiding (fmap) +import qualified Data.ByteString as BS +import qualified Data.Map as Map +import Data.Text (Text, pack) +import Data.Void (Void) +import Ext.Plutus.Ledger.Contexts (findOnlyOneDatumHashByValue, + findValueByDatumHash, + parseDatum, + scriptInputsAt, + valueSpentFrom) +import Ledger hiding + (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as UntypedScripts +import qualified Ledger.Typed.Scripts as Scripts +import Playground.Contract +import Plutus.Contract hiding (when) +import Plutus.Contracts.LendingPool.OnChain.Core.Script (AaveDatum (..), + AaveRedeemer (..), + Reserve (..), + UserConfig (..)) +import qualified Plutus.Contracts.Service.Oracle as Oracle +import Plutus.V1.Ledger.Value +import qualified PlutusTx +import qualified PlutusTx.AssocMap as AssocMap +import PlutusTx.Prelude hiding + (Semigroup (..), + unless) +import Prelude (Semigroup (..)) +import qualified Prelude + +{-# INLINABLE pickUserConfigs #-} +pickUserConfigs :: AaveDatum -> Maybe (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) +pickUserConfigs (UserConfigsDatum stateToken configs) = Just (stateToken, configs) +pickUserConfigs _ = Nothing + +{-# INLINABLE pickReserves #-} +pickReserves :: AaveDatum -> Maybe (AssetClass, AssocMap.Map AssetClass Reserve) +pickReserves (ReservesDatum stateToken configs) = Just (stateToken, configs) +pickReserves _ = Nothing + +{-# INLINABLE pickUserCollateralFunds #-} +pickUserCollateralFunds :: AaveDatum -> Maybe (PubKeyHash, AssetClass) +pickUserCollateralFunds (UserCollateralFundsDatum user aTokenAsset) = Just (user, aTokenAsset) +pickUserCollateralFunds _ = Nothing + +{-# INLINABLE totalDebtAndCollateralInLovelace #-} +totalDebtAndCollateralInLovelace :: + PubKeyHash + -> AssocMap.Map AssetClass Integer + -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig + -> Maybe UserConfig +totalDebtAndCollateralInLovelace actor oracles userConfigs = + foldrM addCollateral (UserConfig 0 0) $ AssocMap.toList userConfigs + where + addCollateral :: + ((AssetClass, PubKeyHash), UserConfig) + -> UserConfig + -> Maybe UserConfig + addCollateral ((asset, user), userConfig) currentTotal + | user == actor = + (\rate -> UserConfig { + ucCollateralizedInvestment = rate * ucCollateralizedInvestment userConfig + ucCollateralizedInvestment currentTotal, + ucDebt = rate * ucDebt userConfig + ucDebt currentTotal } + ) <$> + AssocMap.lookup asset oracles + | otherwise = Just currentTotal + +{-# INLINABLE doesCollateralCoverDebt #-} +doesCollateralCoverDebt :: + PubKeyHash + -> AssocMap.Map AssetClass Integer + -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig + -> Bool +doesCollateralCoverDebt actor oracles userConfigs = maybe False (\UserConfig{..} -> ucDebt <= ucCollateralizedInvestment) $ + totalDebtAndCollateralInLovelace actor oracles userConfigs + +{-# INLINABLE areOraclesTrusted #-} +areOraclesTrusted :: [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] + -> AssocMap.Map AssetClass Reserve + -> Bool +areOraclesTrusted oracles reserves = all checkOracle oracles + where + checkOracle o = let oracle = Oracle.fromTuple o in + Just oracle == (Oracle.fromTuple . rTrustedOracle <$> AssocMap.lookup (Oracle.oAsset oracle) reserves) + +{-# INLINABLE checkNegativeFundsTransformation #-} +checkNegativeFundsTransformation :: ScriptContext -> AssetClass -> PubKeyHash -> Bool +checkNegativeFundsTransformation ctx asset actor = isValidFundsChange + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + + scriptSpentValue = findValueByDatumHash scriptsDatumHash $ scriptInputsAt scriptsHash txInfo + scriptRemainderValue = findValueByDatumHash scriptsDatumHash scriptOutputs + actorSpentValue = valueSpentFrom txInfo actor + actorRemainderValue = valuePaidTo txInfo actor + + isValidFundsChange :: Bool + isValidFundsChange = + let paidAmout = assetClassValueOf actorRemainderValue asset - assetClassValueOf actorSpentValue asset + fundsChange = assetClassValueOf scriptSpentValue asset - assetClassValueOf scriptRemainderValue asset + in fundsChange == paidAmout && fundsChange > 0 && paidAmout > 0 + +{-# INLINABLE checkNegativeReservesTransformation #-} +checkNegativeReservesTransformation :: AssetClass + -> AssocMap.Map AssetClass Reserve + -> ScriptContext + -> (AssetClass, PubKeyHash) + -> Bool +checkNegativeReservesTransformation stateToken reserves ctx (reserveId, _) = + maybe False checkreserves reservesOutputDatum + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + + reservesOutputDatumHash = + findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs + reservesOutputDatum :: + Maybe (AssetClass, AssocMap.Map AssetClass Reserve) + reservesOutputDatum = + reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves + + remainderDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo + remainderValue = (`findValueByDatumHash` scriptOutputs) <$> remainderDatumHash + + checkreserves :: (AssetClass, AssocMap.Map AssetClass Reserve) -> Bool + checkreserves (newStateToken, newReserves) = + newStateToken == stateToken && + maybe + False + checkReserveState + ((,,) <$> remainderValue <*> AssocMap.lookup reserveId reserves <*> AssocMap.lookup reserveId newReserves) + checkReserveState :: (Value, Reserve, Reserve) -> Bool + checkReserveState (value, oldState, newState) = + let fundsAmount = rAmount newState + in assetClassValueOf value reserveId == fundsAmount && fundsAmount >= 0 && checkReservesConsistency oldState newState + +{-# INLINABLE checkPositiveReservesTransformation #-} +checkPositiveReservesTransformation :: AssetClass + -> AssocMap.Map AssetClass Reserve + -> ScriptContext + -> (AssetClass, PubKeyHash) + -> Bool +checkPositiveReservesTransformation stateToken reserves ctx (reserveId, _) = maybe False checkreserves reservesOutputDatum + where + txInfo = scriptContextTxInfo ctx + (scriptsHash, scriptsDatumHash) = ownHashes ctx + scriptOutputs = scriptOutputsAt scriptsHash txInfo + + reservesOutputDatumHash = + findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs + reservesOutputDatum :: + Maybe (AssetClass, AssocMap.Map AssetClass Reserve) + reservesOutputDatum = + reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves + + investmentDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo + investmentValue = (`findValueByDatumHash` scriptOutputs) <$> investmentDatumHash + + checkreserves :: (AssetClass, AssocMap.Map AssetClass Reserve) -> Bool + checkreserves (newStateToken, newReserves) = + newStateToken == stateToken && + maybe + False + checkReserveState + ((,,) <$> investmentValue <*> AssocMap.lookup reserveId reserves <*> AssocMap.lookup reserveId newReserves) + checkReserveState :: (Value, Reserve, Reserve) -> Bool + checkReserveState (value, oldState, newState) = + let fundsChange = rAmount newState - rAmount oldState + in assetClassValueOf value reserveId == fundsChange && fundsChange > 0 && checkReservesConsistency oldState newState + +{-# INLINABLE checkReservesConsistency #-} +checkReservesConsistency :: Reserve -> Reserve -> Bool +checkReservesConsistency oldState newState = + rCurrency oldState == rCurrency newState && + rAToken oldState == rAToken newState && + rLiquidityIndex oldState == rLiquidityIndex newState && + rCurrentStableBorrowRate oldState == rCurrentStableBorrowRate newState && + Oracle.fromTuple (rTrustedOracle oldState) == Oracle.fromTuple (rTrustedOracle newState) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Script.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Script.hs new file mode 100644 index 000000000..f5e1b86b1 --- /dev/null +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Script.hs @@ -0,0 +1,126 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# OPTIONS_GHC -fno-specialise #-} +{-# OPTIONS_GHC -fno-strictness #-} +{-# OPTIONS_GHC -fno-ignore-interface-pragmas #-} +{-# OPTIONS_GHC -fno-omit-interface-pragmas #-} +{-# OPTIONS_GHC -fobject-code #-} + +module Plutus.Contracts.LendingPool.OnChain.Core.Script where + +import Control.Lens ((^?)) +import qualified Control.Lens as Lens +import Control.Monad hiding (fmap) +import qualified Data.ByteString as BS +import qualified Data.Map as Map +import Data.Text (Text, pack) +import Data.Void (Void) +import Ext.Plutus.Ledger.Contexts (findOnlyOneDatumHashByValue, + findValueByDatumHash, + parseDatum, scriptInputsAt, + valueSpentFrom) +import Ledger hiding (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as UntypedScripts +import qualified Ledger.Typed.Scripts as Scripts +import Playground.Contract +import Plutus.Contract hiding (when) +import qualified Plutus.Contracts.Service.Oracle as Oracle +import Plutus.V1.Ledger.Value +import qualified PlutusTx +import qualified PlutusTx.AssocMap as AssocMap +import PlutusTx.Prelude hiding (Semigroup (..), + unless) +import Prelude (Semigroup (..)) +import qualified Prelude + +deriving anyclass instance ToSchema Rational + +data Reserve = Reserve + { rCurrency :: AssetClass, -- reserve id + rAToken :: AssetClass, + rAmount :: Integer, + rLiquidityIndex :: Integer, + rCurrentStableBorrowRate :: Rational, + rTrustedOracle :: (CurrencySymbol, PubKeyHash, Integer, AssetClass) + } + deriving stock (Prelude.Eq, Show, Generic) + deriving anyclass (ToJSON, FromJSON) + +PlutusTx.unstableMakeIsData ''Reserve +PlutusTx.makeLift ''Reserve +Lens.makeClassy_ ''Reserve + +-- TODO (?) only aTokens pledged as collateral should accumulate interest +-- data UserConfig = UserConfig +-- { ucDebt :: [IncentivizedAmount] +-- , ucCollateralizedInvestment :: [IncentivizedAmount] +-- } +-- data IncentivizedAmount = IncentivizedAmount +-- { iaAmount :: Integer +-- , iaRate :: Rational +-- , iaSlot :: Slot +-- } + +data UserConfig = UserConfig + { + ucDebt :: Integer, + ucCollateralizedInvestment :: Integer + } + deriving stock (Prelude.Eq, Show, Generic) + deriving anyclass (ToJSON, FromJSON, ToSchema) + +PlutusTx.unstableMakeIsData ''UserConfig +PlutusTx.makeLift ''UserConfig +Lens.makeClassy_ ''UserConfig + +data AaveRedeemer = + StartRedeemer + | DepositRedeemer (AssetClass, PubKeyHash) + | WithdrawRedeemer (AssetClass, PubKeyHash) + | BorrowRedeemer (AssetClass, PubKeyHash) [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] + | RepayRedeemer (AssetClass, PubKeyHash) + | ProvideCollateralRedeemer (AssetClass, PubKeyHash) + | RevokeCollateralRedeemer (AssetClass, PubKeyHash) AssetClass [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] + deriving Show + +PlutusTx.unstableMakeIsData ''AaveRedeemer +PlutusTx.makeLift ''AaveRedeemer + +-- TODO: solve purescript generation issue with type synonyms +type UserConfigId = (AssetClass, PubKeyHash) +type LendingPoolOperator = PubKeyHash +type Oracles = AssocMap.Map AssetClass Integer -- Shows how many lovelaces should be paid for a specific asset + +data AaveDatum = + LendingPoolDatum LendingPoolOperator + | ReservesDatum AssetClass (AssocMap.Map AssetClass Reserve) -- State token and reserve currency -> reserve map + | ReserveFundsDatum + | UserConfigsDatum AssetClass (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -- State token and UserConfigId -> user config map + | UserCollateralFundsDatum PubKeyHash AssetClass -- User pub key and aToken asset type + deriving stock (Show) + +PlutusTx.unstableMakeIsData ''AaveDatum +PlutusTx.makeLift ''AaveDatum +Lens.makeClassyPrisms ''AaveDatum + +data AaveScript +instance Scripts.ValidatorTypes AaveScript where + type instance RedeemerType AaveScript = AaveRedeemer + type instance DatumType AaveScript = AaveDatum diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Validator.hs similarity index 59% rename from MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs rename to MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Validator.hs index cb1687f15..775884cd2 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Validator.hs @@ -14,35 +14,56 @@ {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} - -module Plutus.Contracts.Core where - -import Control.Lens ((^?)) -import qualified Control.Lens as Lens -import Control.Monad hiding (fmap) -import qualified Data.ByteString as BS -import qualified Data.Map as Map -import Data.Text (Text, pack) -import Data.Void (Void) -import Ext.Plutus.Ledger.Contexts (findOnlyOneDatumHashByValue, - findValueByDatumHash, - parseDatum, scriptInputsAt, - valueSpentFrom) -import Ledger hiding (singleton) -import Ledger.Constraints as Constraints -import Ledger.Constraints.OnChain as Constraints -import Ledger.Constraints.TxConstraints as Constraints -import qualified Ledger.Scripts as UntypedScripts -import qualified Ledger.Typed.Scripts as Scripts +{-# OPTIONS_GHC -fno-specialise #-} +{-# OPTIONS_GHC -fno-strictness #-} +{-# OPTIONS_GHC -fno-ignore-interface-pragmas #-} +{-# OPTIONS_GHC -fno-omit-interface-pragmas #-} +{-# OPTIONS_GHC -fobject-code #-} + +module Plutus.Contracts.LendingPool.OnChain.Core.Validator (Aave(..), aaveInstance) where + +import Control.Lens ((^?)) +import qualified Control.Lens as Lens +import Control.Monad hiding (fmap) +import qualified Data.ByteString as BS +import qualified Data.Map as Map +import Data.Text (Text, pack) +import Data.Void (Void) +import Ext.Plutus.Ledger.Contexts (findOnlyOneDatumHashByValue, + findValueByDatumHash, + parseDatum, + scriptInputsAt, + valueSpentFrom) +import Ledger hiding + (singleton) +import Ledger.Constraints as Constraints +import Ledger.Constraints.OnChain as Constraints +import Ledger.Constraints.TxConstraints as Constraints +import qualified Ledger.Scripts as UntypedScripts +import qualified Ledger.Typed.Scripts as Scripts import Playground.Contract -import Plutus.Contract hiding (when) -import qualified Plutus.Contracts.Oracle as Oracle +import Plutus.Contract hiding (when) +import Plutus.Contracts.LendingPool.OnChain.Core.Logic (areOraclesTrusted, + checkNegativeFundsTransformation, + checkNegativeReservesTransformation, + checkPositiveReservesTransformation, + doesCollateralCoverDebt, + pickReserves, + pickUserCollateralFunds, + pickUserConfigs) +import Plutus.Contracts.LendingPool.OnChain.Core.Script (AaveDatum (..), + AaveRedeemer (..), + AaveScript, + Reserve (..), + UserConfig (..)) +import qualified Plutus.Contracts.Service.Oracle as Oracle import Plutus.V1.Ledger.Value import qualified PlutusTx -import qualified PlutusTx.AssocMap as AssocMap -import PlutusTx.Prelude hiding (Semigroup (..), - unless) -import Prelude (Semigroup (..)) +import qualified PlutusTx.AssocMap as AssocMap +import PlutusTx.Prelude hiding + (Semigroup (..), + unless) +import Prelude (Semigroup (..)) import qualified Prelude newtype Aave = Aave @@ -52,135 +73,13 @@ newtype Aave = Aave PlutusTx.makeLift ''Aave -deriving anyclass instance ToSchema Rational - -data Reserve = Reserve - { rCurrency :: AssetClass, -- reserve id - rAToken :: AssetClass, - rAmount :: Integer, - rLiquidityIndex :: Integer, - rCurrentStableBorrowRate :: Rational, - rTrustedOracle :: (CurrencySymbol, PubKeyHash, Integer, AssetClass) - } - deriving stock (Prelude.Eq, Show, Generic) - deriving anyclass (ToJSON, FromJSON) - -PlutusTx.unstableMakeIsData ''Reserve -PlutusTx.makeLift ''Reserve -Lens.makeClassy_ ''Reserve - --- TODO (?) only aTokens pledged as collateral should accumulate interest --- data UserConfig = UserConfig --- { ucDebt :: [IncentivizedAmount] --- , ucCollateralizedInvestment :: [IncentivizedAmount] --- } --- data IncentivizedAmount = IncentivizedAmount --- { iaAmount :: Integer --- , iaRate :: Rational --- , iaSlot :: Slot --- } - -data UserConfig = UserConfig - { - ucDebt :: Integer, - ucCollateralizedInvestment :: Integer - } - deriving stock (Prelude.Eq, Show, Generic) - deriving anyclass (ToJSON, FromJSON, ToSchema) - -PlutusTx.unstableMakeIsData ''UserConfig -PlutusTx.makeLift ''UserConfig -Lens.makeClassy_ ''UserConfig - -data AaveRedeemer = - StartRedeemer - | DepositRedeemer (AssetClass, PubKeyHash) - | WithdrawRedeemer (AssetClass, PubKeyHash) - | BorrowRedeemer (AssetClass, PubKeyHash) [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] - | RepayRedeemer (AssetClass, PubKeyHash) - | ProvideCollateralRedeemer (AssetClass, PubKeyHash) - | RevokeCollateralRedeemer (AssetClass, PubKeyHash) AssetClass [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] - deriving Show - -PlutusTx.unstableMakeIsData ''AaveRedeemer -PlutusTx.makeLift ''AaveRedeemer - --- TODO: solve purescript generation issue with type synonyms -type UserConfigId = (AssetClass, PubKeyHash) -type LendingPoolOperator = PubKeyHash -type Oracles = AssocMap.Map AssetClass Integer -- Shows how many lovelaces should be paid for a specific asset - -data AaveDatum = - LendingPoolDatum LendingPoolOperator - | ReservesDatum AssetClass (AssocMap.Map AssetClass Reserve) -- State token and reserve currency -> reserve map - | ReserveFundsDatum - | UserConfigsDatum AssetClass (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -- State token and UserConfigId -> user config map - | UserCollateralFundsDatum PubKeyHash AssetClass -- User pub key and aToken asset type - deriving stock (Show) - -PlutusTx.unstableMakeIsData ''AaveDatum -PlutusTx.makeLift ''AaveDatum -Lens.makeClassyPrisms ''AaveDatum - -{-# INLINABLE pickUserConfigs #-} -pickUserConfigs :: AaveDatum -> Maybe (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -pickUserConfigs (UserConfigsDatum stateToken configs) = Just (stateToken, configs) -pickUserConfigs _ = Nothing - -{-# INLINABLE pickReserves #-} -pickReserves :: AaveDatum -> Maybe (AssetClass, AssocMap.Map AssetClass Reserve) -pickReserves (ReservesDatum stateToken configs) = Just (stateToken, configs) -pickReserves _ = Nothing - -{-# INLINABLE pickUserCollateralFunds #-} -pickUserCollateralFunds :: AaveDatum -> Maybe (PubKeyHash, AssetClass) -pickUserCollateralFunds (UserCollateralFundsDatum user aTokenAsset) = Just (user, aTokenAsset) -pickUserCollateralFunds _ = Nothing - -{-# INLINABLE totalDebtAndCollateralInLovelace #-} -totalDebtAndCollateralInLovelace :: - PubKeyHash - -> AssocMap.Map AssetClass Integer - -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig - -> Maybe UserConfig -totalDebtAndCollateralInLovelace actor oracles userConfigs = - foldrM addCollateral (UserConfig 0 0) $ AssocMap.toList userConfigs - where - addCollateral :: - ((AssetClass, PubKeyHash), UserConfig) - -> UserConfig - -> Maybe UserConfig - addCollateral ((asset, user), userConfig) currentTotal - | user == actor = - (\rate -> UserConfig { - ucCollateralizedInvestment = rate * ucCollateralizedInvestment userConfig + ucCollateralizedInvestment currentTotal, - ucDebt = rate * ucDebt userConfig + ucDebt currentTotal } - ) <$> - AssocMap.lookup asset oracles - | otherwise = Just currentTotal - -{-# INLINABLE doesCollateralCoverDebt #-} -doesCollateralCoverDebt :: - PubKeyHash - -> AssocMap.Map AssetClass Integer - -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig - -> Bool -doesCollateralCoverDebt actor oracles userConfigs = maybe False (\UserConfig{..} -> ucDebt <= ucCollateralizedInvestment) $ - totalDebtAndCollateralInLovelace actor oracles userConfigs - -{-# INLINABLE areOraclesTrusted #-} -areOraclesTrusted :: [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] - -> AssocMap.Map AssetClass Reserve - -> Bool -areOraclesTrusted oracles reserves = all checkOracle oracles +aaveInstance :: Aave -> Scripts.TypedValidator AaveScript +aaveInstance aave = Scripts.mkTypedValidator @AaveScript + ($$(PlutusTx.compile [|| makeAaveValidator ||]) + `PlutusTx.applyCode` PlutusTx.liftCode aave) + $$(PlutusTx.compile [|| wrap ||]) where - checkOracle o = let oracle = Oracle.fromTuple o in - Just oracle == (Oracle.fromTuple . rTrustedOracle <$> AssocMap.lookup (Oracle.oAsset oracle) reserves) - -data AaveScript -instance Scripts.ValidatorTypes AaveScript where - type instance RedeemerType AaveScript = AaveRedeemer - type instance DatumType AaveScript = AaveDatum + wrap = Scripts.wrapValidator @AaveDatum @AaveRedeemer {-# INLINABLE makeAaveValidator #-} -- Main validator @@ -203,6 +102,7 @@ makeAaveValidator aave datum (RepayRedeemer userConfigId) ctx = trace "RepayR makeAaveValidator aave datum (ProvideCollateralRedeemer userConfigId) ctx = trace "ProvideCollateralRedeemer" $ validateProvideCollateral aave datum ctx userConfigId makeAaveValidator aave datum (RevokeCollateralRedeemer userConfigId aTokenAsset oracles) ctx = trace "RevokeCollateralRedeemer" $ validateRevokeCollateral aave datum ctx userConfigId aTokenAsset oracles +{-# INLINABLE validateStart #-} validateStart :: Aave -> AaveDatum -> ScriptContext -> Bool validateStart aave (LendingPoolDatum operator) ctx = traceIfFalse "validateStart: Lending Pool Datum management is not authorized by operator" @@ -216,6 +116,7 @@ validateStart aave (LendingPoolDatum operator) ctx = outs -> isJust $ AssocMap.lookup scriptsDatumHash $ AssocMap.fromList outs validateStart aave _ ctx = trace "validateStart: Lending Pool Datum management is not allowed" False +{-# INLINABLE validateDeposit #-} validateDeposit :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId = traceIfFalse "validateDeposit: User Configs Datum change is not valid" isValidUserConfigsTransformation @@ -250,6 +151,7 @@ validateDeposit aave (ReservesDatum stateToken reserves) ctx userConfigId = validateDeposit _ _ _ _ = trace "validateDeposit: Lending Pool Datum management is not allowed" False +{-# INLINABLE validateWithdraw #-} validateWithdraw :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool validateWithdraw aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId = -- TODO add implementation for this case @@ -262,6 +164,7 @@ validateWithdraw aave ReserveFundsDatum ctx (reserveId, actor) = validateWithdraw _ _ _ _ = trace "validateWithdraw: Lending Pool Datum management is not allowed" False +{-# INLINABLE validateBorrow #-} validateBorrow :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] -> Bool validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) oracles = traceIfFalse "validateBorrow: User Configs Datum change is not valid" isValidUserConfigsTransformation @@ -307,6 +210,7 @@ validateBorrow aave ReserveFundsDatum ctx (reserveId, actor) oracles = validateBorrow _ _ _ _ _ = trace "validateBorrow: Lending Pool Datum management is not allowed" False +{-# INLINABLE validateRepay #-} validateRepay :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool validateRepay aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) = traceIfFalse "validateRepay: User Configs Datum change is not valid" isValidUserConfigsTransformation @@ -345,6 +249,7 @@ validateRepay aave (ReservesDatum stateToken reserves) ctx userConfigId = validateRepay _ _ _ _ = trace "validateRepay: Lending Pool Datum management is not allowed" False +{-# INLINABLE validateProvideCollateral #-} validateProvideCollateral :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool validateProvideCollateral aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) = traceIfFalse "validateProvideCollateral: User Configs Datum change is not valid" isValidUserConfigsTransformation @@ -387,6 +292,7 @@ validateProvideCollateral aave (UserConfigsDatum stateToken userConfigs) ctx us validateProvideCollateral _ _ _ _ = trace "validateProvideCollateral: Lending Pool Datum management is not allowed" False +{-# INLINABLE validateRevokeCollateral #-} validateRevokeCollateral :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> AssetClass -> [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] -> Bool validateRevokeCollateral aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) aTokenAsset oracles = traceIfFalse "validateRevokeCollateral: User Configs Datum change is not valid" isValidUserConfigsTransformation @@ -434,119 +340,3 @@ validateRevokeCollateral aave (ReservesDatum stateToken reserves) ctx userConfig traceIfFalse "validateRevokeCollateral: Reserves Datum change is not valid" $ areOraclesTrusted oracles reserves validateRevokeCollateral _ _ _ _ _ _ = trace "validateRevokeCollateral: Lending Pool Datum management is not allowed" False - -checkNegativeFundsTransformation :: ScriptContext -> AssetClass -> PubKeyHash -> Bool -checkNegativeFundsTransformation ctx asset actor = isValidFundsChange - where - txInfo = scriptContextTxInfo ctx - (scriptsHash, scriptsDatumHash) = ownHashes ctx - scriptOutputs = scriptOutputsAt scriptsHash txInfo - - scriptSpentValue = findValueByDatumHash scriptsDatumHash $ scriptInputsAt scriptsHash txInfo - scriptRemainderValue = findValueByDatumHash scriptsDatumHash scriptOutputs - actorSpentValue = valueSpentFrom txInfo actor - actorRemainderValue = valuePaidTo txInfo actor - - isValidFundsChange :: Bool - isValidFundsChange = - let paidAmout = assetClassValueOf actorRemainderValue asset - assetClassValueOf actorSpentValue asset - fundsChange = assetClassValueOf scriptSpentValue asset - assetClassValueOf scriptRemainderValue asset - in fundsChange == paidAmout && fundsChange > 0 && paidAmout > 0 - -checkNegativeReservesTransformation :: AssetClass - -> AssocMap.Map AssetClass Reserve - -> ScriptContext - -> (AssetClass, PubKeyHash) - -> Bool -checkNegativeReservesTransformation stateToken reserves ctx (reserveId, _) = - maybe False checkreserves reservesOutputDatum - where - txInfo = scriptContextTxInfo ctx - (scriptsHash, scriptsDatumHash) = ownHashes ctx - scriptOutputs = scriptOutputsAt scriptsHash txInfo - - reservesOutputDatumHash = - findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs - reservesOutputDatum :: - Maybe (AssetClass, AssocMap.Map AssetClass Reserve) - reservesOutputDatum = - reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves - - remainderDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo - remainderValue = (`findValueByDatumHash` scriptOutputs) <$> remainderDatumHash - - checkreserves :: (AssetClass, AssocMap.Map AssetClass Reserve) -> Bool - checkreserves (newStateToken, newReserves) = - newStateToken == stateToken && - maybe - False - checkReserveState - ((,,) <$> remainderValue <*> AssocMap.lookup reserveId reserves <*> AssocMap.lookup reserveId newReserves) - checkReserveState :: (Value, Reserve, Reserve) -> Bool - checkReserveState (value, oldState, newState) = - let fundsAmount = rAmount newState - in assetClassValueOf value reserveId == fundsAmount && fundsAmount >= 0 && checkReservesConsistency oldState newState - -checkPositiveReservesTransformation :: AssetClass - -> AssocMap.Map AssetClass Reserve - -> ScriptContext - -> (AssetClass, PubKeyHash) - -> Bool -checkPositiveReservesTransformation stateToken reserves ctx (reserveId, _) = maybe False checkreserves reservesOutputDatum - where - txInfo = scriptContextTxInfo ctx - (scriptsHash, scriptsDatumHash) = ownHashes ctx - scriptOutputs = scriptOutputsAt scriptsHash txInfo - - reservesOutputDatumHash = - findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs - reservesOutputDatum :: - Maybe (AssetClass, AssocMap.Map AssetClass Reserve) - reservesOutputDatum = - reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves - - investmentDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo - investmentValue = (`findValueByDatumHash` scriptOutputs) <$> investmentDatumHash - - checkreserves :: (AssetClass, AssocMap.Map AssetClass Reserve) -> Bool - checkreserves (newStateToken, newReserves) = - newStateToken == stateToken && - maybe - False - checkReserveState - ((,,) <$> investmentValue <*> AssocMap.lookup reserveId reserves <*> AssocMap.lookup reserveId newReserves) - checkReserveState :: (Value, Reserve, Reserve) -> Bool - checkReserveState (value, oldState, newState) = - let fundsChange = rAmount newState - rAmount oldState - in assetClassValueOf value reserveId == fundsChange && fundsChange > 0 && checkReservesConsistency oldState newState - -checkReservesConsistency :: Reserve -> Reserve -> Bool -checkReservesConsistency oldState newState = - rCurrency oldState == rCurrency newState && - rAToken oldState == rAToken newState && - rLiquidityIndex oldState == rLiquidityIndex newState && - rCurrentStableBorrowRate oldState == rCurrentStableBorrowRate newState && - Oracle.fromTuple (rTrustedOracle oldState) == Oracle.fromTuple (rTrustedOracle newState) - -aaveProtocolName :: TokenName -aaveProtocolName = "Aave" - -aaveInstance :: Aave -> Scripts.TypedValidator AaveScript -aaveInstance aave = Scripts.mkTypedValidator @AaveScript - ($$(PlutusTx.compile [|| makeAaveValidator ||]) - `PlutusTx.applyCode` PlutusTx.liftCode aave) - $$(PlutusTx.compile [|| wrap ||]) - where - wrap = Scripts.wrapValidator @AaveDatum @AaveRedeemer - -aaveValidator :: Aave -> Validator -aaveValidator = Scripts.validatorScript . aaveInstance - -aaveHash :: Aave -> Ledger.ValidatorHash -aaveHash = UntypedScripts.validatorHash . aaveValidator - -aaveAddress :: Aave -> Ledger.Address -aaveAddress = Ledger.scriptAddress . aaveValidator - -aave :: CurrencySymbol -> Aave -aave protocol = Aave (assetClass protocol aaveProtocolName) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/FungibleToken.hs similarity index 93% rename from MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs rename to MetaLamp/lending-pool/src/Plutus/Contracts/Service/FungibleToken.hs index fa44b7ebd..d43c2bff0 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/FungibleToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/FungibleToken.hs @@ -2,7 +2,7 @@ {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TemplateHaskell #-} -module Plutus.Contracts.FungibleToken where +module Plutus.Contracts.Service.FungibleToken where import Ledger.Typed.Scripts (MonetaryPolicy) import qualified Ledger.Typed.Scripts as Scripts diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs similarity index 88% rename from MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs rename to MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs index 472f6974a..228bdb9c9 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs @@ -15,7 +15,7 @@ {-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -fno-specialise #-} -module Plutus.Contracts.Oracle +module Plutus.Contracts.Service.Oracle ( Oracle (..) , OracleRedeemer (..) , oracleTokenName @@ -36,27 +36,26 @@ module Plutus.Contracts.Oracle , findOracleValueInTxInputs ) where -import Control.Monad hiding (fmap) -import Data.Aeson (FromJSON, ToJSON) -import qualified Data.Map as Map -import Data.Monoid (Last (..)) -import Data.Text (Text, pack) -import GHC.Generics (Generic) -import Ledger hiding (singleton) -import Ledger.Ada as Ada -import Ledger.Constraints as Constraints -import qualified Ledger.Typed.Scripts as Scripts -import Ledger.Value as Value -import Plutus.Contract as Contract hiding (when) -import Plutus.Contracts.Currency as Currency -import qualified Plutus.Contracts.TxUtils as TxUtils -import Plutus.OutputValue -import qualified Plutus.State.Select as Select +import Control.Monad hiding (fmap) +import Data.Aeson (FromJSON, ToJSON) +import qualified Data.Map as Map +import Data.Monoid (Last (..)) +import Data.Text (Text, pack) +import GHC.Generics (Generic) +import Ledger hiding (singleton) +import Ledger.Ada as Ada +import Ledger.Constraints as Constraints +import qualified Ledger.Typed.Scripts as Scripts +import Ledger.Value as Value +import Plutus.Abstract.OutputValue +import qualified Plutus.Abstract.TxUtils as TxUtils +import Plutus.Contract as Contract hiding (when) +import Plutus.Contracts.Currency as Currency import qualified PlutusTx -import PlutusTx.Prelude hiding (Semigroup (..), unless) -import Prelude (Semigroup (..)) -import qualified Prelude as Prelude -import Schema (ToSchema) +import PlutusTx.Prelude hiding (Semigroup (..), unless) +import Prelude (Semigroup (..)) +import qualified Prelude as Prelude +import Schema (ToSchema) data Oracle = Oracle { oSymbol :: CurrencySymbol diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 0d0519225..3d4a129d4 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -13,50 +13,61 @@ module Plutus.PAB.Simulation where -import Control.Monad (forM, forM_, void, when) -import Control.Monad.Freer (Eff, Member, interpret, - type (~>)) -import Control.Monad.Freer.Error (Error) -import Control.Monad.Freer.Extras.Log (LogMsg) -import Control.Monad.IO.Class (MonadIO (..)) -import Data.Aeson (FromJSON, Result (..), - ToJSON, encode, fromJSON) -import qualified Data.ByteString as BS -import qualified Data.Map.Strict as Map -import qualified Data.Monoid as Monoid -import qualified Data.Semigroup as Semigroup -import Data.Text (Text) -import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) -import GHC.Generics (Generic) +import Control.Monad (forM, forM_, void, + when) +import Control.Monad.Freer (Eff, Member, + interpret, + type (~>)) +import Control.Monad.Freer.Error (Error) +import Control.Monad.Freer.Extras.Log (LogMsg) +import Control.Monad.IO.Class (MonadIO (..)) +import Data.Aeson (FromJSON, + Result (..), + ToJSON, encode, + fromJSON) +import qualified Data.ByteString as BS +import qualified Data.Map.Strict as Map +import qualified Data.Monoid as Monoid +import qualified Data.Semigroup as Semigroup +import Data.Text (Text) +import Data.Text.Prettyprint.Doc (Pretty (..), + viaShow) +import GHC.Generics (Generic) import Ledger -import Ledger.Ada (adaSymbol, adaToken, - adaValueOf, - lovelaceValueOf) +import Ledger.Ada (adaSymbol, + adaToken, + adaValueOf, + lovelaceValueOf) import Ledger.Constraints -import qualified Ledger.Constraints.OffChain as Constraints -import qualified Ledger.Typed.Scripts as Scripts -import Ledger.Value as Value -import Plutus.Contract hiding (when) -import qualified Plutus.Contracts.Core as Aave -import Plutus.Contracts.Currency as Currency -import Plutus.Contracts.Endpoints (ContractResponse (..)) -import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Contracts.FungibleToken as FungibleToken -import qualified Plutus.Contracts.Oracle as Oracle -import Plutus.PAB.Effects.Contract (ContractEffect (..)) -import Plutus.PAB.Effects.Contract.Builtin (Builtin, SomeBuiltin (..), - type (.\\)) -import qualified Plutus.PAB.Effects.Contract.Builtin as Builtin -import Plutus.PAB.Monitoring.PABLogMsg (PABMultiAgentMsg) -import Plutus.PAB.Simulator (Simulation, - SimulatorEffectHandlers) -import qualified Plutus.PAB.Simulator as Simulator -import Plutus.PAB.Types (PABError (..)) -import qualified Plutus.PAB.Webserver.Server as PAB.Server -import Plutus.V1.Ledger.Crypto (getPubKeyHash, pubKeyHash) -import Prelude hiding (init) -import Wallet.Emulator.Types (Wallet (..), walletPubKey) -import Wallet.Types (ContractInstanceId) +import qualified Ledger.Constraints.OffChain as Constraints +import qualified Ledger.Typed.Scripts as Scripts +import Ledger.Value as Value +import Plutus.Abstract.ContractResponse (ContractResponse (..)) +import Plutus.Contract hiding (when) +import Plutus.Contracts.Currency as Currency +import qualified Plutus.Contracts.LendingPool.OffChain.Info as Aave +import qualified Plutus.Contracts.LendingPool.OffChain.Owner as Aave +import qualified Plutus.Contracts.LendingPool.OffChain.User as Aave +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave +import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken +import qualified Plutus.Contracts.Service.Oracle as Oracle +import Plutus.PAB.Effects.Contract (ContractEffect (..)) +import Plutus.PAB.Effects.Contract.Builtin (Builtin, + SomeBuiltin (..), + type (.\\)) +import qualified Plutus.PAB.Effects.Contract.Builtin as Builtin +import Plutus.PAB.Monitoring.PABLogMsg (PABMultiAgentMsg) +import Plutus.PAB.Simulator (Simulation, + SimulatorEffectHandlers) +import qualified Plutus.PAB.Simulator as Simulator +import Plutus.PAB.Types (PABError (..)) +import qualified Plutus.PAB.Webserver.Server as PAB.Server +import Plutus.V1.Ledger.Crypto (getPubKeyHash, + pubKeyHash) +import Prelude hiding (init) +import Wallet.Emulator.Types (Wallet (..), + walletPubKey) +import Wallet.Types (ContractInstanceId) ownerWallet :: Wallet ownerWallet = Wallet 1 diff --git a/MetaLamp/lending-pool/test/Fixtures.hs b/MetaLamp/lending-pool/test/Fixtures.hs index 50346037d..aa61a44d4 100644 --- a/MetaLamp/lending-pool/test/Fixtures.hs +++ b/MetaLamp/lending-pool/test/Fixtures.hs @@ -1,6 +1,6 @@ -module Fixtures (module Fixtures.Aave, module Fixtures.Asset, module Fixtures.Init, module Fixtures.Wallet) where +module Fixtures (module Export) where -import Fixtures.Aave -import Fixtures.Asset -import Fixtures.Init -import Fixtures.Wallet +import Fixtures.Aave as Export +import Fixtures.Asset as Export +import Fixtures.Init as Export +import Fixtures.Wallet as Export diff --git a/MetaLamp/lending-pool/test/Fixtures/Aave.hs b/MetaLamp/lending-pool/test/Fixtures/Aave.hs index 4b5ea3be9..95a376269 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Aave.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Aave.hs @@ -5,14 +5,15 @@ module Fixtures.Aave where -import Data.Text (Text) -import Fixtures.Symbol (forgeSymbol, getSymbol) +import Data.Text (Text) +import Fixtures.Symbol (forgeSymbol, + getSymbol) import qualified Ledger +import qualified Plutus.Abstract.TxUtils as TxUtils import Plutus.Contract -import qualified Plutus.Contracts.Core as Aave -import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Contracts.TxUtils as TxUtils -import Plutus.V1.Ledger.Value (CurrencySymbol) +import qualified Plutus.Contracts.LendingPool.OffChain.Owner as Aave +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave +import Plutus.V1.Ledger.Value (CurrencySymbol) import PlutusTx.Prelude aaveSymbol :: CurrencySymbol diff --git a/MetaLamp/lending-pool/test/Fixtures/Asset.hs b/MetaLamp/lending-pool/test/Fixtures/Asset.hs index e5e206487..032e909cd 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Asset.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Asset.hs @@ -2,10 +2,10 @@ module Fixtures.Asset where -import qualified Fixtures.Aave as AaveMock -import qualified Plutus.Contracts.AToken as AToken -import Plutus.PAB.Simulation (toAsset) -import Plutus.V1.Ledger.Value (AssetClass) +import qualified Fixtures.Aave as AaveMock +import qualified Plutus.Contracts.LendingPool.OnChain.AToken as AToken +import Plutus.PAB.Simulation (toAsset) +import Plutus.V1.Ledger.Value (AssetClass) mogus :: AssetClass mogus = toAsset "MOGUS" diff --git a/MetaLamp/lending-pool/test/Fixtures/Init.hs b/MetaLamp/lending-pool/test/Fixtures/Init.hs index 5d1d50684..a690d050f 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Init.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Init.hs @@ -2,28 +2,32 @@ module Fixtures.Init where -import Control.Monad (forM, forM_, void) -import qualified Data.Map as Map -import Data.Text (Text) -import Data.Void (Void) -import qualified Fixtures.Aave as AaveMock -import Fixtures.Asset (defaultAssets) -import Fixtures.Symbol (forgeSymbol, getSymbol) -import Fixtures.Wallet (ownerWallet, userWallets) +import Control.Monad (forM, forM_, void) +import qualified Data.Map as Map +import Data.Text (Text) +import Data.Void (Void) +import qualified Fixtures.Aave as AaveMock +import Fixtures.Asset (defaultAssets) +import Fixtures.Symbol (forgeSymbol, + getSymbol) +import Fixtures.Wallet (ownerWallet, + userWallets) +import Plutus.Abstract.ContractResponse (ContractResponse (..)) import Plutus.Contract -import qualified Plutus.Contracts.Core as Aave -import Plutus.Contracts.Endpoints (ContractResponse (..)) -import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Contracts.Oracle as Oracle -import Plutus.PAB.Simulation (distributeFunds) -import qualified Plutus.Trace.Emulator as Trace -import Plutus.V1.Ledger.Ada (lovelaceValueOf) -import Plutus.V1.Ledger.Crypto (PubKeyHash (..)) -import Plutus.V1.Ledger.Value (AssetClass (..), Value, - assetClassValue) -import qualified PlutusTx.AssocMap as AssocMap -import Utils.Data (getPubKey) -import Wallet.Emulator.Wallet (Wallet) +import qualified Plutus.Contracts.LendingPool.OffChain.Owner as Aave +import qualified Plutus.Contracts.LendingPool.OffChain.User as Aave +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave +import qualified Plutus.Contracts.Service.Oracle as Oracle +import Plutus.PAB.Simulation (distributeFunds) +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Ada (lovelaceValueOf) +import Plutus.V1.Ledger.Crypto (PubKeyHash (..)) +import Plutus.V1.Ledger.Value (AssetClass (..), + Value, + assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap +import Utils.Data (getPubKey) +import Wallet.Emulator.Wallet (Wallet) oracles :: [Oracle.Oracle] oracles = fmap diff --git a/MetaLamp/lending-pool/test/Fixtures/Symbol.hs b/MetaLamp/lending-pool/test/Fixtures/Symbol.hs index f7112a897..f765c3f74 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Symbol.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Symbol.hs @@ -13,8 +13,8 @@ import qualified Ledger import qualified Ledger.Constraints as Constraints import Ledger.Typed.Scripts (MonetaryPolicy) import qualified Ledger.Typed.Scripts as Scripts +import qualified Plutus.Abstract.TxUtils as TxUtils import Plutus.Contract -import qualified Plutus.Contracts.TxUtils as TxUtils import Plutus.V1.Ledger.Contexts (ScriptContext) import qualified Plutus.V1.Ledger.Scripts as Scripts import Plutus.V1.Ledger.Value (CurrencySymbol, TokenName, diff --git a/MetaLamp/lending-pool/test/Spec/Borrow.hs b/MetaLamp/lending-pool/test/Spec/Borrow.hs index 4e9ce0878..9f5cea74b 100644 --- a/MetaLamp/lending-pool/test/Spec/Borrow.hs +++ b/MetaLamp/lending-pool/test/Spec/Borrow.hs @@ -5,20 +5,21 @@ module Spec.Borrow where -import Control.Lens (over) -import qualified Data.Map as Map +import Control.Lens (over) +import qualified Data.Map as Map import qualified Fixtures import Plutus.Contract.Test -import qualified Plutus.Contracts.Core as Aave -import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Trace.Emulator as Trace -import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) -import qualified PlutusTx.AssocMap as AssocMap -import Spec.Deposit (deposit) -import Spec.ProvideCollateral (provideCollateral) -import qualified Spec.Shared as Shared +import qualified Plutus.Contracts.LendingPool.OffChain.User as Aave +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Value (AssetClass, + assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap +import Spec.Deposit (deposit) +import Spec.ProvideCollateral (provideCollateral) +import qualified Spec.Shared as Shared import Test.Tasty -import qualified Utils.Data as Utils +import qualified Utils.Data as Utils tests :: TestTree tests = testGroup "borrow" [ diff --git a/MetaLamp/lending-pool/test/Spec/Deposit.hs b/MetaLamp/lending-pool/test/Spec/Deposit.hs index 8b1912c08..d6bce9936 100644 --- a/MetaLamp/lending-pool/test/Spec/Deposit.hs +++ b/MetaLamp/lending-pool/test/Spec/Deposit.hs @@ -5,18 +5,19 @@ module Spec.Deposit where -import Control.Lens (over) -import qualified Data.Map as Map +import Control.Lens (over) +import qualified Data.Map as Map import qualified Fixtures import Plutus.Contract.Test -import qualified Plutus.Contracts.Core as Aave -import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Trace.Emulator as Trace -import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) -import qualified PlutusTx.AssocMap as AssocMap -import qualified Spec.Shared as Shared +import qualified Plutus.Contracts.LendingPool.OffChain.User as Aave +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Value (AssetClass, + assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap +import qualified Spec.Shared as Shared import Test.Tasty -import qualified Utils.Data as Utils +import qualified Utils.Data as Utils tests :: TestTree tests = testGroup "deposit" [ diff --git a/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs b/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs index 2781bf2c0..d19aaf695 100644 --- a/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs +++ b/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs @@ -5,19 +5,20 @@ module Spec.ProvideCollateral where -import Control.Lens (over) -import qualified Data.Map as Map +import Control.Lens (over) +import qualified Data.Map as Map import qualified Fixtures import Plutus.Contract.Test -import qualified Plutus.Contracts.Core as Aave -import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Trace.Emulator as Trace -import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) -import qualified PlutusTx.AssocMap as AssocMap -import Spec.Deposit (deposit) -import qualified Spec.Shared as Shared +import qualified Plutus.Contracts.LendingPool.OffChain.User as Aave +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Value (AssetClass, + assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap +import Spec.Deposit (deposit) +import qualified Spec.Shared as Shared import Test.Tasty -import qualified Utils.Data as Utils +import qualified Utils.Data as Utils tests :: TestTree tests = testGroup "provideCollateral" [ diff --git a/MetaLamp/lending-pool/test/Spec/Repay.hs b/MetaLamp/lending-pool/test/Spec/Repay.hs index d6a4c3993..8a43d8804 100644 --- a/MetaLamp/lending-pool/test/Spec/Repay.hs +++ b/MetaLamp/lending-pool/test/Spec/Repay.hs @@ -5,21 +5,22 @@ module Spec.Repay where -import Control.Lens (over) -import qualified Data.Map as Map +import Control.Lens (over) +import qualified Data.Map as Map import qualified Fixtures import Plutus.Contract.Test -import qualified Plutus.Contracts.Core as Aave -import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Trace.Emulator as Trace -import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) -import qualified PlutusTx.AssocMap as AssocMap -import Spec.Borrow (borrow) -import Spec.Deposit (deposit) -import Spec.ProvideCollateral (provideCollateral) -import qualified Spec.Shared as Shared +import qualified Plutus.Contracts.LendingPool.OffChain.User as Aave +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Value (AssetClass, + assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap +import Spec.Borrow (borrow) +import Spec.Deposit (deposit) +import Spec.ProvideCollateral (provideCollateral) +import qualified Spec.Shared as Shared import Test.Tasty -import qualified Utils.Data as Utils +import qualified Utils.Data as Utils tests :: TestTree tests = testGroup "repay" [ diff --git a/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs b/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs index 481b47f78..fd73eabb5 100644 --- a/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs +++ b/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs @@ -5,20 +5,21 @@ module Spec.RevokeCollateral where -import Control.Lens (over) -import qualified Data.Map as Map +import Control.Lens (over) +import qualified Data.Map as Map import qualified Fixtures import Plutus.Contract.Test -import qualified Plutus.Contracts.Core as Aave -import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Trace.Emulator as Trace -import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) -import qualified PlutusTx.AssocMap as AssocMap -import Spec.Deposit (deposit) -import Spec.ProvideCollateral (provideCollateral) -import qualified Spec.Shared as Shared +import qualified Plutus.Contracts.LendingPool.OffChain.User as Aave +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Value (AssetClass, + assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap +import Spec.Deposit (deposit) +import Spec.ProvideCollateral (provideCollateral) +import qualified Spec.Shared as Shared import Test.Tasty -import qualified Utils.Data as Utils +import qualified Utils.Data as Utils tests :: TestTree tests = testGroup "revokeCollateral" [ diff --git a/MetaLamp/lending-pool/test/Spec/Shared.hs b/MetaLamp/lending-pool/test/Spec/Shared.hs index 19bb98e98..292f133f5 100644 --- a/MetaLamp/lending-pool/test/Spec/Shared.hs +++ b/MetaLamp/lending-pool/test/Spec/Shared.hs @@ -4,13 +4,13 @@ module Spec.Shared where import qualified Fixtures -import Plutus.Contract.Test (TracePredicate) -import qualified Plutus.Contracts.Core as Aave -import Plutus.V1.Ledger.Crypto (PubKeyHash) -import Plutus.V1.Ledger.Value (AssetClass) -import qualified PlutusTx.AssocMap as AssocMap -import qualified Utils.Data as Utils -import qualified Utils.Trace as Utils +import Plutus.Contract.Test (TracePredicate) +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave +import Plutus.V1.Ledger.Crypto (PubKeyHash) +import Plutus.V1.Ledger.Value (AssetClass) +import qualified PlutusTx.AssocMap as AssocMap +import qualified Utils.Data as Utils +import qualified Utils.Trace as Utils reservesChange :: AssocMap.Map AssetClass Aave.Reserve -> TracePredicate reservesChange reserves = Utils.datumsAtAddress Fixtures.aaveAddress (Utils.one check) diff --git a/MetaLamp/lending-pool/test/Spec/Start.hs b/MetaLamp/lending-pool/test/Spec/Start.hs index bdcf491e7..cc9eeacdc 100644 --- a/MetaLamp/lending-pool/test/Spec/Start.hs +++ b/MetaLamp/lending-pool/test/Spec/Start.hs @@ -5,10 +5,10 @@ module Spec.Start where import qualified Fixtures import Plutus.Contract.Test -import qualified Plutus.Contracts.Core as Aave +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave import Test.Tasty -import qualified Utils.Data as Utils -import qualified Utils.Trace as Utils +import qualified Utils.Data as Utils +import qualified Utils.Trace as Utils tests :: TestTree tests = testGroup "start" [checkPredicate diff --git a/MetaLamp/lending-pool/test/Spec/Withdraw.hs b/MetaLamp/lending-pool/test/Spec/Withdraw.hs index a130ae3e3..acfbd225a 100644 --- a/MetaLamp/lending-pool/test/Spec/Withdraw.hs +++ b/MetaLamp/lending-pool/test/Spec/Withdraw.hs @@ -5,19 +5,20 @@ module Spec.Withdraw where -import Control.Lens (over) -import qualified Data.Map as Map +import Control.Lens (over) +import qualified Data.Map as Map import qualified Fixtures import Plutus.Contract.Test -import qualified Plutus.Contracts.Core as Aave -import qualified Plutus.Contracts.Endpoints as Aave -import qualified Plutus.Trace.Emulator as Trace -import Plutus.V1.Ledger.Value (AssetClass, assetClassValue) -import qualified PlutusTx.AssocMap as AssocMap -import Spec.Deposit (deposit) -import qualified Spec.Shared as Shared +import qualified Plutus.Contracts.LendingPool.OffChain.User as Aave +import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave +import qualified Plutus.Trace.Emulator as Trace +import Plutus.V1.Ledger.Value (AssetClass, + assetClassValue) +import qualified PlutusTx.AssocMap as AssocMap +import Spec.Deposit (deposit) +import qualified Spec.Shared as Shared import Test.Tasty -import qualified Utils.Data as Utils +import qualified Utils.Data as Utils tests :: TestTree tests = testGroup "withdraw" [ diff --git a/MetaLamp/lending-pool/test/Utils/Data.hs b/MetaLamp/lending-pool/test/Utils/Data.hs index 8fa6693de..71c620c55 100644 --- a/MetaLamp/lending-pool/test/Utils/Data.hs +++ b/MetaLamp/lending-pool/test/Utils/Data.hs @@ -1,11 +1,11 @@ module Utils.Data where -import Data.Function ((&)) -import Plutus.Contracts.Endpoints (ContractResponse (..)) -import Plutus.V1.Ledger.Crypto (PubKeyHash, pubKeyHash) -import qualified PlutusTx.AssocMap as AssocMap -import qualified PlutusTx.Prelude as PlutusTx -import Wallet.Emulator.Wallet (Wallet, walletPubKey) +import Data.Function ((&)) +import Plutus.Abstract.ContractResponse (ContractResponse (..)) +import Plutus.V1.Ledger.Crypto (PubKeyHash, pubKeyHash) +import qualified PlutusTx.AssocMap as AssocMap +import qualified PlutusTx.Prelude as PlutusTx +import Wallet.Emulator.Wallet (Wallet, walletPubKey) allSatisfy :: [a -> Bool] -> a -> Bool allSatisfy fs a = and . fmap (a &) $ fs diff --git a/MetaLamp/lending-pool/test/Utils/Trace.hs b/MetaLamp/lending-pool/test/Utils/Trace.hs index 8f9c73412..772e61495 100644 --- a/MetaLamp/lending-pool/test/Utils/Trace.hs +++ b/MetaLamp/lending-pool/test/Utils/Trace.hs @@ -5,29 +5,29 @@ module Utils.Trace where -import qualified Control.Foldl as L -import Control.Monad (unless) -import Control.Monad.Freer.Error (throwError) -import Control.Monad.Freer.Writer (tell) -import qualified Data.Aeson as JSON +import qualified Control.Foldl as L +import Control.Monad (unless) +import Control.Monad.Freer.Error (throwError) +import Control.Monad.Freer.Writer (tell) +import qualified Data.Aeson as JSON -import qualified Data.Map as Map -import Data.Maybe (mapMaybe) -import Data.Monoid (Last (..)) -import Data.String (fromString) -import Data.Text.Prettyprint.Doc (Doc) -import Data.Void (Void) -import Ledger (Address) +import qualified Data.Map as Map +import Data.Maybe (mapMaybe) +import Data.Monoid (Last (..)) +import Data.String (fromString) +import Data.Text.Prettyprint.Doc (Doc) +import Data.Void (Void) +import Ledger (Address) import qualified Ledger -import Ledger.AddressMap (UtxoMap) -import Plutus.Contract (HasBlockchainActions) -import Plutus.Contract.Test (TracePredicate) -import Plutus.Contracts.Endpoints (ContractResponse (..)) -import qualified Plutus.Trace.Emulator as Trace -import Plutus.Trace.Emulator.Types (EmulatorRuntimeError (..)) -import PlutusTx (IsData, fromData) -import qualified Wallet.Emulator.Folds as Folds -import Wallet.Emulator.MultiAgent (EmulatorEvent) +import Ledger.AddressMap (UtxoMap) +import Plutus.Abstract.ContractResponse (ContractResponse (..)) +import Plutus.Contract (HasBlockchainActions) +import Plutus.Contract.Test (TracePredicate) +import qualified Plutus.Trace.Emulator as Trace +import Plutus.Trace.Emulator.Types (EmulatorRuntimeError (..)) +import PlutusTx (IsData, fromData) +import qualified Wallet.Emulator.Folds as Folds +import Wallet.Emulator.MultiAgent (EmulatorEvent) getState :: (Show a From 4cde9677b29f1151bd7d539c177faa7fce2f526a Mon Sep 17 00:00:00 2001 From: megakaban Date: Thu, 1 Jul 2021 16:38:29 +0700 Subject: [PATCH 153/169] Fix frontend imports --- MetaLamp/lending-pool/client/src/Business/AaveInfo.purs | 2 +- MetaLamp/lending-pool/client/src/Component/MainPage.purs | 2 +- MetaLamp/lending-pool/client/src/View/ReserveInfo.purs | 2 +- MetaLamp/lending-pool/client/src/View/UsersTable.purs | 2 +- MetaLamp/lending-pool/test/Utils/Trace.hs | 1 - 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/MetaLamp/lending-pool/client/src/Business/AaveInfo.purs b/MetaLamp/lending-pool/client/src/Business/AaveInfo.purs index 6c5875051..f8d7753d7 100644 --- a/MetaLamp/lending-pool/client/src/Business/AaveInfo.purs +++ b/MetaLamp/lending-pool/client/src/Business/AaveInfo.purs @@ -8,7 +8,7 @@ import Data.Either (Either) import Data.Json.JsonTuple (JsonTuple) import Data.Maybe (Maybe) import Data.Newtype (class Newtype, unwrap) -import Plutus.Contracts.LendingPool.OnChain.Core (Reserve, UserConfig) +import Plutus.Contracts.LendingPool.OnChain.Core.Script (Reserve, UserConfig) import Plutus.Contracts.LendingPool.OffChain.Info (_FundsAt, _PoolFunds, _Reserves, _Users) import Plutus.PAB.Simulation (AaveContracts, _AaveInfo) import Plutus.PAB.Webserver.Types (ContractInstanceClientState) diff --git a/MetaLamp/lending-pool/client/src/Component/MainPage.purs b/MetaLamp/lending-pool/client/src/Component/MainPage.purs index 8891cccf9..5c6ccac86 100644 --- a/MetaLamp/lending-pool/client/src/Component/MainPage.purs +++ b/MetaLamp/lending-pool/client/src/Component/MainPage.purs @@ -28,7 +28,7 @@ import Halogen.HTML.Properties (classes) import Network.RemoteData (RemoteData(..)) import Network.RemoteData as RD import Network.RemoteData as RemoteData -import Plutus.Contracts.LendingPool.OnChain.Core (Reserve(..), UserConfig) +import Plutus.Contracts.LendingPool.OnChain.Core.Script (Reserve(..), UserConfig) import Plutus.PAB.Simulation (AaveContracts) import Plutus.PAB.Webserver.Types (ContractInstanceClientState) import Plutus.V1.Ledger.Crypto (PubKeyHash) diff --git a/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs b/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs index 67cdc9585..ee42f6df7 100644 --- a/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs +++ b/MetaLamp/lending-pool/client/src/View/ReserveInfo.purs @@ -3,7 +3,7 @@ module View.ReserveInfo where import Prelude import Data.BigInteger (BigInteger) import Halogen.HTML as HH -import Plutus.Contracts.LendingPool.OnChain.Core (Reserve(..)) +import Plutus.Contracts.LendingPool.OnChain.Core.Script (Reserve(..)) import Plutus.V1.Ledger.Value (AssetClass) import View.Utils (assetName) diff --git a/MetaLamp/lending-pool/client/src/View/UsersTable.purs b/MetaLamp/lending-pool/client/src/View/UsersTable.purs index 9a13aae10..1427dd643 100644 --- a/MetaLamp/lending-pool/client/src/View/UsersTable.purs +++ b/MetaLamp/lending-pool/client/src/View/UsersTable.purs @@ -6,7 +6,7 @@ import Data.BigInteger (fromInt) import Data.Maybe (fromMaybe) import Data.Tuple (Tuple(..)) import Halogen.HTML as HH -import Plutus.Contracts.LendingPool.OnChain.Core (UserConfig(..)) +import Plutus.Contracts.LendingPool.OnChain.Core.Script (UserConfig(..)) import Plutus.V1.Ledger.Value (AssetClass) import View.Utils (assetName) diff --git a/MetaLamp/lending-pool/test/Utils/Trace.hs b/MetaLamp/lending-pool/test/Utils/Trace.hs index 772e61495..603219669 100644 --- a/MetaLamp/lending-pool/test/Utils/Trace.hs +++ b/MetaLamp/lending-pool/test/Utils/Trace.hs @@ -13,7 +13,6 @@ import qualified Data.Aeson as JSON import qualified Data.Map as Map import Data.Maybe (mapMaybe) -import Data.Monoid (Last (..)) import Data.String (fromString) import Data.Text.Prettyprint.Doc (Doc) import Data.Void (Void) From 6367a55ac0799877430769187030a4018539779b Mon Sep 17 00:00:00 2001 From: megakaban Date: Fri, 2 Jul 2021 13:33:35 +0700 Subject: [PATCH 154/169] Remove unused pragmas --- MetaLamp/lending-pool/generate-purs/Main.hs | 1 - .../src/Plutus/Abstract/ContractResponse.hs | 28 ++++++-------- .../Contracts/LendingPool/OffChain/AToken.hs | 26 +++++-------- .../Contracts/LendingPool/OffChain/Info.hs | 28 ++++++-------- .../Contracts/LendingPool/OnChain/Core.hs | 7 ---- .../LendingPool/OnChain/Core/Logic.hs | 6 --- .../Plutus/Contracts/Service/FungibleToken.hs | 2 +- .../src/Plutus/Contracts/Service/Oracle.hs | 37 +++++++++---------- 8 files changed, 50 insertions(+), 85 deletions(-) diff --git a/MetaLamp/lending-pool/generate-purs/Main.hs b/MetaLamp/lending-pool/generate-purs/Main.hs index 8797fa049..a3d528b2a 100644 --- a/MetaLamp/lending-pool/generate-purs/Main.hs +++ b/MetaLamp/lending-pool/generate-purs/Main.hs @@ -8,7 +8,6 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} module Main where diff --git a/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs index cfde04d7a..94fb78572 100644 --- a/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs @@ -1,20 +1,14 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} module Plutus.Abstract.ContractResponse where diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs index fcc3d6bc6..4fb7f21ae 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs @@ -1,20 +1,12 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} module Plutus.Contracts.LendingPool.OffChain.AToken where diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs index 78d3135dd..54d3b6959 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs @@ -1,20 +1,14 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE GeneralizedNewtypeDeriving #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE MultiParamTypeClasses #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} -{-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} module Plutus.Contracts.LendingPool.OffChain.Info where diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core.hs index 250f67611..afd3312c1 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core.hs @@ -1,18 +1,11 @@ {-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TupleSections #-} -{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -fno-specialise #-} {-# OPTIONS_GHC -fno-strictness #-} diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs index 6312a575d..9271b5a04 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs @@ -1,6 +1,4 @@ {-# LANGUAGE DataKinds #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} @@ -9,10 +7,6 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE TupleSections #-} -{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -fno-specialise #-} {-# OPTIONS_GHC -fno-strictness #-} diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Service/FungibleToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/FungibleToken.hs index d43c2bff0..4acdc6663 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Service/FungibleToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/FungibleToken.hs @@ -8,7 +8,7 @@ import Ledger.Typed.Scripts (MonetaryPolicy) import qualified Ledger.Typed.Scripts as Scripts import Plutus.V1.Ledger.Contexts (ScriptContext) import qualified Plutus.V1.Ledger.Scripts as Scripts -import Plutus.V1.Ledger.Value (TokenName, Value) +import Plutus.V1.Ledger.Value (TokenName) import qualified PlutusTx import PlutusTx.Prelude diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs index 228bdb9c9..438ae2c4e 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs @@ -36,26 +36,25 @@ module Plutus.Contracts.Service.Oracle , findOracleValueInTxInputs ) where -import Control.Monad hiding (fmap) -import Data.Aeson (FromJSON, ToJSON) -import qualified Data.Map as Map -import Data.Monoid (Last (..)) -import Data.Text (Text, pack) -import GHC.Generics (Generic) -import Ledger hiding (singleton) -import Ledger.Ada as Ada -import Ledger.Constraints as Constraints -import qualified Ledger.Typed.Scripts as Scripts -import Ledger.Value as Value -import Plutus.Abstract.OutputValue -import qualified Plutus.Abstract.TxUtils as TxUtils -import Plutus.Contract as Contract hiding (when) -import Plutus.Contracts.Currency as Currency +import Control.Monad hiding (fmap) +import Data.Aeson (FromJSON, ToJSON) +import qualified Data.Map as Map +import Data.Monoid (Last (..)) +import Data.Text (Text, pack) +import GHC.Generics (Generic) +import Ledger hiding (singleton) +import Ledger.Ada as Ada +import Ledger.Constraints as Constraints +import qualified Ledger.Typed.Scripts as Scripts +import Ledger.Value as Value +import qualified Plutus.Abstract.TxUtils as TxUtils +import Plutus.Contract as Contract hiding (when) +import Plutus.Contracts.Currency as Currency import qualified PlutusTx -import PlutusTx.Prelude hiding (Semigroup (..), unless) -import Prelude (Semigroup (..)) -import qualified Prelude as Prelude -import Schema (ToSchema) +import PlutusTx.Prelude hiding (Semigroup (..), unless) +import Prelude (Semigroup (..)) +import qualified Prelude +import Schema (ToSchema) data Oracle = Oracle { oSymbol :: CurrencySymbol From 5af8ecbb068e16a25b8b2f0ab9e7940e2a17a1f0 Mon Sep 17 00:00:00 2001 From: megakaban Date: Fri, 2 Jul 2021 14:06:39 +0700 Subject: [PATCH 155/169] Use type synonyms --- .../Contracts/LendingPool/OffChain/State.hs | 17 ++++----- .../LendingPool/OnChain/Core/Logic.hs | 20 ++++++----- .../LendingPool/OnChain/Core/Script.hs | 19 +++++----- .../LendingPool/OnChain/Core/Validator.hs | 35 ++++++++++--------- MetaLamp/lending-pool/test/Fixtures/Init.hs | 2 +- MetaLamp/lending-pool/test/Spec/Shared.hs | 5 ++- MetaLamp/lending-pool/test/Spec/Start.hs | 1 - 7 files changed, 51 insertions(+), 48 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/State.hs index 4a4211b5e..4772d939a 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/State.hs @@ -39,7 +39,8 @@ import Plutus.Contracts.LendingPool.OnChain.Core (Aave (..), AaveRedeemer (..), AaveScript, Reserve (..), - UserConfig (..)) + UserConfig (..), + UserConfigId) import qualified Plutus.Contracts.LendingPool.OnChain.Core as Core import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken import Plutus.V1.Ledger.Ada (adaValueOf, @@ -75,10 +76,10 @@ findAaveReserve aave reserveId = do reserves <- ovValue <$> findAaveReserves aave maybe (throwError "Reserve not found") pure $ AssocMap.lookup reserveId reserves -findAaveUserConfigs :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map (AssetClass, PubKeyHash) UserConfig)) +findAaveUserConfigs :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map UserConfigId UserConfig)) findAaveUserConfigs aave = findOutputBy aave (userStateToken aave) (^? Core._UserConfigsDatum . _2) -findAaveUserConfig :: HasBlockchainActions s => Aave -> (AssetClass, PubKeyHash) -> Contract w s Text UserConfig +findAaveUserConfig :: HasBlockchainActions s => Aave -> UserConfigId -> Contract w s Text UserConfig findAaveUserConfig aave userConfigId = do configs <- ovValue <$> findAaveUserConfigs aave maybe (throwError "UserConfig not found") pure $ AssocMap.lookup userConfigId configs @@ -121,7 +122,7 @@ roundtripReserves aave redeemer = do reservesOutput <- findAaveReserves aave fst <$> updateReserves aave redeemer reservesOutput -makeUserHandle :: Aave -> (AssocMap.Map (AssetClass, PubKeyHash) UserConfig -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) +makeUserHandle :: Aave -> (AssocMap.Map UserConfigId UserConfig -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map UserConfigId UserConfig) makeUserHandle aave toRedeemer = let stateToken = userStateToken aave in StateHandle { @@ -130,20 +131,20 @@ makeUserHandle aave toRedeemer = toRedeemer = toRedeemer } -putUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript) +putUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssocMap.Map UserConfigId UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript) putUserConfigs aave redeemer = putState aave $ makeUserHandle aave (const redeemer) -updateUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) +updateUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map UserConfigId UserConfig) -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map UserConfigId UserConfig) updateUserConfigs aave redeemer = updateState aave $ makeUserHandle aave (const redeemer) -addUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> (AssetClass, PubKeyHash) -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) +addUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> UserConfigId -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map UserConfigId UserConfig) addUserConfig aave redeemer userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (pure ()) (const $ throwError "Add user config failed: config exists") $ AssocMap.lookup userConfigId (ovValue configsOutput) updateUserConfigs aave redeemer $ Prelude.fmap (AssocMap.insert userConfigId userConfig) configsOutput -updateUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> (AssetClass, PubKeyHash) -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) +updateUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> UserConfigId -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map UserConfigId UserConfig) updateUserConfig aave redeemer userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (throwError "Update failed: user config not found") pure $ diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs index 9271b5a04..895c5e09c 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs @@ -39,8 +39,10 @@ import Playground.Contract import Plutus.Contract hiding (when) import Plutus.Contracts.LendingPool.OnChain.Core.Script (AaveDatum (..), AaveRedeemer (..), + Oracles, Reserve (..), - UserConfig (..)) + UserConfig (..), + UserConfigId) import qualified Plutus.Contracts.Service.Oracle as Oracle import Plutus.V1.Ledger.Value import qualified PlutusTx @@ -52,7 +54,7 @@ import Prelude (Semigroup (.. import qualified Prelude {-# INLINABLE pickUserConfigs #-} -pickUserConfigs :: AaveDatum -> Maybe (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) +pickUserConfigs :: AaveDatum -> Maybe (AssetClass, AssocMap.Map UserConfigId UserConfig) pickUserConfigs (UserConfigsDatum stateToken configs) = Just (stateToken, configs) pickUserConfigs _ = Nothing @@ -69,14 +71,14 @@ pickUserCollateralFunds _ = Nothing {-# INLINABLE totalDebtAndCollateralInLovelace #-} totalDebtAndCollateralInLovelace :: PubKeyHash - -> AssocMap.Map AssetClass Integer - -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig + -> Oracles + -> AssocMap.Map UserConfigId UserConfig -> Maybe UserConfig totalDebtAndCollateralInLovelace actor oracles userConfigs = foldrM addCollateral (UserConfig 0 0) $ AssocMap.toList userConfigs where addCollateral :: - ((AssetClass, PubKeyHash), UserConfig) + (UserConfigId, UserConfig) -> UserConfig -> Maybe UserConfig addCollateral ((asset, user), userConfig) currentTotal @@ -91,8 +93,8 @@ totalDebtAndCollateralInLovelace actor oracles userConfigs = {-# INLINABLE doesCollateralCoverDebt #-} doesCollateralCoverDebt :: PubKeyHash - -> AssocMap.Map AssetClass Integer - -> AssocMap.Map (AssetClass, PubKeyHash) UserConfig + -> Oracles + -> AssocMap.Map UserConfigId UserConfig -> Bool doesCollateralCoverDebt actor oracles userConfigs = maybe False (\UserConfig{..} -> ucDebt <= ucCollateralizedInvestment) $ totalDebtAndCollateralInLovelace actor oracles userConfigs @@ -129,7 +131,7 @@ checkNegativeFundsTransformation ctx asset actor = isValidFundsChange checkNegativeReservesTransformation :: AssetClass -> AssocMap.Map AssetClass Reserve -> ScriptContext - -> (AssetClass, PubKeyHash) + -> UserConfigId -> Bool checkNegativeReservesTransformation stateToken reserves ctx (reserveId, _) = maybe False checkreserves reservesOutputDatum @@ -164,7 +166,7 @@ checkNegativeReservesTransformation stateToken reserves ctx (reserveId, _) = checkPositiveReservesTransformation :: AssetClass -> AssocMap.Map AssetClass Reserve -> ScriptContext - -> (AssetClass, PubKeyHash) + -> UserConfigId -> Bool checkPositiveReservesTransformation stateToken reserves ctx (reserveId, _) = maybe False checkreserves reservesOutputDatum where diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Script.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Script.hs index f5e1b86b1..4cca7c6db 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Script.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Script.hs @@ -90,29 +90,30 @@ PlutusTx.unstableMakeIsData ''UserConfig PlutusTx.makeLift ''UserConfig Lens.makeClassy_ ''UserConfig +type UserConfigId = (AssetClass, PubKeyHash) + data AaveRedeemer = StartRedeemer - | DepositRedeemer (AssetClass, PubKeyHash) - | WithdrawRedeemer (AssetClass, PubKeyHash) - | BorrowRedeemer (AssetClass, PubKeyHash) [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] - | RepayRedeemer (AssetClass, PubKeyHash) - | ProvideCollateralRedeemer (AssetClass, PubKeyHash) - | RevokeCollateralRedeemer (AssetClass, PubKeyHash) AssetClass [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] + | DepositRedeemer UserConfigId + | WithdrawRedeemer UserConfigId + | BorrowRedeemer UserConfigId [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] + | RepayRedeemer UserConfigId + | ProvideCollateralRedeemer UserConfigId + | RevokeCollateralRedeemer UserConfigId AssetClass [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] deriving Show PlutusTx.unstableMakeIsData ''AaveRedeemer PlutusTx.makeLift ''AaveRedeemer --- TODO: solve purescript generation issue with type synonyms -type UserConfigId = (AssetClass, PubKeyHash) type LendingPoolOperator = PubKeyHash + type Oracles = AssocMap.Map AssetClass Integer -- Shows how many lovelaces should be paid for a specific asset data AaveDatum = LendingPoolDatum LendingPoolOperator | ReservesDatum AssetClass (AssocMap.Map AssetClass Reserve) -- State token and reserve currency -> reserve map | ReserveFundsDatum - | UserConfigsDatum AssetClass (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -- State token and UserConfigId -> user config map + | UserConfigsDatum AssetClass (AssocMap.Map UserConfigId UserConfig) -- State token and UserConfigId -> user config map | UserCollateralFundsDatum PubKeyHash AssetClass -- User pub key and aToken asset type deriving stock (Show) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Validator.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Validator.hs index 775884cd2..626a1cf46 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Validator.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Validator.hs @@ -55,7 +55,8 @@ import Plutus.Contracts.LendingPool.OnChain.Core.Script (AaveDatum (.. AaveRedeemer (..), AaveScript, Reserve (..), - UserConfig (..)) + UserConfig (..), + UserConfigId) import qualified Plutus.Contracts.Service.Oracle as Oracle import Plutus.V1.Ledger.Value import qualified PlutusTx @@ -117,7 +118,7 @@ validateStart aave (LendingPoolDatum operator) ctx = validateStart aave _ ctx = trace "validateStart: Lending Pool Datum management is not allowed" False {-# INLINABLE validateDeposit #-} -validateDeposit :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool +validateDeposit :: Aave -> AaveDatum -> ScriptContext -> UserConfigId -> Bool validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId = traceIfFalse "validateDeposit: User Configs Datum change is not valid" isValidUserConfigsTransformation where @@ -126,14 +127,14 @@ validateDeposit aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId userConfigsOutputDatumHash = findOnlyOneDatumHashByValue (assetClassValue stateToken 1) $ scriptOutputsAt scriptsHash txInfo userConfigsOutputDatum :: - Maybe (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) + Maybe (AssetClass, AssocMap.Map UserConfigId UserConfig) userConfigsOutputDatum = userConfigsOutputDatumHash >>= parseDatum txInfo >>= pickUserConfigs isValidUserConfigsTransformation :: Bool isValidUserConfigsTransformation = maybe False checkUserConfigs userConfigsOutputDatum - checkUserConfigs :: (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -> Bool + checkUserConfigs :: (AssetClass, AssocMap.Map UserConfigId UserConfig) -> Bool checkUserConfigs (newStateToken, newUserConfigs) = newStateToken == stateToken && maybe @@ -152,7 +153,7 @@ validateDeposit aave (ReservesDatum stateToken reserves) ctx userConfigId = validateDeposit _ _ _ _ = trace "validateDeposit: Lending Pool Datum management is not allowed" False {-# INLINABLE validateWithdraw #-} -validateWithdraw :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool +validateWithdraw :: Aave -> AaveDatum -> ScriptContext -> UserConfigId -> Bool validateWithdraw aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId = -- TODO add implementation for this case traceIfFalse "validateWithdraw: User Configs Datum change is not valid" False @@ -165,7 +166,7 @@ validateWithdraw aave ReserveFundsDatum ctx (reserveId, actor) = validateWithdraw _ _ _ _ = trace "validateWithdraw: Lending Pool Datum management is not allowed" False {-# INLINABLE validateBorrow #-} -validateBorrow :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] -> Bool +validateBorrow :: Aave -> AaveDatum -> ScriptContext -> UserConfigId -> [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] -> Bool validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) oracles = traceIfFalse "validateBorrow: User Configs Datum change is not valid" isValidUserConfigsTransformation where @@ -175,7 +176,7 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( userConfigsOutputDatumHash = findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs userConfigsOutputDatum :: - Maybe (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) + Maybe (AssetClass, AssocMap.Map UserConfigId UserConfig) userConfigsOutputDatum = userConfigsOutputDatumHash >>= parseDatum txInfo >>= pickUserConfigs @@ -191,7 +192,7 @@ validateBorrow aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@( isValidUserConfigsTransformation = maybe False checkUserConfigs userConfigsOutputDatum checkUserConfigs :: - (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -> Bool + (AssetClass, AssocMap.Map UserConfigId UserConfig) -> Bool checkUserConfigs (newStateToken, newUserConfigs) = newStateToken == stateToken && doesCollateralCoverDebt actor oracleValues newUserConfigs && maybe False (checkRedeemerConfig $ AssocMap.lookup userConfigId userConfigs) (AssocMap.lookup userConfigId newUserConfigs) @@ -211,7 +212,7 @@ validateBorrow aave ReserveFundsDatum ctx (reserveId, actor) oracles = validateBorrow _ _ _ _ _ = trace "validateBorrow: Lending Pool Datum management is not allowed" False {-# INLINABLE validateRepay #-} -validateRepay :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool +validateRepay :: Aave -> AaveDatum -> ScriptContext -> UserConfigId -> Bool validateRepay aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) = traceIfFalse "validateRepay: User Configs Datum change is not valid" isValidUserConfigsTransformation where @@ -221,7 +222,7 @@ validateRepay aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(r userConfigsOutputDatumHash = findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs userConfigsOutputDatum :: - Maybe (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) + Maybe (AssetClass, AssocMap.Map UserConfigId UserConfig) userConfigsOutputDatum = userConfigsOutputDatumHash >>= parseDatum txInfo >>= pickUserConfigs @@ -231,7 +232,7 @@ validateRepay aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(r isValidUserConfigsTransformation :: Bool isValidUserConfigsTransformation = maybe False checkUserConfigs userConfigsOutputDatum - checkUserConfigs :: (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -> Bool + checkUserConfigs :: (AssetClass, AssocMap.Map UserConfigId UserConfig) -> Bool checkUserConfigs (newStateToken, newUserConfigs) = newStateToken == stateToken && (Just True == @@ -250,7 +251,7 @@ validateRepay aave (ReservesDatum stateToken reserves) ctx userConfigId = validateRepay _ _ _ _ = trace "validateRepay: Lending Pool Datum management is not allowed" False {-# INLINABLE validateProvideCollateral #-} -validateProvideCollateral :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> Bool +validateProvideCollateral :: Aave -> AaveDatum -> ScriptContext -> UserConfigId -> Bool validateProvideCollateral aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) = traceIfFalse "validateProvideCollateral: User Configs Datum change is not valid" isValidUserConfigsTransformation where @@ -261,7 +262,7 @@ validateProvideCollateral aave (UserConfigsDatum stateToken userConfigs) ctx us userConfigsOutputDatumHash = findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs userConfigsOutputDatum :: - Maybe (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) + Maybe (AssetClass, AssocMap.Map UserConfigId UserConfig) userConfigsOutputDatum = userConfigsOutputDatumHash >>= parseDatum txInfo >>= pickUserConfigs @@ -279,7 +280,7 @@ validateProvideCollateral aave (UserConfigsDatum stateToken userConfigs) ctx us isValidUserConfigsTransformation = fromMaybe False $ checkUserConfigs <$> userConfigsOutputDatum <*> collateralOutputDatum checkUserConfigs :: - (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -> (PubKeyHash, AssetClass) -> Bool + (AssetClass, AssocMap.Map UserConfigId UserConfig) -> (PubKeyHash, AssetClass) -> Bool checkUserConfigs (newStateToken, newUserConfigs) (user, aTokenAsset) = newStateToken == stateToken && user == actor && maybe False (checkRedeemerConfig aTokenAsset $ AssocMap.lookup userConfigId userConfigs) (AssocMap.lookup userConfigId newUserConfigs) @@ -293,7 +294,7 @@ validateProvideCollateral aave (UserConfigsDatum stateToken userConfigs) ctx us validateProvideCollateral _ _ _ _ = trace "validateProvideCollateral: Lending Pool Datum management is not allowed" False {-# INLINABLE validateRevokeCollateral #-} -validateRevokeCollateral :: Aave -> AaveDatum -> ScriptContext -> (AssetClass, PubKeyHash) -> AssetClass -> [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] -> Bool +validateRevokeCollateral :: Aave -> AaveDatum -> ScriptContext -> UserConfigId -> AssetClass -> [(CurrencySymbol, PubKeyHash, Integer, AssetClass)] -> Bool validateRevokeCollateral aave (UserConfigsDatum stateToken userConfigs) ctx userConfigId@(reserveId, actor) aTokenAsset oracles = traceIfFalse "validateRevokeCollateral: User Configs Datum change is not valid" isValidUserConfigsTransformation where @@ -304,7 +305,7 @@ validateRevokeCollateral aave (UserConfigsDatum stateToken userConfigs) ctx use userConfigsOutputDatumHash = findOnlyOneDatumHashByValue (assetClassValue stateToken 1) scriptOutputs userConfigsOutputDatum :: - Maybe (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) + Maybe (AssetClass, AssocMap.Map UserConfigId UserConfig) userConfigsOutputDatum = userConfigsOutputDatumHash >>= parseDatum txInfo >>= pickUserConfigs @@ -320,7 +321,7 @@ validateRevokeCollateral aave (UserConfigsDatum stateToken userConfigs) ctx use isValidUserConfigsTransformation = maybe False checkUserConfigs userConfigsOutputDatum checkUserConfigs :: - (AssetClass, AssocMap.Map (AssetClass, PubKeyHash) UserConfig) -> Bool + (AssetClass, AssocMap.Map UserConfigId UserConfig) -> Bool checkUserConfigs (newStateToken, newUserConfigs) = newStateToken == stateToken && doesCollateralCoverDebt actor oracleValues newUserConfigs && fromMaybe False (checkRedeemerConfig <$> (AssocMap.lookup userConfigId userConfigs) <*> (AssocMap.lookup userConfigId newUserConfigs)) diff --git a/MetaLamp/lending-pool/test/Fixtures/Init.hs b/MetaLamp/lending-pool/test/Fixtures/Init.hs index a690d050f..85742b794 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Init.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Init.hs @@ -43,7 +43,7 @@ oracles = fmap startParams :: [Aave.CreateParams] startParams = fmap (\o -> Aave.CreateParams (Oracle.oAsset o) o) oracles -initialUsers :: AssocMap.Map (AssetClass, PubKeyHash) Aave.UserConfig +initialUsers :: AssocMap.Map Aave.UserConfigId Aave.UserConfig initialUsers = AssocMap.empty initialReserves :: AssocMap.Map AssetClass Aave.Reserve diff --git a/MetaLamp/lending-pool/test/Spec/Shared.hs b/MetaLamp/lending-pool/test/Spec/Shared.hs index 292f133f5..5de4c67ec 100644 --- a/MetaLamp/lending-pool/test/Spec/Shared.hs +++ b/MetaLamp/lending-pool/test/Spec/Shared.hs @@ -1,5 +1,4 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE DataKinds #-} module Spec.Shared where @@ -18,7 +17,7 @@ reservesChange reserves = Utils.datumsAtAddress Fixtures.aaveAddress (Utils.one check (Aave.ReservesDatum _ reserves') = reserves' == reserves check _ = False -userConfigsChange :: AssocMap.Map (AssetClass, PubKeyHash) Aave.UserConfig -> TracePredicate +userConfigsChange :: AssocMap.Map Aave.UserConfigId Aave.UserConfig -> TracePredicate userConfigsChange configs = Utils.datumsAtAddress Fixtures.aaveAddress (Utils.one check) where check (Aave.UserConfigsDatum _ configs') = configs' == configs diff --git a/MetaLamp/lending-pool/test/Spec/Start.hs b/MetaLamp/lending-pool/test/Spec/Start.hs index cc9eeacdc..30738f784 100644 --- a/MetaLamp/lending-pool/test/Spec/Start.hs +++ b/MetaLamp/lending-pool/test/Spec/Start.hs @@ -1,5 +1,4 @@ {-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE TypeApplications #-} module Spec.Start where From 5b26e6352e7c518a7e902bc74cf7ec3888e2f0cc Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Mon, 12 Jul 2021 12:45:40 +0700 Subject: [PATCH 156/169] add nix config from plutus-starter --- MetaLamp/lending-pool/cabal.project | 55 +++-- MetaLamp/lending-pool/default.nix | 35 +++ MetaLamp/lending-pool/nix/default.nix | 20 ++ MetaLamp/lending-pool/nix/lib/ci.nix | 201 ++++++++++++++++++ MetaLamp/lending-pool/nix/pkgs/default.nix | 28 +++ .../lending-pool/nix/pkgs/haskell/default.nix | 35 +++ .../lending-pool/nix/pkgs/haskell/haskell.nix | 54 +++++ MetaLamp/lending-pool/nix/sources.json | 14 ++ MetaLamp/lending-pool/nix/sources.nix | 174 +++++++++++++++ MetaLamp/lending-pool/release.nix | 52 +++++ MetaLamp/lending-pool/shell.nix | 18 ++ .../src/Plutus/Abstract/ContractResponse.hs | 2 +- .../src/Plutus/Abstract/State/Select.hs | 6 +- .../src/Plutus/Abstract/State/Update.hs | 4 +- .../src/Plutus/Abstract/TxUtils.hs | 2 +- .../Contracts/LendingPool/OffChain/AToken.hs | 4 +- .../Contracts/LendingPool/OffChain/Info.hs | 11 +- .../Contracts/LendingPool/OffChain/Owner.hs | 7 +- .../Contracts/LendingPool/OffChain/State.hs | 34 +-- .../Contracts/LendingPool/OffChain/User.hs | 37 ++-- .../LendingPool/OnChain/Core/Script.hs | 2 - .../src/Plutus/Contracts/Service/Oracle.hs | 10 +- .../lending-pool/src/Plutus/PAB/Simulation.hs | 10 +- MetaLamp/lending-pool/test/Fixtures/Init.hs | 2 +- MetaLamp/lending-pool/test/Fixtures/Symbol.hs | 2 +- MetaLamp/lending-pool/test/Utils/Trace.hs | 4 +- 26 files changed, 738 insertions(+), 85 deletions(-) create mode 100644 MetaLamp/lending-pool/default.nix create mode 100644 MetaLamp/lending-pool/nix/default.nix create mode 100644 MetaLamp/lending-pool/nix/lib/ci.nix create mode 100644 MetaLamp/lending-pool/nix/pkgs/default.nix create mode 100644 MetaLamp/lending-pool/nix/pkgs/haskell/default.nix create mode 100644 MetaLamp/lending-pool/nix/pkgs/haskell/haskell.nix create mode 100644 MetaLamp/lending-pool/nix/sources.json create mode 100644 MetaLamp/lending-pool/nix/sources.nix create mode 100644 MetaLamp/lending-pool/release.nix create mode 100644 MetaLamp/lending-pool/shell.nix diff --git a/MetaLamp/lending-pool/cabal.project b/MetaLamp/lending-pool/cabal.project index 964bef10c..ad1a2aaad 100644 --- a/MetaLamp/lending-pool/cabal.project +++ b/MetaLamp/lending-pool/cabal.project @@ -1,4 +1,4 @@ -index-state: 2021-02-24T00:00:00Z +index-state: 2021-04-13T00:00:00Z packages: ./. @@ -26,7 +26,7 @@ source-repository-package prettyprinter-configurable quickcheck-dynamic word-array - tag: 5cdd2c3d708bf4c33514681dee096da6463273b7 + tag: plutus-starter-devcontainer/v1.0.6 -- The following sections are copied from the 'plutus' repository cabal.project at the revision -- given above. @@ -56,6 +56,12 @@ constraints: extra-packages: ieee, filemanip +-- Drops an instance breaking our code. Should be released to Hackage eventually. +source-repository-package + type: git + location: https://github.com/Quid2/flat.git + tag: 95e5d7488451e43062ca84d5376b3adcc465f1cd + -- Needs some patches, but upstream seems to be fairly dead (no activity in > 1 year) source-repository-package type: git @@ -70,7 +76,7 @@ source-repository-package source-repository-package type: git location: https://github.com/input-output-hk/cardano-crypto.git - tag: f73079303f663e028288f9f4a9e08bcca39a923e + tag: ce8f1934e4b6252084710975bd9bbc0a4648ece4 -- Needs a fix (https://github.com/wenkokke/unlit/pull/11) and a Hackage release source-repository-package @@ -81,18 +87,20 @@ source-repository-package source-repository-package type: git location: https://github.com/input-output-hk/cardano-base - tag: 4251c0bb6e4f443f00231d28f5f70d42876da055 + tag: a715c7f420770b70bbe95ca51d3dec83866cb1bd subdir: binary binary/test slotting cardano-crypto-class cardano-crypto-praos + cardano-crypto-tests + strict-containers source-repository-package type: git location: https://github.com/input-output-hk/cardano-prelude - tag: ee4e7b547a991876e6b05ba542f4e62909f4a571 + tag: fd773f7a58412131512b9f694ab95653ac430852 subdir: cardano-prelude cardano-prelude-test @@ -100,22 +108,25 @@ source-repository-package source-repository-package type: git location: https://github.com/input-output-hk/ouroboros-network - tag: 6cb9052bde39472a0555d19ade8a42da63d3e904 + tag: e50613562d6d4a0f933741fcf590b0f69a1eda67 subdir: typed-protocols typed-protocols-examples ouroboros-network ouroboros-network-testing ouroboros-network-framework + ouroboros-consensus + ouroboros-consensus-byron + ouroboros-consensus-cardano + ouroboros-consensus-shelley io-sim io-sim-classes network-mux - Win32-network source-repository-package type: git location: https://github.com/input-output-hk/iohk-monitoring-framework - tag: a89c38ed5825ba17ca79fddb85651007753d699d + tag: 34abfb7f4f5610cabb45396e0496472446a0b2ca subdir: iohk-monitoring tracer-transformers @@ -125,7 +136,7 @@ source-repository-package source-repository-package type: git location: https://github.com/input-output-hk/cardano-ledger-specs - tag: 097890495cbb0e8b62106bcd090a5721c3f4b36f + tag: a3ef848542961079b7cd53d599e5385198a3035c subdir: byron/chain/executable-spec byron/crypto @@ -137,14 +148,32 @@ source-repository-package semantics/small-steps-test shelley/chain-and-ledger/dependencies/non-integer shelley/chain-and-ledger/executable-spec + shelley/chain-and-ledger/shelley-spec-ledger-test shelley-ma/impl + cardano-ledger-core + alonzo/impl +-- A lot of plutus dependencies have to be synchronized with the dependencies of +-- cardano-node. If you update cardano-node, please make sure that all dependencies +-- of cardano-node are also updated. source-repository-package type: git - location: https://github.com/input-output-hk/goblins - tag: cde90a2b27f79187ca8310b6549331e59595e7ba + location: https://github.com/input-output-hk/cardano-node.git + tag: b3cabae6b3bf30a0b1b4e78bc4b67282dabad0a6 + subdir: + cardano-api source-repository-package type: git - location: https://github.com/Quid2/flat.git - tag: 95e5d7488451e43062ca84d5376b3adcc465f1cd + location: https://github.com/input-output-hk/Win32-network + tag: 94153b676617f8f33abe8d8182c37377d2784bd1 + +source-repository-package + type: git + location: https://github.com/input-output-hk/hedgehog-extras + tag: 8bcd3c9dc22cc44f9fcfe161f4638a384fc7a187 + +source-repository-package + type: git + location: https://github.com/input-output-hk/goblins + tag: cde90a2b27f79187ca8310b6549331e59595e7ba diff --git a/MetaLamp/lending-pool/default.nix b/MetaLamp/lending-pool/default.nix new file mode 100644 index 000000000..6c0824149 --- /dev/null +++ b/MetaLamp/lending-pool/default.nix @@ -0,0 +1,35 @@ +######################################################################## +# default.nix -- The top-level nix build file for plutus-starter. +# +# This file defines various attributes that are used for building and +# developing plutus-starter. +# +######################################################################## + +let + # Here a some of the various attributes for the variable 'packages': + # + # { pkgs + # plutus-starter: { + # haskell: { + # project # The Haskell project created by haskell-nix.project + # packages # All the packages defined by our project, including dependencies + # projectPackages # Just the packages in the project + # } + # hlint + # cabal-install + # stylish-haskell + # haskell-language-server + # } + # } + + packages = import ./nix; + + inherit (packages) pkgs plutus-starter; + project = plutus-starter.haskell.project; +in +{ + inherit pkgs plutus-starter; + + inherit project; +} diff --git a/MetaLamp/lending-pool/nix/default.nix b/MetaLamp/lending-pool/nix/default.nix new file mode 100644 index 000000000..6a866cbb2 --- /dev/null +++ b/MetaLamp/lending-pool/nix/default.nix @@ -0,0 +1,20 @@ +let + # Pratically, the only needed dependency is the plutus repository. + sources = import ./sources.nix { inherit pkgs; }; + + # We're going to get everything from the main plutus repository. This ensures + # we're using the same version of multiple dependencies such as nipxkgs, + # haskell-nix, cabal-install, compiler-nix-name, etc. + plutus = import sources.plutus {}; + pkgs = plutus.pkgs; + + haskell-nix = pkgs.haskell-nix; + + plutus-starter = import ./pkgs { + inherit pkgs haskell-nix sources plutus; + }; + +in +{ + inherit pkgs plutus-starter; +} diff --git a/MetaLamp/lending-pool/nix/lib/ci.nix b/MetaLamp/lending-pool/nix/lib/ci.nix new file mode 100644 index 000000000..80794a750 --- /dev/null +++ b/MetaLamp/lending-pool/nix/lib/ci.nix @@ -0,0 +1,201 @@ +{ pkgs }: + +let + # Generic nixpkgs, use *only* for lib functions that are stable across versions + lib = pkgs.lib; +in +rec { + # Borrowed from https://github.com/cachix/ghcide-nix/pull/4/files#diff-70bfff902f4dec33e545cac10ee5844d + # Tweaked to use builtins.mapAttrs instead of needing the one from nixpkgs lib + /* + dimension: name -> attrs -> function -> attrs + where + function: keyText -> value -> attrsOf package + + WARNING: Attribute names must not contain periods ("."). + See https://github.com/NixOS/nix/issues/3088 + + NOTE: The dimension name will be picked up by agent and web ui soon. + + Specifies a dimension of the build matrix. For example + + dimension "Example" { + withP = { p = true; } + withoutP = { p = false; } + } (key: # either "withP" or "withoutP" + { p }: # either p = true or p = false + myProject p + ) + + evaluates roughly to + + { + withP = myProject true; + withoutP = myProject false; + } + + Use nested calls for multiple dimensions. + + Example: + + dimension "System" { + "x86_64-linux" = {}; + # ... + }: (system: {}: + + dimension "Nixpkgs release" ( + { + "nixpkgs-19_03".nixpkgs = someSource + } // optionalAttrs (system != "...") { + "nixpkgs-unstable".nixpkgs = someOtherSource + } + ) (_key: { nixpkgs }: + + myProject system nixpkgs + + ) + ) + + evaluates roughly to + + { + x86_64-linux.nixpkgs-19_03 = myProject "x86_64-linux" someSource; + x86_64-linux.nixpkgs-unstable = myProject "x86_64-linux" someOtherSource; + ... + } + + If you need to make references across attributes, you can do so by binding + the result. Wherever you write + + dimension "My dimension" {} (key: value: f1 key value) + + You can also write + + let + myDimension = dimension "My dimension" {} (key: value: f2 key value myDimension) + in + myDimension + + This example builds a single test runner to reuse across releases: + + let + overlay = + testRunnerPkgs: self: super: { + # ... + }; + myProject = + { nixpkgs, + pkgs ? import nixpkgs { overlays = [ overlay ]; }, + testRunnerPkgs ? pkgs + }: pkgs; + in + + let + latest = "nixpkgs-19_03"; + releases = + dimension "Nixpkgs release" + { + nixpkgs-18_09.nixpkgs = someSource + nixpkgs-19_03.nixpkgs = someOtherSource + } + (_key: { nixpkgs }: + + myProject { + inherit nixpkgs; + testRunnerPkgs = releases."${latest}"; + } + + ); + in releases; + + */ + dimension = name: attrs: f: + builtins.mapAttrs + (k: v: + let o = f k v; + in o // { recurseForDerivations = o.recurseForDerivations or true; } + ) + attrs + // { meta.dimension.name = name; }; + + /* + Takes an attribute set and returns all the paths to derivations within it, i.e. + derivationPaths { a = { b = ; }; c = ; } == [ "a.b" "c" ] + This can be used with 'attrByPath' or the 'constitutents' of an aggregate Hydra job. + */ + derivationPaths = + let + names = x: lib.filter (n: n != "recurseForDerivations" && n != "meta") (builtins.attrNames x); + go = nameSections: attrs: + builtins.concatMap + (n: + let + v = builtins.getAttr n attrs; + newNameSections = nameSections ++ [ n ]; + in + if pkgs.lib.isDerivation v + then [ (builtins.concatStringsSep "." newNameSections) ] + else if builtins.isAttrs v + then go newNameSections v + else [ ] + ) + (names attrs); + in + go [ ]; + + # Creates an aggregate job with the given name from every derivation in the attribute set. + derivationAggregate = name: attrs: pkgs.releaseTools.aggregate { + inherit name; + constituents = derivationPaths attrs; + }; + + # A filter for removing packages that aren't supported on the current platform + # according to 'meta.platforms'. + platformFilterGeneric = pkgs: system: + # This needs to use the correct nixpkgs version so all the systems line up + let + lib = pkgs.lib; + platform = lib.systems.elaborate { inherit system; }; + # Can't just default to [] for platforms, since no meta.platforms + # means "all platforms" not "no platforms" + in + drv: + if drv ? meta && drv.meta ? platforms then + lib.any (lib.meta.platformMatch platform) drv.meta.platforms + else true; + + # Hydra doesn't like these attributes hanging around in "jobsets": it thinks they're jobs! + stripAttrsForHydra = filterAttrsOnlyRecursive (n: _: n != "recurseForDerivations" && n != "dimension"); + + # Keep derivations and attrsets with 'recurseForDerivations'. This ensures that we match the + # derivations that Hercules will see, and prevents Hydra from trying to pick up all sorts of bad stuff + # (like attrsets that contain themselves!). + filterDerivations = filterAttrsOnlyRecursive (n: attrs: lib.isDerivation attrs || attrs.recurseForDerivations or false); + + # A version of 'filterAttrsRecursive' that doesn't recurse into derivations. This prevents us from going into an infinite + # loop with the 'out' attribute on derivations. + # TODO: Surely this shouldn't be necessary. I think normal 'filterAttrsRecursive' will effectively cause infinite loops + # if you keep derivations and your predicate forces the value of the attribute, as this then triggers a loop on the + # 'out' attribute. Weird. + filterAttrsOnlyRecursive = pred: set: + lib.listToAttrs ( + lib.concatMap + (name: + let v = set.${name}; in + if pred name v then [ + (lib.nameValuePair name ( + if builtins.isAttrs v && !lib.isDerivation v then filterAttrsOnlyRecursive pred v + else v + )) + ] else [ ] + ) + (builtins.attrNames set) + ); + + # Takes an array of systems and returns a `name: system` AttrSet + # filterSystems :: [ string ] -> AttrSet + filterSystems = systems: lib.filterAttrs (_: v: builtins.elem v systems) { + linux = "x86_64-linux"; + darwin = "x86_64-darwin"; + }; +} diff --git a/MetaLamp/lending-pool/nix/pkgs/default.nix b/MetaLamp/lending-pool/nix/pkgs/default.nix new file mode 100644 index 000000000..73ff41e3f --- /dev/null +++ b/MetaLamp/lending-pool/nix/pkgs/default.nix @@ -0,0 +1,28 @@ +{ pkgs +, sources +, plutus +, haskell-nix +}: +let + gitignore-nix = pkgs.callPackage plutus."gitignore.nix" { }; + + compiler-nix-name = plutus.plutus.haskell.compiler-nix-name; + + haskell = pkgs.callPackage ./haskell { + inherit gitignore-nix sources haskell-nix; + inherit compiler-nix-name; # Use the same GHC version as plutus + }; + + hlint = plutus.plutus.hlint; + + cabal-install = plutus.plutus.cabal-install; + + stylish-haskell = plutus.plutus.stylish-haskell; + + haskell-language-server = plutus.plutus.haskell-language-server; + + cardano-repo-tool = plutus.plutus.cardano-repo-tool; +in +{ + inherit haskell hlint cabal-install stylish-haskell haskell-language-server cardano-repo-tool; +} diff --git a/MetaLamp/lending-pool/nix/pkgs/haskell/default.nix b/MetaLamp/lending-pool/nix/pkgs/haskell/default.nix new file mode 100644 index 000000000..67036b9d5 --- /dev/null +++ b/MetaLamp/lending-pool/nix/pkgs/haskell/default.nix @@ -0,0 +1,35 @@ +{ lib +, haskell-nix +, gitignore-nix +, sources +, compiler-nix-name +}: +let + # The Hackage index-state from cabal.project + index-state = + let + parseIndexState = rawCabalProject: + let + indexState = lib.lists.concatLists ( + lib.lists.filter (l: l != null) + (map (l: builtins.match "^index-state: *(.*)" l) + (lib.splitString "\n" rawCabalProject))); + in + lib.lists.head (indexState ++ [ null ]); + in + parseIndexState (builtins.readFile ../../../cabal.project); + + # The haskell project created by haskell-nix.cabalProject' + project = import ./haskell.nix { + inherit haskell-nix compiler-nix-name gitignore-nix; + }; + + # All the packages defined by our project, including dependencies + packages = project.hsPkgs; + + # Just the packages in the project + projectPackages = haskell-nix.haskellLib.selectProjectPackages packages; +in +rec { + inherit project projectPackages packages; +} diff --git a/MetaLamp/lending-pool/nix/pkgs/haskell/haskell.nix b/MetaLamp/lending-pool/nix/pkgs/haskell/haskell.nix new file mode 100644 index 000000000..517deaa42 --- /dev/null +++ b/MetaLamp/lending-pool/nix/pkgs/haskell/haskell.nix @@ -0,0 +1,54 @@ +############################################################################ +# Builds Haskell packages with Haskell.nix +############################################################################ +{ haskell-nix +, gitignore-nix +, compiler-nix-name +}: + +let + project = haskell-nix.project { + # 'cleanGit' cleans a source directory based on the files known by git + src = haskell-nix.haskellLib.cleanGit { + name = "plutus-starter"; + src = ../../../.; + }; + + inherit compiler-nix-name; + + sha256map = { + "https://github.com/Quid2/flat.git"."95e5d7488451e43062ca84d5376b3adcc465f1cd" = "06l31x3y93rjpryvlxnpsyq2zyxvb0z6lik6yq2fvh36i5zwvwa3"; + "https://github.com/input-output-hk/plutus.git"."plutus-starter-devcontainer/v1.0.6" = "1jzbcsdrv0b43dj7bwbd1fbk71f7gph6zzb8y29n9cn3j8illnyc"; + "https://github.com/shmish111/purescript-bridge.git"."6a92d7853ea514be8b70bab5e72077bf5a510596" = "13j64vv116in3c204qsl1v0ajphac9fqvsjp7x3zzfr7n7g61drb"; + "https://github.com/shmish111/servant-purescript.git"."a76104490499aa72d40c2790d10e9383e0dbde63" = "11nxxmi5bw66va7psvrgrw7b7n85fvqgfp58yva99w3v9q3a50v9"; + "https://github.com/input-output-hk/cardano-crypto.git"."ce8f1934e4b6252084710975bd9bbc0a4648ece4" = "1v2laq04piyj511b2m77hxjh9l1yd6k9kc7g6bjala4w3zdwa4ni"; + "https://github.com/michaelpj/unlit.git"."9ca1112093c5ffd356fc99c7dafa080e686dd748" = "145sffn8gbdn6xp9q5b75yd3m46ql5bnc02arzmpfs6wgjslfhff"; + "https://github.com/input-output-hk/cardano-base"."a715c7f420770b70bbe95ca51d3dec83866cb1bd" = "06l06mmb8cd4q37bnvfpgx1c5zgsl4xaf106dqva98738i8asj7j"; + "https://github.com/input-output-hk/cardano-prelude"."fd773f7a58412131512b9f694ab95653ac430852" = "02jddik1yw0222wd6q0vv10f7y8rdgrlqaiy83ph002f9kjx7mh6"; + "https://github.com/input-output-hk/ouroboros-network"."e50613562d6d4a0f933741fcf590b0f69a1eda67" = "0i192ksa69lpzjhzmhd2h1mramkvvikw04pqws18h5dly55f4z3k"; + "https://github.com/input-output-hk/iohk-monitoring-framework"."34abfb7f4f5610cabb45396e0496472446a0b2ca" = "1fdc0a02ipa385dnwa6r6jyc8jlg537i12hflfglkhjs2b7i92gs"; + "https://github.com/input-output-hk/cardano-ledger-specs"."a3ef848542961079b7cd53d599e5385198a3035c" = "02iwn2lcfcfvrnvcqnx586ncdnma23vdqvicxgr4f39vcacalzpd"; + "https://github.com/input-output-hk/cardano-node.git"."b3cabae6b3bf30a0b1b4e78bc4b67282dabad0a6" = "1csmji1bgi45wgrw7kqy19s4bbbpa78kjg3bz7mbiwb8vjgg9kvq"; + "https://github.com/input-output-hk/Win32-network"."94153b676617f8f33abe8d8182c37377d2784bd1" = "0pb7bg0936fldaa5r08nqbxvi2g8pcy4w3c7kdcg7pdgmimr30ss"; + "https://github.com/input-output-hk/hedgehog-extras"."8bcd3c9dc22cc44f9fcfe161f4638a384fc7a187" = "12viwpahjdfvlqpnzdgjp40nw31rvyznnab1hml9afpaxd6ixh70"; + "https://github.com/input-output-hk/goblins"."cde90a2b27f79187ca8310b6549331e59595e7ba" = "17c88rbva3iw82yg9srlxjv2ia5wjb9cyqw44hik565f5v9svnyg"; + }; + + modules = [ + { + packages = { + eventful-sql-common = { + # This is needed so evenful-sql-common will build with a newer version of persistent. + ghcOptions = [ "-XDerivingStrategies -XStandaloneDeriving -XUndecidableInstances -XDataKinds -XFlexibleInstances -XMultiParamTypeClasses" ]; + doHaddock = false; + }; + + # Broken due to haddock errors. Refer to https://github.com/input-output-hk/plutus/blob/master/nix/pkgs/haskell/haskell.nix + plutus-ledger.doHaddock = false; + plutus-use-cases.doHaddock = false; + }; + } + ]; + }; +in + project diff --git a/MetaLamp/lending-pool/nix/sources.json b/MetaLamp/lending-pool/nix/sources.json new file mode 100644 index 000000000..94979120f --- /dev/null +++ b/MetaLamp/lending-pool/nix/sources.json @@ -0,0 +1,14 @@ +{ + "plutus": { + "branch": "master", + "description": "The Plutus language implementation and tools", + "homepage": "", + "owner": "input-output-hk", + "repo": "plutus", + "rev": "plutus-starter-devcontainer/v1.0.6", + "sha256": "1jzbcsdrv0b43dj7bwbd1fbk71f7gph6zzb8y29n9cn3j8illnyc", + "type": "tarball", + "url": "https://github.com/input-output-hk/plutus/archive/plutus-starter-devcontainer/v1.0.6.tar.gz", + "url_template": "https://github.com///archive/.tar.gz" + } +} diff --git a/MetaLamp/lending-pool/nix/sources.nix b/MetaLamp/lending-pool/nix/sources.nix new file mode 100644 index 000000000..1938409dd --- /dev/null +++ b/MetaLamp/lending-pool/nix/sources.nix @@ -0,0 +1,174 @@ +# This file has been generated by Niv. + +let + + # + # The fetchers. fetch_ fetches specs of type . + # + + fetch_file = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchurl { inherit (spec) url sha256; name = name'; } + else + pkgs.fetchurl { inherit (spec) url sha256; name = name'; }; + + fetch_tarball = pkgs: name: spec: + let + name' = sanitizeName name + "-src"; + in + if spec.builtin or true then + builtins_fetchTarball { name = name'; inherit (spec) url sha256; } + else + pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; + + fetch_git = name: spec: + let + ref = + if spec ? ref then spec.ref else + if spec ? branch then "refs/heads/${spec.branch}" else + if spec ? tag then "refs/tags/${spec.tag}" else + abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!"; + in + builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; }; + + fetch_local = spec: spec.path; + + fetch_builtin-tarball = name: throw + ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=tarball -a builtin=true''; + + fetch_builtin-url = name: throw + ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. + $ niv modify ${name} -a type=file -a builtin=true''; + + # + # Various helpers + # + + # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695 + sanitizeName = name: + ( + concatMapStrings (s: if builtins.isList s then "-" else s) + ( + builtins.split "[^[:alnum:]+._?=-]+" + ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name) + ) + ); + + # The set of packages used when specs are fetched using non-builtins. + mkPkgs = sources: system: + let + sourcesNixpkgs = + import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; }; + hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; + hasThisAsNixpkgsPath = == ./.; + in + if builtins.hasAttr "nixpkgs" sources + then sourcesNixpkgs + else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then + import {} + else + abort + '' + Please specify either (through -I or NIX_PATH=nixpkgs=...) or + add a package called "nixpkgs" to your sources.json. + ''; + + # The actual fetching function. + fetch = pkgs: name: spec: + + if ! builtins.hasAttr "type" spec then + abort "ERROR: niv spec ${name} does not have a 'type' attribute" + else if spec.type == "file" then fetch_file pkgs name spec + else if spec.type == "tarball" then fetch_tarball pkgs name spec + else if spec.type == "git" then fetch_git name spec + else if spec.type == "local" then fetch_local spec + else if spec.type == "builtin-tarball" then fetch_builtin-tarball name + else if spec.type == "builtin-url" then fetch_builtin-url name + else + abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; + + # If the environment variable NIV_OVERRIDE_${name} is set, then use + # the path directly as opposed to the fetched source. + replace = name: drv: + let + saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name; + ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; + in + if ersatz == "" then drv else + # this turns the string into an actual Nix path (for both absolute and + # relative paths) + if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; + + # Ports of functions for older nix versions + + # a Nix version of mapAttrs if the built-in doesn't exist + mapAttrs = builtins.mapAttrs or ( + f: set: with builtins; + listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) + ); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 + range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 + stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); + + # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 + stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); + concatMapStrings = f: list: concatStrings (map f list); + concatStrings = builtins.concatStringsSep ""; + + # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331 + optionalAttrs = cond: as: if cond then as else {}; + + # fetchTarball version that is compatible between all the versions of Nix + builtins_fetchTarball = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchTarball; + in + if lessThan nixVersion "1.12" then + fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) + else + fetchTarball attrs; + + # fetchurl version that is compatible between all the versions of Nix + builtins_fetchurl = { url, name ? null, sha256 }@attrs: + let + inherit (builtins) lessThan nixVersion fetchurl; + in + if lessThan nixVersion "1.12" then + fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) + else + fetchurl attrs; + + # Create the final "sources" from the config + mkSources = config: + mapAttrs ( + name: spec: + if builtins.hasAttr "outPath" spec + then abort + "The values in sources.json should not have an 'outPath' attribute" + else + spec // { outPath = replace name (fetch config.pkgs name spec); } + ) config.sources; + + # The "config" used by the fetchers + mkConfig = + { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null + , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile) + , system ? builtins.currentSystem + , pkgs ? mkPkgs sources system + }: rec { + # The sources, i.e. the attribute set of spec name to spec + inherit sources; + + # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers + inherit pkgs; + }; + +in +mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); } diff --git a/MetaLamp/lending-pool/release.nix b/MetaLamp/lending-pool/release.nix new file mode 100644 index 000000000..d83bfbf3f --- /dev/null +++ b/MetaLamp/lending-pool/release.nix @@ -0,0 +1,52 @@ +# The content of this file was partially copied from the equivalent file in the plutus repository. +# It is used by IOHK's Hydra for CI (building the project, running the tests, etc.) +# +# Therefore, do not worry too much about the structure. +let + packages = import ./.; + + pkgs = packages.pkgs; + haskellNix = pkgs.haskell-nix; + + # Just the packages in the project + projectPackages = haskellNix.haskellLib.selectProjectPackages packages.project.hsPkgs; + + inherit (import ./nix/lib/ci.nix { inherit pkgs; }) dimension filterAttrsOnlyRecursive filterDerivations stripAttrsForHydra derivationAggregate; + + # Collects haskell derivations and builds an attrset: + # + # { library = { ... } + # , tests = { ... } + # , benchmarks = { ... } + # , exes = { ... } + # , checks = { ... } + # } + # Where each attribute contains an attribute set + # with all haskell components of that type + mkHaskellDimension = pkgs: haskellProjects: + let + # retrieve all checks from a Haskell package + collectChecks = _: ps: pkgs.haskell-nix.haskellLib.collectChecks' ps; + # retrieve all components of a Haskell package + collectComponents = type: ps: pkgs.haskell-nix.haskellLib.collectComponents' type ps; + # Given a component type and the retrieve function, retrieve components from haskell packages + select = type: selector: (selector type) haskellProjects; + # { component-type : retriever-fn } + attrs = { + "library" = collectComponents; + "tests" = collectComponents; + "benchmarks" = collectComponents; + "exes" = collectComponents; + "checks" = collectChecks; + }; + in + dimension "Haskell component" attrs select; + + ciJobsets = stripAttrsForHydra (filterDerivations { + shell = (import ./shell.nix); + + build = pkgs.recurseIntoAttrs (mkHaskellDimension pkgs projectPackages); + }); +in + ciJobsets // { required = derivationAggregate "required-plutus-starter" ciJobsets; } + diff --git a/MetaLamp/lending-pool/shell.nix b/MetaLamp/lending-pool/shell.nix new file mode 100644 index 000000000..76d271966 --- /dev/null +++ b/MetaLamp/lending-pool/shell.nix @@ -0,0 +1,18 @@ +let + packages = import ./.; + inherit (packages) pkgs plutus-starter; + inherit (plutus-starter) haskell; + +in + haskell.project.shellFor { + withHoogle = false; + + nativeBuildInputs = with plutus-starter; [ + hlint + cabal-install + haskell-language-server + stylish-haskell + pkgs.niv + cardano-repo-tool + ]; + } diff --git a/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs index 94fb78572..28b87b51e 100644 --- a/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs @@ -66,7 +66,7 @@ instance Monoid (ContractResponse e a) where mappend = (<>) withContractResponse :: forall l a p r s. - HasEndpoint l p s + (HasEndpoint l p s, FromJSON p) => Proxy l -> (a -> r) -> (p -> Contract (ContractResponse Text r) s Text a) diff --git a/MetaLamp/lending-pool/src/Plutus/Abstract/State/Select.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/State/Select.hs index eabb0146a..e85c29670 100644 --- a/MetaLamp/lending-pool/src/Plutus/Abstract/State/Select.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/State/Select.hs @@ -40,7 +40,7 @@ getDatum o = case txOutDatumHash $ txOutTxOut o of Nothing -> throwError "datum has wrong type" Just d -> return d -getState :: (HasBlockchainActions s, PlutusTx.IsData datum) => Address -> Contract w s Text [OutputValue datum] +getState :: (PlutusTx.IsData datum) => Address -> Contract w s Text [OutputValue datum] getState address = do utxos <- utxoAt address traverse getDatum' . Map.toList $ utxos @@ -49,7 +49,7 @@ getState address = do d <- getDatum o pure $ OutputValue oref o d -findOutputsBy :: (HasBlockchainActions s, PlutusTx.IsData datum) => +findOutputsBy :: (PlutusTx.IsData datum) => Address -> AssetClass -> (datum -> Maybe a) -> @@ -61,7 +61,7 @@ findOutputsBy address stateToken mapDatum = mapMaybe checkStateToken <$> getStat then fmap (OutputValue oref outTx) (mapDatum datum) else Nothing -findOutputBy :: (HasBlockchainActions s, PlutusTx.IsData datum) => +findOutputBy :: (PlutusTx.IsData datum) => Address -> AssetClass -> (datum -> Maybe a) -> diff --git a/MetaLamp/lending-pool/src/Plutus/Abstract/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/State/Update.hs index b25c0d736..356a047bd 100644 --- a/MetaLamp/lending-pool/src/Plutus/Abstract/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/State/Update.hs @@ -86,7 +86,7 @@ data StateHandle scriptType a = StateHandle { } putState :: - (HasBlockchainActions s, IsData (DatumType scriptType), IsData (RedeemerType scriptType)) => + (IsData (DatumType scriptType), IsData (RedeemerType scriptType)) => PutStateHandle scriptType -> StateHandle scriptType a -> a -> @@ -105,7 +105,7 @@ putState PutStateHandle {..} StateHandle{..} newState = do (assetClassValue ownerToken 1) updateState :: - (HasBlockchainActions s, IsData (DatumType scriptType), IsData (RedeemerType scriptType)) => + (IsData (DatumType scriptType), IsData (RedeemerType scriptType)) => Scripts.TypedValidator scriptType -> StateHandle scriptType a -> OutputValue a -> diff --git a/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs index a542e5dbd..05f55d187 100644 --- a/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs @@ -44,7 +44,7 @@ type TxPair a = (Constraints.ScriptLookups a, Constraints.TxConstraints (Redeeme type IsScriptData a = (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) -submitTxPair :: (AsContractError e, HasWriteTx s, IsScriptData a) => +submitTxPair :: (AsContractError e, IsScriptData a) => TxPair a -> Contract w s e Tx submitTxPair = Prelude.uncurry submitTxConstraintsWith diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs index 4fb7f21ae..ac1c5c356 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs @@ -45,7 +45,7 @@ import qualified PlutusTx.Semigroup as Semigroup import Prelude (Semigroup (..)) import qualified Prelude -forgeATokensFrom :: forall w s. (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text (TxUtils.TxPair AaveScript) +forgeATokensFrom :: forall w s. Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text (TxUtils.TxPair AaveScript) forgeATokensFrom aave reserve pkh amount = do let policy = makeLiquidityPolicy (Core.aaveHash aave) (rCurrency reserve) aTokenAmount = amount -- / rLiquidityIndex reserve -- TODO: how should we divide? @@ -56,7 +56,7 @@ forgeATokensFrom aave reserve pkh amount = do <> (Prelude.mempty, mustPayToPubKey pkh forgeValue) <> TxUtils.mustPayToScript (Core.aaveInstance aave) pkh Core.ReserveFundsDatum payment -burnATokensFrom :: (HasBlockchainActions s) => Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text (TxUtils.TxPair AaveScript) +burnATokensFrom :: Aave -> Reserve -> PubKeyHash -> Integer -> Contract w s Text (TxUtils.TxPair AaveScript) burnATokensFrom aave reserve pkh amount = do let asset = rCurrency reserve let userConfigId = (asset, pkh) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs index 54d3b6959..7171142fb 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs @@ -62,23 +62,22 @@ import qualified Prelude import Text.Printf (printf) -- | Gets current Lending Pool reserves state -reserves :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map AssetClass Reserve) +reserves :: Aave -> Contract w s Text (AssocMap.Map AssetClass Reserve) reserves aave = ovValue <$> State.findAaveReserves aave -- | Gets current Lending Pool user configs state -users :: HasBlockchainActions s => Aave -> Contract w s Text (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) +users :: Aave -> Contract w s Text (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) users aave = ovValue <$> State.findAaveUserConfigs aave -fundsAt :: HasBlockchainActions s => PubKeyHash -> Contract w s Text Value +fundsAt :: PubKeyHash -> Contract w s Text Value fundsAt pkh = utxoValue <$> utxoAt (pubKeyHashAddress pkh) -- | Gets all UTxOs belonging to the Lending Pool script and concats them into one Value -poolFunds :: HasBlockchainActions s => Aave -> Contract w s Text Value +poolFunds :: Aave -> Contract w s Text Value poolFunds aave = utxoValue <$> utxoAt (Core.aaveAddress aave) type AaveInfoSchema = - BlockchainActions - .\/ Endpoint "fundsAt" PubKeyHash + Endpoint "fundsAt" PubKeyHash .\/ Endpoint "poolFunds" () .\/ Endpoint "reserves" () .\/ Endpoint "users" () diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Owner.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Owner.hs index ca2cb309f..7a8dc406d 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Owner.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Owner.hs @@ -88,14 +88,14 @@ createReserve aave CreateParams {..} = } -- | Starts the Lending Pool protocol: minting pool NFTs, creating empty user configuration state and all specified liquidity reserves -start :: HasBlockchainActions s => [CreateParams] -> Contract w s Text Aave +start :: [CreateParams] -> Contract w s Text Aave start = start' $ do pkh <- pubKeyHash <$> ownPubKey fmap Currency.currencySymbol $ mapError (pack . show @Currency.CurrencyError) $ Currency.forgeContract pkh [(Core.aaveProtocolName, 1)] -start' :: HasBlockchainActions s => Contract w s Text CurrencySymbol -> [CreateParams] -> Contract w s Text Aave +start' :: Contract w s Text CurrencySymbol -> [CreateParams] -> Contract w s Text Aave start' getAaveToken params = do aaveToken <- getAaveToken pkh <- pubKeyHash <$> ownPubKey @@ -118,8 +118,7 @@ start' getAaveToken params = do pure aave type AaveOwnerSchema = - BlockchainActions - .\/ Endpoint "start" [CreateParams] + Endpoint "start" [CreateParams] data OwnerContractState = Started Aave deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/State.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/State.hs index 4772d939a..7b53bb1c5 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/State.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/State.hs @@ -55,36 +55,36 @@ import Prelude (Semigroup (..), fmap) import qualified Prelude -findOutputsBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text [OutputValue a] +findOutputsBy :: Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text [OutputValue a] findOutputsBy aave = State.findOutputsBy (Core.aaveAddress aave) -findOutputBy :: HasBlockchainActions s => Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text (OutputValue a) +findOutputBy :: Aave -> AssetClass -> (AaveDatum -> Maybe a) -> Contract w s Text (OutputValue a) findOutputBy aave = State.findOutputBy (Core.aaveAddress aave) -findAaveOwnerToken :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue PubKeyHash) +findAaveOwnerToken :: Aave -> Contract w s Text (OutputValue PubKeyHash) findAaveOwnerToken aave@Aave{..} = findOutputBy aave aaveProtocolInst (^? Core._LendingPoolDatum) reserveStateToken, userStateToken :: Aave -> AssetClass reserveStateToken aave = State.makeStateToken (Core.aaveHash aave) (aaveProtocolInst aave) "aaveReserve" userStateToken aave = State.makeStateToken (Core.aaveHash aave) (aaveProtocolInst aave) "aaveUser" -findAaveReserves :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map AssetClass Reserve)) +findAaveReserves :: Aave -> Contract w s Text (OutputValue (AssocMap.Map AssetClass Reserve)) findAaveReserves aave = findOutputBy aave (reserveStateToken aave) (^? Core._ReservesDatum . _2) -findAaveReserve :: HasBlockchainActions s => Aave -> AssetClass -> Contract w s Text Reserve +findAaveReserve :: Aave -> AssetClass -> Contract w s Text Reserve findAaveReserve aave reserveId = do reserves <- ovValue <$> findAaveReserves aave maybe (throwError "Reserve not found") pure $ AssocMap.lookup reserveId reserves -findAaveUserConfigs :: HasBlockchainActions s => Aave -> Contract w s Text (OutputValue (AssocMap.Map UserConfigId UserConfig)) +findAaveUserConfigs :: Aave -> Contract w s Text (OutputValue (AssocMap.Map UserConfigId UserConfig)) findAaveUserConfigs aave = findOutputBy aave (userStateToken aave) (^? Core._UserConfigsDatum . _2) -findAaveUserConfig :: HasBlockchainActions s => Aave -> UserConfigId -> Contract w s Text UserConfig +findAaveUserConfig :: Aave -> UserConfigId -> Contract w s Text UserConfig findAaveUserConfig aave userConfigId = do configs <- ovValue <$> findAaveUserConfigs aave maybe (throwError "UserConfig not found") pure $ AssocMap.lookup userConfigId configs -putState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> a -> Contract w s Text (TxUtils.TxPair AaveScript) +putState :: Aave -> StateHandle AaveScript a -> a -> Contract w s Text (TxUtils.TxPair AaveScript) putState aave stateHandle newState = do ownerTokenOutput <- fmap Core.LendingPoolDatum <$> findAaveOwnerToken aave State.putState @@ -92,7 +92,7 @@ putState aave stateHandle newState = do stateHandle newState -updateState :: (HasBlockchainActions s) => Aave -> StateHandle AaveScript a -> OutputValue a -> Contract w s Text (TxUtils.TxPair AaveScript, a) +updateState :: Aave -> StateHandle AaveScript a -> OutputValue a -> Contract w s Text (TxUtils.TxPair AaveScript, a) updateState aave = State.updateState (Core.aaveInstance aave) makeReserveHandle :: Aave -> (AssocMap.Map AssetClass Reserve -> AaveRedeemer) -> StateHandle AaveScript (AssocMap.Map AssetClass Reserve) @@ -104,20 +104,20 @@ makeReserveHandle aave toRedeemer = toRedeemer = toRedeemer } -putReserves :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssocMap.Map AssetClass Reserve -> Contract w s Text (TxUtils.TxPair AaveScript) +putReserves :: Aave -> AaveRedeemer -> AssocMap.Map AssetClass Reserve -> Contract w s Text (TxUtils.TxPair AaveScript) putReserves aave redeemer = putState aave $ makeReserveHandle aave (const redeemer) -updateReserves :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map AssetClass Reserve) -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map AssetClass Reserve) +updateReserves :: Aave -> AaveRedeemer -> OutputValue (AssocMap.Map AssetClass Reserve) -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map AssetClass Reserve) updateReserves aave redeemer = updateState aave $ makeReserveHandle aave (const redeemer) -updateReserve :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssetClass -> Reserve -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map AssetClass Reserve) +updateReserve :: Aave -> AaveRedeemer -> AssetClass -> Reserve -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map AssetClass Reserve) updateReserve aave redeemer reserveId reserve = do reservesOutput <- findAaveReserves aave _ <- maybe (throwError "Update failed: reserve not found") pure $ AssocMap.lookup reserveId (ovValue reservesOutput) updateReserves aave redeemer $ Prelude.fmap (AssocMap.insert reserveId reserve) reservesOutput -roundtripReserves :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> Contract w s Text (TxUtils.TxPair AaveScript) +roundtripReserves :: Aave -> AaveRedeemer -> Contract w s Text (TxUtils.TxPair AaveScript) roundtripReserves aave redeemer = do reservesOutput <- findAaveReserves aave fst <$> updateReserves aave redeemer reservesOutput @@ -131,20 +131,20 @@ makeUserHandle aave toRedeemer = toRedeemer = toRedeemer } -putUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> AssocMap.Map UserConfigId UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript) +putUserConfigs :: Aave -> AaveRedeemer -> AssocMap.Map UserConfigId UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript) putUserConfigs aave redeemer = putState aave $ makeUserHandle aave (const redeemer) -updateUserConfigs :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> OutputValue (AssocMap.Map UserConfigId UserConfig) -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map UserConfigId UserConfig) +updateUserConfigs :: Aave -> AaveRedeemer -> OutputValue (AssocMap.Map UserConfigId UserConfig) -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map UserConfigId UserConfig) updateUserConfigs aave redeemer = updateState aave $ makeUserHandle aave (const redeemer) -addUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> UserConfigId -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map UserConfigId UserConfig) +addUserConfig :: Aave -> AaveRedeemer -> UserConfigId -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map UserConfigId UserConfig) addUserConfig aave redeemer userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (pure ()) (const $ throwError "Add user config failed: config exists") $ AssocMap.lookup userConfigId (ovValue configsOutput) updateUserConfigs aave redeemer $ Prelude.fmap (AssocMap.insert userConfigId userConfig) configsOutput -updateUserConfig :: (HasBlockchainActions s) => Aave -> AaveRedeemer -> UserConfigId -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map UserConfigId UserConfig) +updateUserConfig :: Aave -> AaveRedeemer -> UserConfigId -> UserConfig -> Contract w s Text (TxUtils.TxPair AaveScript, AssocMap.Map UserConfigId UserConfig) updateUserConfig aave redeemer userConfigId userConfig = do configsOutput <- findAaveUserConfigs aave _ <- maybe (throwError "Update failed: user config not found") pure $ diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs index b2c97dc9b..7bd81b162 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs @@ -80,7 +80,7 @@ PlutusTx.unstableMakeIsData ''DepositParams PlutusTx.makeLift ''DepositParams -- | The user puts N amount of his asset into a corresponding reserve, in exchange he gets N equivalent aTokens -deposit :: (HasBlockchainActions s) => Aave -> DepositParams -> Contract w s Text () +deposit :: Aave -> DepositParams -> Contract w s Text () deposit aave DepositParams {..} = do reserve <- State.findAaveReserve aave dpAsset forgeTx <- AToken.forgeATokensFrom aave reserve dpOnBehalfOf dpAmount @@ -117,7 +117,7 @@ PlutusTx.unstableMakeIsData ''WithdrawParams PlutusTx.makeLift ''WithdrawParams -- | The user withdraws N amount of a specific asset from the corresponding reserve, N aTokens are taken from his wallet and burned -withdraw :: (HasBlockchainActions s) => Aave -> WithdrawParams -> Contract w s Text () +withdraw :: Aave -> WithdrawParams -> Contract w s Text () withdraw aave WithdrawParams {..} = do reserve <- State.findAaveReserve aave wpAsset let userConfigId = (wpAsset, wpUser) @@ -143,7 +143,7 @@ PlutusTx.unstableMakeIsData ''BorrowParams PlutusTx.makeLift ''BorrowParams -- | The user borrows N amount of a needed asset from the corresponding reserve, his debt entry state is encreased by N -borrow :: (HasBlockchainActions s) => Aave -> BorrowParams -> Contract w s Text () +borrow :: Aave -> BorrowParams -> Contract w s Text () borrow aave BorrowParams {..} = do reserves <- ovValue <$> State.findAaveReserves aave reserve <- maybe (throwError "Reserve not found") pure $ AssocMap.lookup bpAsset reserves @@ -207,7 +207,7 @@ PlutusTx.unstableMakeIsData ''RepayParams PlutusTx.makeLift ''RepayParams -- | The user repays N amount of a specific asset to the corresponding reserve, his debt entry state is decreased by N -repay :: (HasBlockchainActions s) => Aave -> RepayParams -> Contract w s Text () +repay :: Aave -> RepayParams -> Contract w s Text () repay aave RepayParams {..} = do reserve <- State.findAaveReserve aave rpAsset @@ -242,14 +242,14 @@ PlutusTx.unstableMakeIsData ''ProvideCollateralParams PlutusTx.makeLift ''ProvideCollateralParams -- | Gets all UTxOs belonging to a user and concats them into one Value -fundsAt :: HasBlockchainActions s => PubKeyHash -> Contract w s Text Value +fundsAt :: PubKeyHash -> Contract w s Text Value fundsAt pkh = utxoValue <$> utxoAt (pubKeyHashAddress pkh) -balanceAt :: HasBlockchainActions s => PubKeyHash -> AssetClass -> Contract w s Text Integer +balanceAt :: PubKeyHash -> AssetClass -> Contract w s Text Integer balanceAt pkh asset = flip assetClassValueOf asset <$> fundsAt pkh -- | User deposits N amount of aToken as collateral, his investment entry state is increased by N -provideCollateral :: (HasBlockchainActions s) => Aave -> ProvideCollateralParams -> Contract w s Text () +provideCollateral :: Aave -> ProvideCollateralParams -> Contract w s Text () provideCollateral aave ProvideCollateralParams {..} = do reserve <- State.findAaveReserve aave pcpUnderlyingAsset @@ -291,7 +291,7 @@ PlutusTx.unstableMakeIsData ''RevokeCollateralParams PlutusTx.makeLift ''RevokeCollateralParams -- | User withdraws N amount of collateralized aToken, his investment entry state is decreased by N -revokeCollateral :: (HasBlockchainActions s) => Aave -> RevokeCollateralParams -> Contract w s Text () +revokeCollateral :: Aave -> RevokeCollateralParams -> Contract w s Text () revokeCollateral aave RevokeCollateralParams {..} = do reserves <- ovValue <$> State.findAaveReserves aave reserve <- maybe (throwError "Reserve not found") pure $ AssocMap.lookup rcpUnderlyingAsset reserves @@ -334,22 +334,21 @@ revokeCollateral aave RevokeCollateralParams {..} = do getUsersCollateral asset tx = ((> 0) . flip assetClassValueOf asset . txOutValue . txOutTxOut $ tx) && (txOutDatumHash . txOutTxOut $ tx) == Just (datumHash . Datum . PlutusTx.toData $ userDatum asset) -getOwnPubKey :: HasBlockchainActions s => Contract w s Text PubKeyHash +getOwnPubKey :: Contract w s Text PubKeyHash getOwnPubKey = pubKeyHash <$> ownPubKey -ownPubKeyBalance :: HasBlockchainActions s => Contract w s Text Value +ownPubKeyBalance :: Contract w s Text Value ownPubKeyBalance = getOwnPubKey >>= fundsAt type AaveUserSchema = - BlockchainActions - .\/ Endpoint "deposit" DepositParams - .\/ Endpoint "withdraw" WithdrawParams - .\/ Endpoint "borrow" BorrowParams - .\/ Endpoint "repay" RepayParams - .\/ Endpoint "provideCollateral" ProvideCollateralParams - .\/ Endpoint "revokeCollateral" RevokeCollateralParams - .\/ Endpoint "ownPubKey" () - .\/ Endpoint "ownPubKeyBalance" () + Endpoint "deposit" DepositParams + .\/ Endpoint "withdraw" WithdrawParams + .\/ Endpoint "borrow" BorrowParams + .\/ Endpoint "repay" RepayParams + .\/ Endpoint "provideCollateral" ProvideCollateralParams + .\/ Endpoint "revokeCollateral" RevokeCollateralParams + .\/ Endpoint "ownPubKey" () + .\/ Endpoint "ownPubKeyBalance" () data UserContractState = Deposited diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Script.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Script.hs index 4cca7c6db..e6ff63139 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Script.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Script.hs @@ -50,8 +50,6 @@ import PlutusTx.Prelude hiding (Semigroup (..), import Prelude (Semigroup (..)) import qualified Prelude -deriving anyclass instance ToSchema Rational - data Reserve = Reserve { rCurrency :: AssetClass, -- reserve id rAToken :: AssetClass, diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs index 438ae2c4e..35026434f 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs @@ -181,7 +181,7 @@ data OracleParams = OracleParams deriving stock (Prelude.Eq, Prelude.Show, Generic) deriving anyclass (ToJSON, FromJSON, ToSchema) -startOracle :: forall w s. HasBlockchainActions s => OracleParams -> Contract w s Text Oracle +startOracle :: forall w s. OracleParams -> Contract w s Text Oracle startOracle op = do pkh <- pubKeyHash <$> Contract.ownPubKey osc <- mapError (pack . Prelude.show) (forgeContract pkh [(oracleTokenName, 1)] :: Contract w s CurrencyError OneShotCurrency) @@ -195,7 +195,7 @@ startOracle op = do logInfo @Prelude.String $ "started oracle " ++ Prelude.show oracle return oracle -updateOracle :: forall w s. HasBlockchainActions s => Oracle -> Integer -> Contract w s Text () +updateOracle :: forall w s. Oracle -> Integer -> Contract w s Text () updateOracle oracle x = do m <- findOracle oracle let c = Constraints.mustPayToTheScript x $ assetClassValue (oracleAsset oracle) 1 @@ -213,7 +213,7 @@ updateOracle oracle x = do awaitTxConfirmed $ txId ledgerTx logInfo @Prelude.String $ "updated oracle value to " ++ Prelude.show x -findOracle :: forall w s. HasBlockchainActions s => Oracle -> Contract w s Text (Maybe (TxOutRef, TxOutTx, Integer)) +findOracle :: forall w s. Oracle -> Contract w s Text (Maybe (TxOutRef, TxOutTx, Integer)) findOracle oracle = do utxos <- Map.filter f <$> utxoAt (oracleAddress oracle) return $ case Map.toList utxos of @@ -227,7 +227,7 @@ findOracle oracle = do useOracle :: forall a w s. - ( HasBlockchainActions s, TxUtils.IsScriptData a + ( TxUtils.IsScriptData a ) => (CurrencySymbol, PubKeyHash, Integer, AssetClass) -> Contract w s Text (TxUtils.TxPair a) @@ -244,7 +244,7 @@ useOracle (fromTuple -> oracle) = do where oracleCoin = oracleAsset oracle -type OracleSchema = BlockchainActions .\/ Endpoint "update" Integer +type OracleSchema = Endpoint "update" Integer runOracle :: OracleParams -> Contract (Last Oracle) OracleSchema Text () runOracle op = do diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 3d4a129d4..8f69978e5 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -85,7 +85,7 @@ toAsset tokenName = distributeFunds :: [Wallet] -> [AssetClass] -> - Contract () BlockchainActions Text () + Contract () EmptySchema Text () distributeFunds wallets assets = do ownPK <- pubKeyHash <$> ownPubKey let testCurrenciesValue = mconcat $ fmap (`assetClassValue` 1000) assets @@ -104,7 +104,7 @@ distributeFunds wallets assets = do createOracles :: [AssetClass] -> - Contract (Monoid.Last [Oracle.Oracle]) BlockchainActions Text () + Contract (Monoid.Last [Oracle.Oracle]) EmptySchema Text () createOracles assets = do oracles <- forM assets $ \asset -> do let oracleParams = Oracle.OracleParams @@ -273,9 +273,9 @@ handleAaveContract :: ~> Eff effs handleAaveContract = Builtin.handleBuiltin getSchema getContract where getSchema = \case - AaveUser _ -> Builtin.endpointsToSchemas @(Aave.AaveUserSchema .\\ BlockchainActions) - AaveInfo _ -> Builtin.endpointsToSchemas @(Aave.AaveInfoSchema .\\ BlockchainActions) - AaveStart -> Builtin.endpointsToSchemas @(Aave.AaveOwnerSchema .\\ BlockchainActions) + AaveUser _ -> Builtin.endpointsToSchemas @Aave.AaveUserSchema + AaveInfo _ -> Builtin.endpointsToSchemas @Aave.AaveInfoSchema + AaveStart -> Builtin.endpointsToSchemas @Aave.AaveOwnerSchema DistributeFunds _ _ -> Builtin.endpointsToSchemas @Empty CreateOracles _ -> Builtin.endpointsToSchemas @Empty getContract = \case diff --git a/MetaLamp/lending-pool/test/Fixtures/Init.hs b/MetaLamp/lending-pool/test/Fixtures/Init.hs index 85742b794..7b66213a1 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Init.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Init.hs @@ -70,7 +70,7 @@ startTrace = do _ <- Trace.waitNSlots 5 pure () -startOracles :: Contract () BlockchainActions Text () +startOracles :: Contract () EmptySchema Text () startOracles = forM_ oracles (\oracle -> do _ <- forgeSymbol Oracle.oracleTokenName diff --git a/MetaLamp/lending-pool/test/Fixtures/Symbol.hs b/MetaLamp/lending-pool/test/Fixtures/Symbol.hs index f765c3f74..f6737d7fc 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Symbol.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Symbol.hs @@ -34,7 +34,7 @@ makePolicy tokenName = Scripts.mkMonetaryPolicyScript $ getSymbol :: TokenName -> CurrencySymbol getSymbol = Ledger.scriptCurrencySymbol . makePolicy -forgeSymbol :: HasBlockchainActions s => TokenName -> Contract () s Text CurrencySymbol +forgeSymbol :: TokenName -> Contract () s Text CurrencySymbol forgeSymbol tokenName = do pkh <- Ledger.pubKeyHash <$> ownPubKey let symbol = getSymbol tokenName diff --git a/MetaLamp/lending-pool/test/Utils/Trace.hs b/MetaLamp/lending-pool/test/Utils/Trace.hs index 603219669..e7de24026 100644 --- a/MetaLamp/lending-pool/test/Utils/Trace.hs +++ b/MetaLamp/lending-pool/test/Utils/Trace.hs @@ -20,7 +20,6 @@ import Ledger (Address) import qualified Ledger import Ledger.AddressMap (UtxoMap) import Plutus.Abstract.ContractResponse (ContractResponse (..)) -import Plutus.Contract (HasBlockchainActions) import Plutus.Contract.Test (TracePredicate) import qualified Plutus.Trace.Emulator as Trace import Plutus.Trace.Emulator.Types (EmulatorRuntimeError (..)) @@ -31,7 +30,6 @@ import Wallet.Emulator.MultiAgent (EmulatorEvent) getState :: (Show a , Show e - , HasBlockchainActions s , Trace.ContractConstraints s , JSON.FromJSON e , JSON.FromJSON a @@ -47,7 +45,7 @@ getState pick userHandle = do case res of ContractSuccess s -> maybe (throwError . GenericError $ "Unexpected state: " <> show s) pure (pick s) ContractError e -> throwError . GenericError . show $ e - s -> throwError . JSONDecodingError $ "Unexpected state: " <> show s + s -> throwError $ EmulatorJSONDecodingError ("Unexpected state: " <> show s) (JSON.toJSON s) utxoAtAddress :: Monad m => Address -> (UtxoMap -> m c)-> L.FoldM m EmulatorEvent c utxoAtAddress address check = Folds.postMapM check (L.generalize $ Folds.utxoAtAddress address) From ba6fec5ef71aa5ce18444774ecf5c5552d84ea9a Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Mon, 12 Jul 2021 14:36:37 +0700 Subject: [PATCH 157/169] update generate-purs --- MetaLamp/lending-pool/generate-purs/Main.hs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/MetaLamp/lending-pool/generate-purs/Main.hs b/MetaLamp/lending-pool/generate-purs/Main.hs index a3d528b2a..0aa6125a8 100644 --- a/MetaLamp/lending-pool/generate-purs/Main.hs +++ b/MetaLamp/lending-pool/generate-purs/Main.hs @@ -48,18 +48,10 @@ import qualified PSGenerator.Common import Plutus.Contract.Checkpoint (CheckpointKey, CheckpointStore, CheckpointStoreItem) -import Plutus.Contract.Effects.AwaitSlot (WaitingForSlot) -import Plutus.Contract.Effects.AwaitTxConfirmed (TxConfirmed) -import Plutus.Contract.Effects.ExposeEndpoint (ActiveEndpoint, - EndpointValue) -import Plutus.Contract.Effects.Instance (OwnIdRequest) -import Plutus.Contract.Effects.OwnPubKey (OwnPubKeyRequest) -import Plutus.Contract.Effects.UtxoAt (UtxoAtAddress) -import Plutus.Contract.Effects.WriteTx (WriteTxResponse) +import Plutus.Contract.Effects (TxConfirmed, ActiveEndpoint, UtxoAtAddress, WriteTxResponse, PABReq(..), PABResp(..)) +import Wallet.Types (EndpointValue) import Plutus.Contract.Resumable (Responses) import Plutus.PAB.Effects.Contract.ContractExe (ContractExe) -import Plutus.PAB.Events.Contract (ContractPABRequest, - ContractPABResponse) import Plutus.PAB.Events.ContractInstanceState (PartiallyDecodedResponse) import qualified Plutus.PAB.Webserver.API as API import Plutus.PAB.Webserver.Types (ChainReport, @@ -133,25 +125,22 @@ myTypes = , (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractSignatureResponse A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(PartiallyDecodedResponse A)) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @ContractPABRequest) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @ContractPABResponse) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @PABReq) + , (equal <*> (genericShow <*> mkSumType)) (Proxy @PABResp) , (equal <*> (genericShow <*> mkSumType)) (Proxy @UnbalancedTx) -- Contract request / response types , (equal <*> (genericShow <*> mkSumType)) (Proxy @ActiveEndpoint) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(EndpointValue A)) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @OwnPubKeyRequest) , (equal <*> (genericShow <*> mkSumType)) (Proxy @TxConfirmed) , (equal <*> (genericShow <*> mkSumType)) (Proxy @UtxoAtAddress) , (equal <*> (genericShow <*> mkSumType)) (Proxy @WriteTxResponse) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @WaitingForSlot) , (equal <*> (genericShow <*> mkSumType)) (Proxy @CheckpointStore) , (order <*> (genericShow <*> mkSumType)) (Proxy @CheckpointKey) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(CheckpointStoreItem A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(Responses A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @AddressChangeRequest) , (equal <*> (genericShow <*> mkSumType)) (Proxy @AddressChangeResponse) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @OwnIdRequest) -- Logging types , (equal <*> (genericShow <*> mkSumType)) (Proxy @(LogMessage A)) From 38288ed595249cd56ee74188cad76eb622f5e118 Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Tue, 13 Jul 2021 12:45:48 +0700 Subject: [PATCH 158/169] setup nix for client --- .../lending-pool/client/package-lock.json | 2754 ++++++++--------- MetaLamp/lending-pool/generate-purs/Main.hs | 15 +- MetaLamp/lending-pool/nix/pkgs/default.nix | 6 +- MetaLamp/lending-pool/package-lock.json | 3 + MetaLamp/lending-pool/shell.nix | 2 + .../lending-pool/src/Plutus/PAB/Simulation.hs | 10 +- 6 files changed, 1392 insertions(+), 1398 deletions(-) create mode 100644 MetaLamp/lending-pool/package-lock.json diff --git a/MetaLamp/lending-pool/client/package-lock.json b/MetaLamp/lending-pool/client/package-lock.json index 77b310829..801b20ea7 100644 --- a/MetaLamp/lending-pool/client/package-lock.json +++ b/MetaLamp/lending-pool/client/package-lock.json @@ -14,8 +14,8 @@ "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", "requires": { - "@types/minimatch": "*", - "@types/node": "*" + "@types/minimatch": "3.0.4", + "@types/node": "15.12.1" } }, "@types/minimatch": { @@ -95,7 +95,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", "requires": { - "@xtuc/ieee754": "^1.2.0" + "@xtuc/ieee754": "1.2.0" } }, "@webassemblyjs/leb128": { @@ -205,7 +205,7 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "requires": { - "mime-types": "~2.1.24", + "mime-types": "2.1.31", "negotiator": "0.6.2" } }, @@ -219,10 +219,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.1.0", + "json-schema-traverse": "0.3.1" } }, "ajv-errors": { @@ -266,8 +266,8 @@ "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "optional": true, "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "normalize-path": "3.0.0", + "picomatch": "2.3.0" } }, "aproba": { @@ -280,8 +280,8 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "delegates": "1.0.0", + "readable-stream": "2.3.7" }, "dependencies": { "readable-stream": { @@ -289,13 +289,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -308,7 +308,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -343,7 +343,7 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "requires": { - "array-uniq": "^1.0.1" + "array-uniq": "1.0.3" } }, "array-uniq": { @@ -366,7 +366,7 @@ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "requires": { - "safer-buffer": "~2.1.0" + "safer-buffer": "2.1.2" } }, "asn1.js": { @@ -374,10 +374,10 @@ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" + "bn.js": "4.12.0", + "inherits": "2.0.4", + "minimalistic-assert": "1.0.1", + "safer-buffer": "2.1.2" }, "dependencies": { "bn.js": { @@ -392,7 +392,7 @@ "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", "requires": { - "object-assign": "^4.1.1", + "object-assign": "4.1.1", "util": "0.10.3" }, "dependencies": { @@ -426,7 +426,7 @@ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "requires": { - "lodash": "^4.17.14" + "lodash": "4.17.21" } }, "async-each": { @@ -469,9 +469,9 @@ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "chalk": "1.1.3", + "esutils": "2.0.3", + "js-tokens": "3.0.2" } }, "balanced-match": { @@ -484,13 +484,13 @@ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.3.0", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.2", + "pascalcase": "0.1.1" }, "dependencies": { "define-property": { @@ -498,7 +498,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -506,7 +506,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-data-descriptor": { @@ -514,7 +514,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-descriptor": { @@ -522,9 +522,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.3" } } } @@ -544,7 +544,7 @@ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "requires": { - "tweetnacl": "^0.14.3" + "tweetnacl": "0.14.5" } }, "big.js": { @@ -573,7 +573,7 @@ "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", "requires": { - "inherits": "~2.0.0" + "inherits": "2.0.4" } }, "bluebird": { @@ -592,15 +592,15 @@ "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", "requires": { "bytes": "3.1.0", - "content-type": "~1.0.4", + "content-type": "1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "1.1.2", "http-errors": "1.7.2", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", + "on-finished": "2.3.0", "qs": "6.7.0", "raw-body": "2.4.0", - "type-is": "~1.6.17" + "type-is": "1.6.18" }, "dependencies": { "bytes": { @@ -620,12 +620,12 @@ "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" + "array-flatten": "2.1.2", + "deep-equal": "1.1.1", + "dns-equal": "1.0.0", + "dns-txt": "2.0.2", + "multicast-dns": "6.2.3", + "multicast-dns-service-types": "1.1.0" } }, "boolbase": { @@ -643,7 +643,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { - "balanced-match": "^1.0.0", + "balanced-match": "1.0.2", "concat-map": "0.0.1" } }, @@ -652,16 +652,16 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "repeat-element": "1.1.4", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" }, "dependencies": { "extend-shallow": { @@ -669,7 +669,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -684,12 +684,12 @@ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "buffer-xor": "1.0.3", + "cipher-base": "1.0.4", + "create-hash": "1.2.0", + "evp_bytestokey": "1.0.3", + "inherits": "2.0.4", + "safe-buffer": "5.2.1" } }, "browserify-cipher": { @@ -697,9 +697,9 @@ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" + "browserify-aes": "1.2.0", + "browserify-des": "1.0.2", + "evp_bytestokey": "1.0.3" } }, "browserify-des": { @@ -707,10 +707,10 @@ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "cipher-base": "1.0.4", + "des.js": "1.0.1", + "inherits": "2.0.4", + "safe-buffer": "5.2.1" } }, "browserify-rsa": { @@ -718,8 +718,8 @@ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", "requires": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" + "bn.js": "5.2.0", + "randombytes": "2.1.0" } }, "browserify-sign": { @@ -727,15 +727,15 @@ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" + "bn.js": "5.2.0", + "browserify-rsa": "4.1.0", + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "elliptic": "6.5.4", + "inherits": "2.0.4", + "parse-asn1": "5.1.6", + "readable-stream": "3.6.0", + "safe-buffer": "5.2.1" } }, "browserify-zlib": { @@ -743,7 +743,7 @@ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "requires": { - "pako": "~1.0.5" + "pako": "1.0.11" } }, "buffer": { @@ -751,9 +751,9 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "base64-js": "1.5.1", + "ieee754": "1.2.1", + "isarray": "1.0.0" } }, "buffer-from": { @@ -786,21 +786,21 @@ "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" + "bluebird": "3.7.2", + "chownr": "1.1.4", + "figgy-pudding": "3.5.2", + "glob": "7.1.7", + "graceful-fs": "4.2.6", + "infer-owner": "1.0.4", + "lru-cache": "5.1.1", + "mississippi": "3.0.0", + "mkdirp": "0.5.5", + "move-concurrently": "1.0.1", + "promise-inflight": "1.0.1", + "rimraf": "2.7.1", + "ssri": "6.0.2", + "unique-filename": "1.1.1", + "y18n": "4.0.3" }, "dependencies": { "lru-cache": { @@ -808,7 +808,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "requires": { - "yallist": "^3.0.2" + "yallist": "3.1.1" } }, "yallist": { @@ -823,15 +823,15 @@ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "collection-visit": "1.0.0", + "component-emitter": "1.3.0", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.1", + "to-object-path": "0.3.0", + "union-value": "1.0.1", + "unset-value": "1.0.0" } }, "call-bind": { @@ -839,8 +839,8 @@ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "function-bind": "1.1.1", + "get-intrinsic": "1.1.1" } }, "camel-case": { @@ -848,8 +848,8 @@ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.1.1" + "no-case": "2.3.2", + "upper-case": "1.1.3" } }, "camelcase": { @@ -862,8 +862,8 @@ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" + "camelcase": "2.1.1", + "map-obj": "1.0.1" } }, "caseless": { @@ -876,11 +876,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" } }, "chokidar": { @@ -889,14 +889,14 @@ "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", "optional": true, "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.3.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" + "anymatch": "3.1.2", + "braces": "3.0.2", + "fsevents": "2.3.2", + "glob-parent": "5.1.2", + "is-binary-path": "2.1.0", + "is-glob": "4.0.1", + "normalize-path": "3.0.0", + "readdirp": "3.5.0" }, "dependencies": { "braces": { @@ -905,7 +905,7 @@ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "optional": true, "requires": { - "fill-range": "^7.0.1" + "fill-range": "7.0.1" } }, "fill-range": { @@ -914,7 +914,7 @@ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "optional": true, "requires": { - "to-regex-range": "^5.0.1" + "to-regex-range": "5.0.1" } }, "is-number": { @@ -929,7 +929,7 @@ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "optional": true, "requires": { - "is-number": "^7.0.0" + "is-number": "7.0.0" } } } @@ -949,8 +949,8 @@ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "2.0.4", + "safe-buffer": "5.2.1" } }, "class-utils": { @@ -958,10 +958,10 @@ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" }, "dependencies": { "define-property": { @@ -969,7 +969,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -979,7 +979,7 @@ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", "requires": { - "source-map": "~0.6.0" + "source-map": "0.6.1" } }, "cliui": { @@ -987,9 +987,9 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" + "string-width": "3.1.0", + "strip-ansi": "5.2.0", + "wrap-ansi": "5.1.0" }, "dependencies": { "ansi-regex": { @@ -1007,9 +1007,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "7.0.3", + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "5.2.0" } }, "strip-ansi": { @@ -1017,7 +1017,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "4.1.0" } } } @@ -1027,9 +1027,9 @@ "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" + "is-plain-object": "2.0.4", + "kind-of": "6.0.3", + "shallow-clone": "3.0.1" } }, "co": { @@ -1047,8 +1047,8 @@ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "map-visit": "1.0.0", + "object-visit": "1.0.1" } }, "color-convert": { @@ -1069,7 +1069,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "requires": { - "delayed-stream": "~1.0.0" + "delayed-stream": "1.0.0" } }, "commander": { @@ -1092,7 +1092,7 @@ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "requires": { - "mime-db": ">= 1.43.0 < 2" + "mime-db": "1.48.0" } }, "compression": { @@ -1100,13 +1100,13 @@ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "requires": { - "accepts": "~1.3.5", + "accepts": "1.3.7", "bytes": "3.0.0", - "compressible": "~2.0.16", + "compressible": "2.0.18", "debug": "2.6.9", - "on-headers": "~1.0.2", + "on-headers": "1.0.2", "safe-buffer": "5.1.2", - "vary": "~1.1.2" + "vary": "1.1.2" }, "dependencies": { "safe-buffer": { @@ -1126,10 +1126,10 @@ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "buffer-from": "1.1.1", + "inherits": "2.0.4", + "readable-stream": "2.3.7", + "typedarray": "0.0.6" }, "dependencies": { "readable-stream": { @@ -1137,13 +1137,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -1156,7 +1156,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -1216,12 +1216,12 @@ "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" + "aproba": "1.2.0", + "fs-write-stream-atomic": "1.0.10", + "iferr": "0.1.5", + "mkdirp": "0.5.5", + "rimraf": "2.7.1", + "run-queue": "1.0.3" } }, "copy-descriptor": { @@ -1239,8 +1239,8 @@ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" + "bn.js": "4.12.0", + "elliptic": "6.5.4" }, "dependencies": { "bn.js": { @@ -1255,11 +1255,11 @@ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" + "cipher-base": "1.0.4", + "inherits": "2.0.4", + "md5.js": "1.3.5", + "ripemd160": "2.0.2", + "sha.js": "2.4.11" } }, "create-hmac": { @@ -1267,12 +1267,12 @@ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "cipher-base": "1.0.4", + "create-hash": "1.2.0", + "inherits": "2.0.4", + "ripemd160": "2.0.2", + "safe-buffer": "5.2.1", + "sha.js": "2.4.11" } }, "cross-spawn": { @@ -1280,8 +1280,8 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" + "lru-cache": "4.1.5", + "which": "1.3.1" } }, "crypto-browserify": { @@ -1289,17 +1289,17 @@ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" + "browserify-cipher": "1.0.1", + "browserify-sign": "4.2.1", + "create-ecdh": "4.0.4", + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "diffie-hellman": "5.0.3", + "inherits": "2.0.4", + "pbkdf2": "3.1.2", + "public-encrypt": "4.0.3", + "randombytes": "2.1.0", + "randomfill": "1.0.4" } }, "css-loader": { @@ -1307,18 +1307,18 @@ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-1.0.1.tgz", "integrity": "sha512-+ZHAZm/yqvJ2kDtPne3uX0C+Vr3Zn5jFn2N4HywtS5ujwvsVkyg0VArEXpl3BgczDA8anieki1FIzhchX4yrDw==", "requires": { - "babel-code-frame": "^6.26.0", - "css-selector-tokenizer": "^0.7.0", - "icss-utils": "^2.1.0", - "loader-utils": "^1.0.2", - "lodash": "^4.17.11", - "postcss": "^6.0.23", - "postcss-modules-extract-imports": "^1.2.0", - "postcss-modules-local-by-default": "^1.2.0", - "postcss-modules-scope": "^1.1.0", - "postcss-modules-values": "^1.3.0", - "postcss-value-parser": "^3.3.0", - "source-list-map": "^2.0.0" + "babel-code-frame": "6.26.0", + "css-selector-tokenizer": "0.7.3", + "icss-utils": "2.1.0", + "loader-utils": "1.4.0", + "lodash": "4.17.21", + "postcss": "6.0.23", + "postcss-modules-extract-imports": "1.2.1", + "postcss-modules-local-by-default": "1.2.0", + "postcss-modules-scope": "1.1.0", + "postcss-modules-values": "1.3.0", + "postcss-value-parser": "3.3.1", + "source-list-map": "2.0.1" } }, "css-select": { @@ -1326,10 +1326,10 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", "requires": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" + "boolbase": "1.0.0", + "css-what": "3.4.2", + "domutils": "1.7.0", + "nth-check": "1.0.2" } }, "css-selector-tokenizer": { @@ -1337,8 +1337,8 @@ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", "requires": { - "cssesc": "^3.0.0", - "fastparse": "^1.1.2" + "cssesc": "3.0.0", + "fastparse": "1.1.2" } }, "css-what": { @@ -1356,7 +1356,7 @@ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", "requires": { - "array-find-index": "^1.0.1" + "array-find-index": "1.0.2" } }, "cyclist": { @@ -1374,7 +1374,7 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "debug": { @@ -1400,12 +1400,12 @@ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" + "is-arguments": "1.1.0", + "is-date-object": "1.0.4", + "is-regex": "1.1.3", + "object-is": "1.1.5", + "object-keys": "1.1.1", + "regexp.prototype.flags": "1.3.1" } }, "default-gateway": { @@ -1413,8 +1413,8 @@ "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", "requires": { - "execa": "^1.0.0", - "ip-regex": "^2.1.0" + "execa": "1.0.0", + "ip-regex": "2.1.0" } }, "define-properties": { @@ -1422,7 +1422,7 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "requires": { - "object-keys": "^1.0.12" + "object-keys": "1.1.1" } }, "define-property": { @@ -1430,8 +1430,8 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "is-descriptor": "1.0.2", + "isobject": "3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -1439,7 +1439,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-data-descriptor": { @@ -1447,7 +1447,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-descriptor": { @@ -1455,9 +1455,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.3" } } } @@ -1467,13 +1467,13 @@ "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", "requires": { - "@types/glob": "^7.1.1", - "globby": "^6.1.0", - "is-path-cwd": "^2.0.0", - "is-path-in-cwd": "^2.0.0", - "p-map": "^2.0.0", - "pify": "^4.0.1", - "rimraf": "^2.6.3" + "@types/glob": "7.1.3", + "globby": "6.1.0", + "is-path-cwd": "2.2.0", + "is-path-in-cwd": "2.1.0", + "p-map": "2.1.0", + "pify": "4.0.1", + "rimraf": "2.7.1" }, "dependencies": { "globby": { @@ -1481,11 +1481,11 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "array-union": "1.0.2", + "glob": "7.1.7", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" }, "dependencies": { "pify": { @@ -1522,8 +1522,8 @@ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "inherits": "2.0.4", + "minimalistic-assert": "1.0.1" } }, "destroy": { @@ -1546,9 +1546,9 @@ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" + "bn.js": "4.12.0", + "miller-rabin": "4.0.1", + "randombytes": "2.1.0" }, "dependencies": { "bn.js": { @@ -1568,8 +1568,8 @@ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" + "ip": "1.1.5", + "safe-buffer": "5.2.1" } }, "dns-txt": { @@ -1577,7 +1577,7 @@ "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", "requires": { - "buffer-indexof": "^1.0.0" + "buffer-indexof": "1.1.1" } }, "dom-converter": { @@ -1585,7 +1585,7 @@ "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", "requires": { - "utila": "~0.4" + "utila": "0.4.0" } }, "dom-serializer": { @@ -1593,8 +1593,8 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" + "domelementtype": "2.2.0", + "entities": "2.2.0" }, "dependencies": { "domelementtype": { @@ -1619,7 +1619,7 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", "requires": { - "domelementtype": "1" + "domelementtype": "1.3.1" } }, "domutils": { @@ -1627,8 +1627,8 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "dom-serializer": "0.2.2", + "domelementtype": "1.3.1" } }, "duplexify": { @@ -1636,10 +1636,10 @@ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" + "end-of-stream": "1.4.4", + "inherits": "2.0.4", + "readable-stream": "2.3.7", + "stream-shift": "1.0.1" }, "dependencies": { "readable-stream": { @@ -1647,13 +1647,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -1666,7 +1666,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -1676,8 +1676,8 @@ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "jsbn": "0.1.1", + "safer-buffer": "2.1.2" } }, "ee-first": { @@ -1690,13 +1690,13 @@ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" + "bn.js": "4.12.0", + "brorand": "1.1.0", + "hash.js": "1.1.7", + "hmac-drbg": "1.0.1", + "inherits": "2.0.4", + "minimalistic-assert": "1.0.1", + "minimalistic-crypto-utils": "1.0.1" }, "dependencies": { "bn.js": { @@ -1726,7 +1726,7 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "requires": { - "once": "^1.4.0" + "once": "1.4.0" } }, "enhanced-resolve": { @@ -1734,9 +1734,9 @@ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" + "graceful-fs": "4.2.6", + "memory-fs": "0.5.0", + "tapable": "1.1.3" }, "dependencies": { "memory-fs": { @@ -1744,8 +1744,8 @@ "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" + "errno": "0.1.8", + "readable-stream": "2.3.7" } }, "readable-stream": { @@ -1753,13 +1753,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -1772,7 +1772,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -1792,7 +1792,7 @@ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "requires": { - "prr": "~1.0.1" + "prr": "1.0.1" } }, "error-ex": { @@ -1800,7 +1800,7 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "requires": { - "is-arrayish": "^0.2.1" + "is-arrayish": "0.2.1" } }, "es-abstract": { @@ -1808,22 +1808,22 @@ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "is-callable": "^1.2.3", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.3", - "is-string": "^1.0.6", - "object-inspect": "^1.10.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "call-bind": "1.0.2", + "es-to-primitive": "1.2.1", + "function-bind": "1.1.1", + "get-intrinsic": "1.1.1", + "has": "1.0.3", + "has-symbols": "1.0.2", + "is-callable": "1.2.3", + "is-negative-zero": "2.0.1", + "is-regex": "1.1.3", + "is-string": "1.0.6", + "object-inspect": "1.10.3", + "object-keys": "1.1.1", + "object.assign": "4.1.2", + "string.prototype.trimend": "1.0.4", + "string.prototype.trimstart": "1.0.4", + "unbox-primitive": "1.0.1" } }, "es-to-primitive": { @@ -1831,9 +1831,9 @@ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "1.2.3", + "is-date-object": "1.0.4", + "is-symbol": "1.0.4" } }, "escape-html": { @@ -1851,8 +1851,8 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "esrecurse": "4.3.0", + "estraverse": "4.3.0" } }, "esrecurse": { @@ -1860,7 +1860,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "requires": { - "estraverse": "^5.2.0" + "estraverse": "5.2.0" }, "dependencies": { "estraverse": { @@ -1900,7 +1900,7 @@ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", "requires": { - "original": "^1.0.0" + "original": "1.0.2" } }, "evp_bytestokey": { @@ -1908,8 +1908,8 @@ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" + "md5.js": "1.3.5", + "safe-buffer": "5.2.1" } }, "execa": { @@ -1917,13 +1917,13 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "6.0.5", + "get-stream": "4.1.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.3", + "strip-eof": "1.0.0" }, "dependencies": { "cross-spawn": { @@ -1931,11 +1931,11 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "nice-try": "1.0.5", + "path-key": "2.0.1", + "semver": "5.7.1", + "shebang-command": "1.2.0", + "which": "1.3.1" } } } @@ -1945,13 +1945,13 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -1959,7 +1959,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -1967,7 +1967,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -1977,7 +1977,7 @@ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "requires": { - "homedir-polyfill": "^1.0.1" + "homedir-polyfill": "1.0.3" } }, "express": { @@ -1985,36 +1985,36 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", "requires": { - "accepts": "~1.3.7", + "accepts": "1.3.7", "array-flatten": "1.1.1", "body-parser": "1.19.0", "content-disposition": "0.5.3", - "content-type": "~1.0.4", + "content-type": "1.0.4", "cookie": "0.4.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "depd": "1.1.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.2", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", + "proxy-addr": "2.0.7", "qs": "6.7.0", - "range-parser": "~1.2.1", + "range-parser": "1.2.1", "safe-buffer": "5.1.2", "send": "0.17.1", "serve-static": "1.14.1", "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", + "statuses": "1.5.0", + "type-is": "1.6.18", "utils-merge": "1.0.1", - "vary": "~1.1.2" + "vary": "1.1.2" }, "dependencies": { "array-flatten": { @@ -2044,8 +2044,8 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -2053,7 +2053,7 @@ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -2063,14 +2063,14 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -2078,7 +2078,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "extend-shallow": { @@ -2086,7 +2086,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "is-accessor-descriptor": { @@ -2094,7 +2094,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-data-descriptor": { @@ -2102,7 +2102,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-descriptor": { @@ -2110,9 +2110,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.3" } } } @@ -2122,10 +2122,10 @@ "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz", "integrity": "sha512-bt/LZ4m5Rqt/Crl2HiKuAl/oqg0psx1tsTLkvWbJen1CtD+fftkZhMaQ9HOtY2gWsl2Wq+sABmMVi9z3DhKWQQ==", "requires": { - "async": "^2.4.1", - "loader-utils": "^1.1.0", - "schema-utils": "^0.3.0", - "webpack-sources": "^1.0.1" + "async": "2.6.3", + "loader-utils": "1.4.0", + "schema-utils": "0.3.0", + "webpack-sources": "1.4.3" } }, "extsprintf": { @@ -2153,7 +2153,7 @@ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "requires": { - "websocket-driver": ">=0.5.1" + "websocket-driver": "0.7.4" } }, "figgy-pudding": { @@ -2166,8 +2166,8 @@ "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-2.0.0.tgz", "integrity": "sha512-YCsBfd1ZGCyonOKLxPiKPdu+8ld9HAaMEvJewzz+b2eTF7uL5Zm/HdBF6FjCrpCMRq25Mi0U1gl4pwn2TlH7hQ==", "requires": { - "loader-utils": "^1.0.2", - "schema-utils": "^1.0.0" + "loader-utils": "1.4.0", + "schema-utils": "1.0.0" }, "dependencies": { "ajv": { @@ -2175,10 +2175,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "3.1.3", + "fast-json-stable-stringify": "2.1.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.4.1" } }, "fast-deep-equal": { @@ -2196,9 +2196,9 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "ajv": "6.12.6", + "ajv-errors": "1.0.1", + "ajv-keywords": "3.5.2" } } } @@ -2208,10 +2208,10 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" }, "dependencies": { "extend-shallow": { @@ -2219,7 +2219,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -2230,12 +2230,12 @@ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.3", + "statuses": "1.5.0", + "unpipe": "1.0.0" } }, "find-cache-dir": { @@ -2243,9 +2243,9 @@ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" + "commondir": "1.0.1", + "make-dir": "2.1.0", + "pkg-dir": "3.0.0" } }, "find-up": { @@ -2253,8 +2253,8 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" } }, "findup-sync": { @@ -2262,10 +2262,10 @@ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" + "detect-file": "1.0.0", + "is-glob": "4.0.1", + "micromatch": "3.1.10", + "resolve-dir": "1.0.1" } }, "flush-write-stream": { @@ -2273,8 +2273,8 @@ "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" + "inherits": "2.0.4", + "readable-stream": "2.3.7" }, "dependencies": { "readable-stream": { @@ -2282,13 +2282,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -2301,7 +2301,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -2326,9 +2326,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "asynckit": "0.4.0", + "combined-stream": "1.0.8", + "mime-types": "2.1.31" } }, "forwarded": { @@ -2341,7 +2341,7 @@ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "requires": { - "map-cache": "^0.2.2" + "map-cache": "0.2.2" } }, "fresh": { @@ -2354,8 +2354,8 @@ "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" + "inherits": "2.0.4", + "readable-stream": "2.3.7" }, "dependencies": { "readable-stream": { @@ -2363,13 +2363,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -2382,7 +2382,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -2392,10 +2392,10 @@ "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" + "graceful-fs": "4.2.6", + "iferr": "0.1.5", + "imurmurhash": "0.1.4", + "readable-stream": "2.3.7" }, "dependencies": { "readable-stream": { @@ -2403,13 +2403,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -2422,7 +2422,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -2443,10 +2443,10 @@ "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" + "graceful-fs": "4.2.6", + "inherits": "2.0.4", + "mkdirp": "0.5.5", + "rimraf": "2.7.1" } }, "function-bind": { @@ -2459,14 +2459,14 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.3", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.3" } }, "gaze": { @@ -2474,7 +2474,7 @@ "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", "requires": { - "globule": "^1.0.0" + "globule": "1.3.2" } }, "get-caller-file": { @@ -2487,9 +2487,9 @@ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "function-bind": "1.1.1", + "has": "1.0.3", + "has-symbols": "1.0.2" } }, "get-stdin": { @@ -2502,7 +2502,7 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "requires": { - "pump": "^3.0.0" + "pump": "3.0.0" } }, "get-value": { @@ -2515,7 +2515,7 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { - "assert-plus": "^1.0.0" + "assert-plus": "1.0.0" } }, "glob": { @@ -2523,12 +2523,12 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.4", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } }, "glob-parent": { @@ -2537,7 +2537,7 @@ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "optional": true, "requires": { - "is-glob": "^4.0.1" + "is-glob": "4.0.1" } }, "global-modules": { @@ -2545,7 +2545,7 @@ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", "requires": { - "global-prefix": "^3.0.0" + "global-prefix": "3.0.0" }, "dependencies": { "global-prefix": { @@ -2553,9 +2553,9 @@ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", "requires": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" + "ini": "1.3.8", + "kind-of": "6.0.3", + "which": "1.3.1" } } } @@ -2565,11 +2565,11 @@ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "expand-tilde": "2.0.2", + "homedir-polyfill": "1.0.3", + "ini": "1.3.8", + "is-windows": "1.0.2", + "which": "1.3.1" } }, "globby": { @@ -2577,12 +2577,12 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-4.1.0.tgz", "integrity": "sha1-CA9UVJ7BuCpsYOYx/ILhIR2+lfg=", "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^6.0.1", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "6.0.4", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" }, "dependencies": { "glob": { @@ -2590,11 +2590,11 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "inflight": "1.0.6", + "inherits": "2.0.4", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" } } } @@ -2604,9 +2604,9 @@ "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz", "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==", "requires": { - "glob": "~7.1.1", - "lodash": "~4.17.10", - "minimatch": "~3.0.2" + "glob": "7.1.7", + "lodash": "4.17.21", + "minimatch": "3.0.4" } }, "graceful-fs": { @@ -2629,8 +2629,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" + "ajv": "6.12.6", + "har-schema": "2.0.0" }, "dependencies": { "ajv": { @@ -2638,10 +2638,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "3.1.3", + "fast-json-stable-stringify": "2.1.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.4.1" } }, "fast-deep-equal": { @@ -2661,7 +2661,7 @@ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "requires": { - "function-bind": "^1.1.1" + "function-bind": "1.1.1" } }, "has-ansi": { @@ -2669,7 +2669,7 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "has-bigints": { @@ -2697,9 +2697,9 @@ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" } }, "has-values": { @@ -2707,8 +2707,8 @@ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "is-number": "3.0.0", + "kind-of": "4.0.0" }, "dependencies": { "kind-of": { @@ -2716,7 +2716,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -2726,9 +2726,9 @@ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" + "inherits": "2.0.4", + "readable-stream": "3.6.0", + "safe-buffer": "5.2.1" } }, "hash.js": { @@ -2736,8 +2736,8 @@ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" + "inherits": "2.0.4", + "minimalistic-assert": "1.0.1" } }, "he": { @@ -2750,9 +2750,9 @@ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" + "hash.js": "1.1.7", + "minimalistic-assert": "1.0.1", + "minimalistic-crypto-utils": "1.0.1" } }, "homedir-polyfill": { @@ -2760,7 +2760,7 @@ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "requires": { - "parse-passwd": "^1.0.0" + "parse-passwd": "1.0.0" } }, "hosted-git-info": { @@ -2773,10 +2773,10 @@ "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" + "inherits": "2.0.4", + "obuf": "1.1.2", + "readable-stream": "2.3.7", + "wbuf": "1.7.3" }, "dependencies": { "readable-stream": { @@ -2784,13 +2784,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -2803,7 +2803,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -2818,13 +2818,13 @@ "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", "requires": { - "camel-case": "3.0.x", - "clean-css": "4.2.x", - "commander": "2.17.x", - "he": "1.2.x", - "param-case": "2.1.x", - "relateurl": "0.2.x", - "uglify-js": "3.4.x" + "camel-case": "3.0.0", + "clean-css": "4.2.3", + "commander": "2.17.1", + "he": "1.2.0", + "param-case": "2.1.1", + "relateurl": "0.2.7", + "uglify-js": "3.4.10" } }, "html-webpack-plugin": { @@ -2832,12 +2832,12 @@ "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", "requires": { - "html-minifier": "^3.2.3", - "loader-utils": "^0.2.16", - "lodash": "^4.17.3", - "pretty-error": "^2.0.2", - "tapable": "^1.0.0", - "toposort": "^1.0.0", + "html-minifier": "3.5.21", + "loader-utils": "0.2.17", + "lodash": "4.17.21", + "pretty-error": "2.1.2", + "tapable": "1.1.3", + "toposort": "1.0.7", "util.promisify": "1.0.0" }, "dependencies": { @@ -2861,10 +2861,10 @@ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0", - "object-assign": "^4.0.1" + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" } } } @@ -2874,12 +2874,12 @@ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" + "domelementtype": "1.3.1", + "domhandler": "2.4.2", + "domutils": "1.7.0", + "entities": "1.1.2", + "inherits": "2.0.4", + "readable-stream": "3.6.0" }, "dependencies": { "entities": { @@ -2899,10 +2899,10 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", "requires": { - "depd": "~1.1.2", + "depd": "1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", + "statuses": "1.5.0", "toidentifier": "1.0.0" }, "dependencies": { @@ -2923,9 +2923,9 @@ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" + "eventemitter3": "4.0.7", + "follow-redirects": "1.14.1", + "requires-port": "1.0.0" } }, "http-proxy-middleware": { @@ -2933,10 +2933,10 @@ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", "requires": { - "http-proxy": "^1.17.0", - "is-glob": "^4.0.0", - "lodash": "^4.17.11", - "micromatch": "^3.1.10" + "http-proxy": "1.18.1", + "is-glob": "4.0.1", + "lodash": "4.17.21", + "micromatch": "3.1.10" } }, "http-signature": { @@ -2944,9 +2944,9 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.16.1" } }, "https-browserify": { @@ -2959,7 +2959,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": "2.1.2" } }, "icss-replace-symbols": { @@ -2972,7 +2972,7 @@ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", "requires": { - "postcss": "^6.0.1" + "postcss": "6.0.23" } }, "ieee754": { @@ -2990,8 +2990,8 @@ "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" + "pkg-dir": "3.0.0", + "resolve-cwd": "2.0.0" } }, "imurmurhash": { @@ -3009,7 +3009,7 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "requires": { - "repeating": "^2.0.0" + "repeating": "2.0.1" } }, "infer-owner": { @@ -3022,8 +3022,8 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { - "once": "^1.3.0", - "wrappy": "1" + "once": "1.4.0", + "wrappy": "1.0.2" } }, "inherits": { @@ -3041,8 +3041,8 @@ "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", "requires": { - "default-gateway": "^4.2.0", - "ipaddr.js": "^1.9.0" + "default-gateway": "4.2.0", + "ipaddr.js": "1.9.1" } }, "interpret": { @@ -3075,7 +3075,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -3083,7 +3083,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -3093,7 +3093,7 @@ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", "requires": { - "call-bind": "^1.0.0" + "call-bind": "1.0.2" } }, "is-arrayish": { @@ -3112,7 +3112,7 @@ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "optional": true, "requires": { - "binary-extensions": "^2.0.0" + "binary-extensions": "2.2.0" } }, "is-boolean-object": { @@ -3120,7 +3120,7 @@ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", "requires": { - "call-bind": "^1.0.2" + "call-bind": "1.0.2" } }, "is-buffer": { @@ -3138,7 +3138,7 @@ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", "requires": { - "has": "^1.0.3" + "has": "1.0.3" } }, "is-data-descriptor": { @@ -3146,7 +3146,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -3154,7 +3154,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -3169,9 +3169,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" }, "dependencies": { "kind-of": { @@ -3201,7 +3201,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "number-is-nan": "^1.0.0" + "number-is-nan": "1.0.1" } }, "is-glob": { @@ -3209,7 +3209,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "requires": { - "is-extglob": "^2.1.1" + "is-extglob": "2.1.1" } }, "is-negative-zero": { @@ -3222,7 +3222,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -3230,7 +3230,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -3250,7 +3250,7 @@ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", "requires": { - "is-path-inside": "^2.1.0" + "is-path-inside": "2.1.0" } }, "is-path-inside": { @@ -3258,7 +3258,7 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", "requires": { - "path-is-inside": "^1.0.2" + "path-is-inside": "1.0.2" } }, "is-plain-object": { @@ -3266,7 +3266,7 @@ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "is-regex": { @@ -3274,8 +3274,8 @@ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", "requires": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" + "call-bind": "1.0.2", + "has-symbols": "1.0.2" } }, "is-stream": { @@ -3293,7 +3293,7 @@ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "requires": { - "has-symbols": "^1.0.2" + "has-symbols": "1.0.2" } }, "is-typedarray": { @@ -3366,7 +3366,7 @@ "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", "requires": { - "bignumber.js": "^9.0.0" + "bignumber.js": "9.0.1" } }, "json-parse-better-errors": { @@ -3399,7 +3399,7 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "requires": { - "minimist": "^1.2.0" + "minimist": "1.2.5" } }, "jsprim": { @@ -3428,11 +3428,11 @@ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "graceful-fs": "4.2.6", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" } }, "loader-runner": { @@ -3445,9 +3445,9 @@ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "big.js": "5.2.2", + "emojis-list": "3.0.0", + "json5": "1.0.1" } }, "locate-path": { @@ -3455,8 +3455,8 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "3.0.0", + "path-exists": "3.0.0" }, "dependencies": { "path-exists": { @@ -3486,8 +3486,8 @@ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.3" } }, "lower-case": { @@ -3500,8 +3500,8 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "pseudomap": "1.0.2", + "yallist": "2.1.2" } }, "make-dir": { @@ -3509,8 +3509,8 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "pify": "4.0.1", + "semver": "5.7.1" }, "dependencies": { "pify": { @@ -3535,7 +3535,7 @@ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "requires": { - "object-visit": "^1.0.0" + "object-visit": "1.0.1" } }, "md5.js": { @@ -3543,9 +3543,9 @@ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "hash-base": "3.1.0", + "inherits": "2.0.4", + "safe-buffer": "5.2.1" } }, "media-typer": { @@ -3558,8 +3558,8 @@ "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" + "errno": "0.1.8", + "readable-stream": "2.3.7" }, "dependencies": { "readable-stream": { @@ -3567,13 +3567,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -3586,7 +3586,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -3596,16 +3596,16 @@ "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.5", + "normalize-package-data": "2.5.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" } }, "merge-descriptors": { @@ -3623,19 +3623,19 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.3", + "nanomatch": "1.2.13", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "miller-rabin": { @@ -3643,8 +3643,8 @@ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" + "bn.js": "4.12.0", + "brorand": "1.1.0" }, "dependencies": { "bn.js": { @@ -3687,7 +3687,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "brace-expansion": "^1.1.7" + "brace-expansion": "1.1.11" } }, "minimist": { @@ -3700,16 +3700,16 @@ "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" + "concat-stream": "1.6.2", + "duplexify": "3.7.1", + "end-of-stream": "1.4.4", + "flush-write-stream": "1.1.1", + "from2": "2.3.0", + "parallel-transform": "1.2.0", + "pump": "3.0.0", + "pumpify": "1.5.1", + "stream-each": "1.2.3", + "through2": "2.0.5" } }, "mixin-deep": { @@ -3717,8 +3717,8 @@ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" + "for-in": "1.0.2", + "is-extendable": "1.0.1" }, "dependencies": { "is-extendable": { @@ -3726,7 +3726,7 @@ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "requires": { - "is-plain-object": "^2.0.4" + "is-plain-object": "2.0.4" } } } @@ -3736,7 +3736,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "requires": { - "minimist": "^1.2.5" + "minimist": "1.2.5" } }, "move-concurrently": { @@ -3744,12 +3744,12 @@ "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" + "aproba": "1.2.0", + "copy-concurrently": "1.0.5", + "fs-write-stream-atomic": "1.0.10", + "mkdirp": "0.5.5", + "rimraf": "2.7.1", + "run-queue": "1.0.3" } }, "ms": { @@ -3762,8 +3762,8 @@ "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" + "dns-packet": "1.3.4", + "thunky": "1.1.0" } }, "multicast-dns-service-types": { @@ -3781,17 +3781,17 @@ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-windows": "1.0.2", + "kind-of": "6.0.3", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" } }, "negotiator": { @@ -3814,7 +3814,7 @@ "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", "requires": { - "lower-case": "^1.1.1" + "lower-case": "1.1.4" } }, "node-forge": { @@ -3827,18 +3827,18 @@ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", "requires": { - "fstream": "^1.0.0", - "glob": "^7.0.3", - "graceful-fs": "^4.1.2", - "mkdirp": "^0.5.0", - "nopt": "2 || 3", - "npmlog": "0 || 1 || 2 || 3 || 4", - "osenv": "0", - "request": "^2.87.0", - "rimraf": "2", - "semver": "~5.3.0", - "tar": "^2.0.0", - "which": "1" + "fstream": "1.0.12", + "glob": "7.1.7", + "graceful-fs": "4.2.6", + "mkdirp": "0.5.5", + "nopt": "3.0.6", + "npmlog": "4.1.2", + "osenv": "0.1.5", + "request": "2.88.2", + "rimraf": "2.7.1", + "semver": "5.3.0", + "tar": "2.2.2", + "which": "1.3.1" }, "dependencies": { "semver": { @@ -3853,29 +3853,29 @@ "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", + "assert": "1.5.0", + "browserify-zlib": "0.2.0", + "buffer": "4.9.2", + "console-browserify": "1.2.0", + "constants-browserify": "1.0.0", + "crypto-browserify": "3.12.0", + "domain-browser": "1.2.0", + "events": "3.3.0", + "https-browserify": "1.0.0", + "os-browserify": "0.3.0", "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", + "process": "0.11.10", + "punycode": "1.4.1", + "querystring-es3": "0.2.1", + "readable-stream": "2.3.7", + "stream-browserify": "2.0.2", + "stream-http": "2.8.3", + "string_decoder": "1.3.0", + "timers-browserify": "2.0.12", "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" + "url": "0.11.0", + "util": "0.11.1", + "vm-browserify": "1.1.2" }, "dependencies": { "punycode": { @@ -3888,13 +3888,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" }, "dependencies": { "string_decoder": { @@ -3902,7 +3902,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -3919,23 +3919,23 @@ "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz", "integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==", "requires": { - "async-foreach": "^0.1.3", - "chalk": "^1.1.1", - "cross-spawn": "^3.0.0", - "gaze": "^1.0.0", - "get-stdin": "^4.0.1", - "glob": "^7.0.3", - "in-publish": "^2.0.0", - "lodash": "^4.17.15", - "meow": "^3.7.0", - "mkdirp": "^0.5.1", - "nan": "^2.13.2", - "node-gyp": "^3.8.0", - "npmlog": "^4.0.0", - "request": "^2.88.0", + "async-foreach": "0.1.3", + "chalk": "1.1.3", + "cross-spawn": "3.0.1", + "gaze": "1.1.3", + "get-stdin": "4.0.1", + "glob": "7.1.7", + "in-publish": "2.0.1", + "lodash": "4.17.21", + "meow": "3.7.0", + "mkdirp": "0.5.5", + "nan": "2.14.2", + "node-gyp": "3.8.0", + "npmlog": "4.1.2", + "request": "2.88.2", "sass-graph": "2.2.5", - "stdout-stream": "^1.4.0", - "true-case-path": "^1.0.2" + "stdout-stream": "1.4.1", + "true-case-path": "1.0.3" } }, "nopt": { @@ -3943,7 +3943,7 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "requires": { - "abbrev": "1" + "abbrev": "1.1.1" } }, "normalize-package-data": { @@ -3951,10 +3951,10 @@ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "hosted-git-info": "2.8.9", + "resolve": "1.20.0", + "semver": "5.7.1", + "validate-npm-package-license": "3.0.4" } }, "normalize-path": { @@ -3967,7 +3967,7 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "requires": { - "path-key": "^2.0.0" + "path-key": "2.0.1" } }, "npmlog": { @@ -3975,10 +3975,10 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "are-we-there-yet": "1.1.5", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" } }, "nth-check": { @@ -3986,7 +3986,7 @@ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", "requires": { - "boolbase": "~1.0.0" + "boolbase": "1.0.0" } }, "number-is-nan": { @@ -4009,9 +4009,9 @@ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" }, "dependencies": { "define-property": { @@ -4019,7 +4019,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "kind-of": { @@ -4027,7 +4027,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -4042,8 +4042,8 @@ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "1.0.2", + "define-properties": "1.1.3" } }, "object-keys": { @@ -4056,7 +4056,7 @@ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "requires": { - "isobject": "^3.0.0" + "isobject": "3.0.1" } }, "object.assign": { @@ -4064,10 +4064,10 @@ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" + "call-bind": "1.0.2", + "define-properties": "1.1.3", + "has-symbols": "1.0.2", + "object-keys": "1.1.1" } }, "object.getownpropertydescriptors": { @@ -4075,9 +4075,9 @@ "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2" + "call-bind": "1.0.2", + "define-properties": "1.1.3", + "es-abstract": "1.18.3" } }, "object.pick": { @@ -4085,7 +4085,7 @@ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "requires": { - "isobject": "^3.0.1" + "isobject": "3.0.1" } }, "obuf": { @@ -4111,7 +4111,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1" + "wrappy": "1.0.2" } }, "opn": { @@ -4119,7 +4119,7 @@ "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", "requires": { - "is-wsl": "^1.1.0" + "is-wsl": "1.1.0" } }, "original": { @@ -4127,7 +4127,7 @@ "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", "requires": { - "url-parse": "^1.4.3" + "url-parse": "1.5.1" } }, "os-browserify": { @@ -4150,8 +4150,8 @@ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" } }, "p-finally": { @@ -4164,7 +4164,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { - "p-try": "^2.0.0" + "p-try": "2.2.0" } }, "p-locate": { @@ -4172,7 +4172,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "requires": { - "p-limit": "^2.0.0" + "p-limit": "2.3.0" } }, "p-map": { @@ -4185,7 +4185,7 @@ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", "requires": { - "retry": "^0.12.0" + "retry": "0.12.0" }, "dependencies": { "retry": { @@ -4210,9 +4210,9 @@ "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", "requires": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" + "cyclist": "1.0.1", + "inherits": "2.0.4", + "readable-stream": "2.3.7" }, "dependencies": { "readable-stream": { @@ -4220,13 +4220,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -4239,7 +4239,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -4249,7 +4249,7 @@ "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", "requires": { - "no-case": "^2.2.0" + "no-case": "2.3.2" } }, "parse-asn1": { @@ -4257,11 +4257,11 @@ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" + "asn1.js": "5.4.1", + "browserify-aes": "1.2.0", + "evp_bytestokey": "1.0.3", + "pbkdf2": "3.1.2", + "safe-buffer": "5.2.1" } }, "parse-json": { @@ -4269,7 +4269,7 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "requires": { - "error-ex": "^1.2.0" + "error-ex": "1.3.2" } }, "parse-passwd": { @@ -4302,7 +4302,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "requires": { - "pinkie-promise": "^2.0.0" + "pinkie-promise": "2.0.1" } }, "path-is-absolute": { @@ -4335,9 +4335,9 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "graceful-fs": "4.2.6", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" } }, "pbkdf2": { @@ -4345,11 +4345,11 @@ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "create-hash": "1.2.0", + "create-hmac": "1.1.7", + "ripemd160": "2.0.2", + "safe-buffer": "5.2.1", + "sha.js": "2.4.11" } }, "performance-now": { @@ -4360,8 +4360,7 @@ "picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "optional": true + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" }, "pify": { "version": "2.3.0", @@ -4378,7 +4377,7 @@ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "requires": { - "pinkie": "^2.0.0" + "pinkie": "2.0.4" } }, "pkg-dir": { @@ -4386,7 +4385,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "requires": { - "find-up": "^3.0.0" + "find-up": "3.0.0" }, "dependencies": { "find-up": { @@ -4394,7 +4393,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { - "locate-path": "^3.0.0" + "locate-path": "3.0.0" } } } @@ -4404,9 +4403,9 @@ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" + "async": "2.6.3", + "debug": "3.2.7", + "mkdirp": "0.5.5" }, "dependencies": { "debug": { @@ -4414,7 +4413,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.3" } }, "ms": { @@ -4434,9 +4433,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" + "chalk": "2.4.2", + "source-map": "0.6.1", + "supports-color": "5.5.0" }, "dependencies": { "ansi-styles": { @@ -4444,7 +4443,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.3" } }, "chalk": { @@ -4452,9 +4451,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" } }, "supports-color": { @@ -4462,7 +4461,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -4472,7 +4471,7 @@ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz", "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==", "requires": { - "postcss": "^6.0.1" + "postcss": "6.0.23" } }, "postcss-modules-local-by-default": { @@ -4480,8 +4479,8 @@ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", "requires": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" + "css-selector-tokenizer": "0.7.3", + "postcss": "6.0.23" } }, "postcss-modules-scope": { @@ -4489,8 +4488,8 @@ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", "requires": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" + "css-selector-tokenizer": "0.7.3", + "postcss": "6.0.23" } }, "postcss-modules-values": { @@ -4498,8 +4497,8 @@ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", "requires": { - "icss-replace-symbols": "^1.1.0", - "postcss": "^6.0.1" + "icss-replace-symbols": "1.1.0", + "postcss": "6.0.23" } }, "postcss-value-parser": { @@ -4512,8 +4511,8 @@ "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", "requires": { - "lodash": "^4.17.20", - "renderkid": "^2.0.4" + "lodash": "4.17.21", + "renderkid": "2.0.5" } }, "process": { @@ -4536,8 +4535,8 @@ "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", "requires": { - "err-code": "^1.0.0", - "retry": "^0.10.0" + "err-code": "1.1.2", + "retry": "0.10.1" } }, "proxy-addr": { @@ -4569,12 +4568,12 @@ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" + "bn.js": "4.12.0", + "browserify-rsa": "4.1.0", + "create-hash": "1.2.0", + "parse-asn1": "5.1.6", + "randombytes": "2.1.0", + "safe-buffer": "5.2.1" }, "dependencies": { "bn.js": { @@ -4589,8 +4588,8 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "1.4.4", + "once": "1.4.0" } }, "pumpify": { @@ -4598,9 +4597,9 @@ "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" + "duplexify": "3.7.1", + "inherits": "2.0.4", + "pump": "2.0.1" }, "dependencies": { "pump": { @@ -4608,8 +4607,8 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "end-of-stream": "1.4.4", + "once": "1.4.0" } } } @@ -4624,16 +4623,16 @@ "resolved": "https://registry.npmjs.org/purs-loader/-/purs-loader-3.7.2.tgz", "integrity": "sha512-Sidqk2RE1R2DTPt30I6G3p//c9pMaV9jd36NI3HXXSyf4Kf5X01FiP/2wMTJ8a5XKAXKdKCJ3WPqA8Whlxi0tg==", "requires": { - "bluebird": "^3.3.5", - "chalk": "^1.1.3", - "cross-spawn": "^3.0.1", - "dargs": "^5.1.0", - "debug": "^2.6.0", - "globby": "^4.0.0", - "js-string-escape": "^1.0.1", - "loader-utils": "^1.0.2", - "lodash.difference": "^4.5.0", - "promise-retry": "^1.1.0" + "bluebird": "3.7.2", + "chalk": "1.1.3", + "cross-spawn": "3.0.1", + "dargs": "5.1.0", + "debug": "2.6.9", + "globby": "4.1.0", + "js-string-escape": "1.0.1", + "loader-utils": "1.4.0", + "lodash.difference": "4.5.0", + "promise-retry": "1.1.1" } }, "qs": { @@ -4661,7 +4660,7 @@ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "requires": { - "safe-buffer": "^5.1.0" + "safe-buffer": "5.2.1" } }, "randomfill": { @@ -4669,8 +4668,8 @@ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" + "randombytes": "2.1.0", + "safe-buffer": "5.2.1" } }, "range-parser": { @@ -4701,9 +4700,9 @@ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "load-json-file": "1.1.0", + "normalize-package-data": "2.5.0", + "path-type": "1.1.0" } }, "read-pkg-up": { @@ -4711,8 +4710,8 @@ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "find-up": "1.1.2", + "read-pkg": "1.1.0" } }, "readable-stream": { @@ -4720,9 +4719,9 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "inherits": "2.0.4", + "string_decoder": "1.3.0", + "util-deprecate": "1.0.2" } }, "readdirp": { @@ -4731,7 +4730,7 @@ "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", "optional": true, "requires": { - "picomatch": "^2.2.1" + "picomatch": "2.3.0" } }, "redent": { @@ -4739,8 +4738,8 @@ "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" + "indent-string": "2.1.0", + "strip-indent": "1.0.1" } }, "regex-not": { @@ -4748,8 +4747,8 @@ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" } }, "regexp.prototype.flags": { @@ -4757,8 +4756,8 @@ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "1.0.2", + "define-properties": "1.1.3" } }, "relateurl": { @@ -4776,11 +4775,11 @@ "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.5.tgz", "integrity": "sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ==", "requires": { - "css-select": "^2.0.2", - "dom-converter": "^0.2", - "htmlparser2": "^3.10.1", - "lodash": "^4.17.20", - "strip-ansi": "^3.0.0" + "css-select": "2.1.0", + "dom-converter": "0.2.0", + "htmlparser2": "3.10.1", + "lodash": "4.17.21", + "strip-ansi": "3.0.1" } }, "repeat-element": { @@ -4798,7 +4797,7 @@ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "requires": { - "is-finite": "^1.0.0" + "is-finite": "1.1.0" } }, "request": { @@ -4806,26 +4805,26 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" + "aws-sign2": "0.7.0", + "aws4": "1.11.0", + "caseless": "0.12.0", + "combined-stream": "1.0.8", + "extend": "3.0.2", + "forever-agent": "0.6.1", + "form-data": "2.3.3", + "har-validator": "5.1.5", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.31", + "oauth-sign": "0.9.0", + "performance-now": "2.1.0", + "qs": "6.5.2", + "safe-buffer": "5.2.1", + "tough-cookie": "2.5.0", + "tunnel-agent": "0.6.0", + "uuid": "3.4.0" }, "dependencies": { "uuid": { @@ -4855,8 +4854,8 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "is-core-module": "2.4.0", + "path-parse": "1.0.7" } }, "resolve-cwd": { @@ -4864,7 +4863,7 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", "requires": { - "resolve-from": "^3.0.0" + "resolve-from": "3.0.0" } }, "resolve-dir": { @@ -4872,8 +4871,8 @@ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" + "expand-tilde": "2.0.2", + "global-modules": "1.0.0" }, "dependencies": { "global-modules": { @@ -4881,9 +4880,9 @@ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "global-prefix": "1.0.2", + "is-windows": "1.0.2", + "resolve-dir": "1.0.1" } } } @@ -4913,7 +4912,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { - "glob": "^7.1.3" + "glob": "7.1.7" } }, "ripemd160": { @@ -4921,8 +4920,8 @@ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "hash-base": "3.1.0", + "inherits": "2.0.4" } }, "run-queue": { @@ -4930,7 +4929,7 @@ "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", "requires": { - "aproba": "^1.1.1" + "aproba": "1.2.0" } }, "safe-buffer": { @@ -4943,7 +4942,7 @@ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { - "ret": "~0.1.10" + "ret": "0.1.15" } }, "safer-buffer": { @@ -4956,10 +4955,10 @@ "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", "requires": { - "glob": "^7.0.0", - "lodash": "^4.0.0", - "scss-tokenizer": "^0.2.3", - "yargs": "^13.3.2" + "glob": "7.1.7", + "lodash": "4.17.21", + "scss-tokenizer": "0.2.3", + "yargs": "13.3.2" } }, "sass-loader": { @@ -4967,11 +4966,11 @@ "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.3.1.tgz", "integrity": "sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA==", "requires": { - "clone-deep": "^4.0.1", - "loader-utils": "^1.0.1", - "neo-async": "^2.5.0", - "pify": "^4.0.1", - "semver": "^6.3.0" + "clone-deep": "4.0.1", + "loader-utils": "1.4.0", + "neo-async": "2.6.2", + "pify": "4.0.1", + "semver": "6.3.0" }, "dependencies": { "pify": { @@ -4991,7 +4990,7 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", "requires": { - "ajv": "^5.0.0" + "ajv": "5.5.2" } }, "scss-tokenizer": { @@ -4999,8 +4998,8 @@ "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", "requires": { - "js-base64": "^2.1.8", - "source-map": "^0.4.2" + "js-base64": "2.6.4", + "source-map": "0.4.4" }, "dependencies": { "source-map": { @@ -5008,7 +5007,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "requires": { - "amdefine": ">=0.0.4" + "amdefine": "1.0.1" } } } @@ -5023,7 +5022,7 @@ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz", "integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==", "requires": { - "node-forge": "^0.10.0" + "node-forge": "0.10.0" } }, "semver": { @@ -5037,18 +5036,18 @@ "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", + "depd": "1.1.2", + "destroy": "1.0.4", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "1.7.2", "mime": "1.6.0", "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "on-finished": "2.3.0", + "range-parser": "1.2.1", + "statuses": "1.5.0" }, "dependencies": { "mime": { @@ -5068,7 +5067,7 @@ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", "requires": { - "randombytes": "^2.1.0" + "randombytes": "2.1.0" } }, "serve-index": { @@ -5076,13 +5075,13 @@ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", "requires": { - "accepts": "~1.3.4", + "accepts": "1.3.7", "batch": "0.6.1", "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" + "escape-html": "1.0.3", + "http-errors": "1.6.3", + "mime-types": "2.1.31", + "parseurl": "1.3.3" }, "dependencies": { "http-errors": { @@ -5090,10 +5089,10 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { - "depd": "~1.1.2", + "depd": "1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "statuses": "1.5.0" } }, "inherits": { @@ -5113,9 +5112,9 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "parseurl": "1.3.3", "send": "0.17.1" } }, @@ -5129,10 +5128,10 @@ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" }, "dependencies": { "extend-shallow": { @@ -5140,7 +5139,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } } } @@ -5160,8 +5159,8 @@ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "2.0.4", + "safe-buffer": "5.2.1" } }, "shallow-clone": { @@ -5169,7 +5168,7 @@ "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "requires": { - "kind-of": "^6.0.2" + "kind-of": "6.0.3" } }, "shebang-command": { @@ -5177,7 +5176,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "requires": { - "shebang-regex": "^1.0.0" + "shebang-regex": "1.0.0" } }, "shebang-regex": { @@ -5195,14 +5194,14 @@ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.3", + "use": "3.1.1" }, "dependencies": { "define-property": { @@ -5210,7 +5209,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } }, "extend-shallow": { @@ -5218,7 +5217,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "^0.1.0" + "is-extendable": "0.1.1" } }, "source-map": { @@ -5233,9 +5232,9 @@ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" }, "dependencies": { "define-property": { @@ -5243,7 +5242,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "^1.0.0" + "is-descriptor": "1.0.2" } }, "is-accessor-descriptor": { @@ -5251,7 +5250,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-data-descriptor": { @@ -5259,7 +5258,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "^6.0.0" + "kind-of": "6.0.3" } }, "is-descriptor": { @@ -5267,9 +5266,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.3" } } } @@ -5279,7 +5278,7 @@ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "requires": { - "kind-of": "^3.2.0" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -5287,7 +5286,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -5297,9 +5296,9 @@ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", "requires": { - "faye-websocket": "^0.11.3", - "uuid": "^3.4.0", - "websocket-driver": "^0.7.4" + "faye-websocket": "0.11.4", + "uuid": "3.4.0", + "websocket-driver": "0.7.4" }, "dependencies": { "uuid": { @@ -5314,12 +5313,12 @@ "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.1.tgz", "integrity": "sha512-VnVAb663fosipI/m6pqRXakEOw7nvd7TUgdr3PlR/8V2I95QIdwT8L4nMxhyU8SmDBHYXU1TOElaKOmKLfYzeQ==", "requires": { - "debug": "^3.2.6", - "eventsource": "^1.0.7", - "faye-websocket": "^0.11.3", - "inherits": "^2.0.4", - "json3": "^3.3.3", - "url-parse": "^1.5.1" + "debug": "3.2.7", + "eventsource": "1.1.0", + "faye-websocket": "0.11.4", + "inherits": "2.0.4", + "json3": "3.3.3", + "url-parse": "1.5.1" }, "dependencies": { "debug": { @@ -5327,7 +5326,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.3" } }, "ms": { @@ -5352,11 +5351,11 @@ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "atob": "2.1.2", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.1", + "urix": "0.1.0" } }, "source-map-support": { @@ -5364,8 +5363,8 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "buffer-from": "1.1.1", + "source-map": "0.6.1" } }, "source-map-url": { @@ -5378,8 +5377,8 @@ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "spdx-expression-parse": "3.0.1", + "spdx-license-ids": "3.0.9" } }, "spdx-exceptions": { @@ -5392,8 +5391,8 @@ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "spdx-exceptions": "2.3.0", + "spdx-license-ids": "3.0.9" } }, "spdx-license-ids": { @@ -5406,11 +5405,11 @@ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" + "debug": "4.3.1", + "handle-thing": "2.0.1", + "http-deceiver": "1.2.7", + "select-hose": "2.0.0", + "spdy-transport": "3.0.0" }, "dependencies": { "debug": { @@ -5433,12 +5432,12 @@ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" + "debug": "4.3.1", + "detect-node": "2.1.0", + "hpack.js": "2.1.6", + "obuf": "1.1.2", + "readable-stream": "3.6.0", + "wbuf": "1.7.3" }, "dependencies": { "debug": { @@ -5461,7 +5460,7 @@ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "requires": { - "extend-shallow": "^3.0.0" + "extend-shallow": "3.0.2" } }, "sshpk": { @@ -5469,15 +5468,15 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" + "asn1": "0.2.4", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.2", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.2", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "safer-buffer": "2.1.2", + "tweetnacl": "0.14.5" } }, "ssri": { @@ -5485,7 +5484,7 @@ "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", "requires": { - "figgy-pudding": "^3.5.1" + "figgy-pudding": "3.5.2" } }, "static-extend": { @@ -5493,8 +5492,8 @@ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "define-property": "0.2.5", + "object-copy": "0.1.0" }, "dependencies": { "define-property": { @@ -5502,7 +5501,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "^0.1.0" + "is-descriptor": "0.1.6" } } } @@ -5517,7 +5516,7 @@ "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", "requires": { - "readable-stream": "^2.0.1" + "readable-stream": "2.3.7" }, "dependencies": { "readable-stream": { @@ -5525,13 +5524,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -5544,7 +5543,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -5554,8 +5553,8 @@ "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" + "inherits": "2.0.4", + "readable-stream": "2.3.7" }, "dependencies": { "readable-stream": { @@ -5563,13 +5562,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -5582,7 +5581,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -5592,8 +5591,8 @@ "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" + "end-of-stream": "1.4.4", + "stream-shift": "1.0.1" } }, "stream-http": { @@ -5601,11 +5600,11 @@ "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" + "builtin-status-codes": "3.0.0", + "inherits": "2.0.4", + "readable-stream": "2.3.7", + "to-arraybuffer": "1.0.1", + "xtend": "4.0.2" }, "dependencies": { "readable-stream": { @@ -5613,13 +5612,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -5632,7 +5631,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -5647,9 +5646,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" } }, "string.prototype.trimend": { @@ -5657,8 +5656,8 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "1.0.2", + "define-properties": "1.1.3" } }, "string.prototype.trimstart": { @@ -5666,8 +5665,8 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "1.0.2", + "define-properties": "1.1.3" } }, "string_decoder": { @@ -5675,7 +5674,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "requires": { - "safe-buffer": "~5.2.0" + "safe-buffer": "5.2.1" } }, "strip-ansi": { @@ -5683,7 +5682,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "^2.0.0" + "ansi-regex": "2.1.1" } }, "strip-bom": { @@ -5691,7 +5690,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "requires": { - "is-utf8": "^0.2.0" + "is-utf8": "0.2.1" } }, "strip-eof": { @@ -5704,7 +5703,7 @@ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", "requires": { - "get-stdin": "^4.0.1" + "get-stdin": "4.0.1" } }, "style-loader": { @@ -5712,8 +5711,8 @@ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", "requires": { - "loader-utils": "^1.1.0", - "schema-utils": "^1.0.0" + "loader-utils": "1.4.0", + "schema-utils": "1.0.0" }, "dependencies": { "ajv": { @@ -5721,10 +5720,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "3.1.3", + "fast-json-stable-stringify": "2.1.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.4.1" } }, "fast-deep-equal": { @@ -5742,9 +5741,9 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "ajv": "6.12.6", + "ajv-errors": "1.0.1", + "ajv-keywords": "3.5.2" } } } @@ -5764,9 +5763,9 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", "requires": { - "block-stream": "*", - "fstream": "^1.0.12", - "inherits": "2" + "block-stream": "0.0.9", + "fstream": "1.0.12", + "inherits": "2.0.4" } }, "terser": { @@ -5774,9 +5773,9 @@ "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", "requires": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" + "commander": "2.20.3", + "source-map": "0.6.1", + "source-map-support": "0.5.19" }, "dependencies": { "commander": { @@ -5791,15 +5790,15 @@ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", "requires": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" + "cacache": "12.0.4", + "find-cache-dir": "2.1.0", + "is-wsl": "1.1.0", + "schema-utils": "1.0.0", + "serialize-javascript": "4.0.0", + "source-map": "0.6.1", + "terser": "4.8.0", + "webpack-sources": "1.4.3", + "worker-farm": "1.7.0" }, "dependencies": { "ajv": { @@ -5807,10 +5806,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "3.1.3", + "fast-json-stable-stringify": "2.1.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.4.1" } }, "fast-deep-equal": { @@ -5828,9 +5827,9 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "ajv": "6.12.6", + "ajv-errors": "1.0.1", + "ajv-keywords": "3.5.2" } } } @@ -5840,8 +5839,8 @@ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "readable-stream": "2.3.7", + "xtend": "4.0.2" }, "dependencies": { "readable-stream": { @@ -5849,13 +5848,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "safe-buffer": { @@ -5868,7 +5867,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -5883,7 +5882,7 @@ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", "requires": { - "setimmediate": "^1.0.4" + "setimmediate": "1.0.5" } }, "to-arraybuffer": { @@ -5896,7 +5895,7 @@ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "requires": { - "kind-of": "^3.0.2" + "kind-of": "3.2.2" }, "dependencies": { "kind-of": { @@ -5904,7 +5903,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "^1.1.5" + "is-buffer": "1.1.6" } } } @@ -5914,10 +5913,10 @@ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" } }, "to-regex-range": { @@ -5925,8 +5924,8 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "3.0.0", + "repeat-string": "1.6.1" } }, "toidentifier": { @@ -5944,8 +5943,8 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "1.8.0", + "punycode": "2.1.1" } }, "trim-newlines": { @@ -5958,7 +5957,7 @@ "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", "requires": { - "glob": "^7.1.2" + "glob": "7.1.7" } }, "tty-browserify": { @@ -5971,7 +5970,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "^5.0.1" + "safe-buffer": "5.2.1" } }, "tweetnacl": { @@ -5985,7 +5984,7 @@ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "requires": { "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "mime-types": "2.1.31" } }, "typedarray": { @@ -5998,8 +5997,8 @@ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", "requires": { - "commander": "~2.19.0", - "source-map": "~0.6.1" + "commander": "2.19.0", + "source-map": "0.6.1" }, "dependencies": { "commander": { @@ -6014,10 +6013,10 @@ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" + "function-bind": "1.1.1", + "has-bigints": "1.0.1", + "has-symbols": "1.0.2", + "which-boxed-primitive": "1.0.2" } }, "union-value": { @@ -6025,10 +6024,10 @@ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "2.0.1" } }, "unique-filename": { @@ -6036,7 +6035,7 @@ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "requires": { - "unique-slug": "^2.0.0" + "unique-slug": "2.0.2" } }, "unique-slug": { @@ -6044,7 +6043,7 @@ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", "requires": { - "imurmurhash": "^0.1.4" + "imurmurhash": "0.1.4" } }, "unpipe": { @@ -6057,8 +6056,8 @@ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" + "has-value": "0.3.1", + "isobject": "3.0.1" }, "dependencies": { "has-value": { @@ -6066,9 +6065,9 @@ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" }, "dependencies": { "isobject": { @@ -6103,7 +6102,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "requires": { - "punycode": "^2.1.0" + "punycode": "2.1.1" } }, "urix": { @@ -6132,9 +6131,9 @@ "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", "requires": { - "loader-utils": "^1.1.0", - "mime": "^2.0.3", - "schema-utils": "^1.0.0" + "loader-utils": "1.4.0", + "mime": "2.5.2", + "schema-utils": "1.0.0" }, "dependencies": { "ajv": { @@ -6142,10 +6141,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "3.1.3", + "fast-json-stable-stringify": "2.1.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.4.1" } }, "fast-deep-equal": { @@ -6163,9 +6162,9 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "ajv": "6.12.6", + "ajv-errors": "1.0.1", + "ajv-keywords": "3.5.2" } } } @@ -6175,8 +6174,8 @@ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" + "querystringify": "2.2.0", + "requires-port": "1.0.0" } }, "use": { @@ -6209,8 +6208,8 @@ "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" + "define-properties": "1.1.3", + "object.getownpropertydescriptors": "2.1.2" } }, "utila": { @@ -6243,8 +6242,8 @@ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "spdx-correct": "3.1.1", + "spdx-expression-parse": "3.0.1" } }, "vary": { @@ -6257,9 +6256,9 @@ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { - "assert-plus": "^1.0.0", + "assert-plus": "1.0.0", "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "extsprintf": "1.3.0" } }, "vm-browserify": { @@ -6272,10 +6271,10 @@ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", "requires": { - "chokidar": "^3.4.1", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0", - "watchpack-chokidar2": "^2.0.1" + "chokidar": "3.5.1", + "graceful-fs": "4.2.6", + "neo-async": "2.6.2", + "watchpack-chokidar2": "2.0.1" } }, "watchpack-chokidar2": { @@ -6284,7 +6283,7 @@ "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", "optional": true, "requires": { - "chokidar": "^2.1.8" + "chokidar": "2.1.8" }, "dependencies": { "anymatch": { @@ -6293,8 +6292,8 @@ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "optional": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "micromatch": "3.1.10", + "normalize-path": "2.1.1" }, "dependencies": { "normalize-path": { @@ -6303,7 +6302,7 @@ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "optional": true, "requires": { - "remove-trailing-separator": "^1.0.1" + "remove-trailing-separator": "1.1.0" } } } @@ -6320,18 +6319,18 @@ "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "optional": true, "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "anymatch": "2.0.0", + "async-each": "1.0.3", + "braces": "2.3.2", + "fsevents": "1.2.13", + "glob-parent": "3.1.0", + "inherits": "2.0.4", + "is-binary-path": "1.0.1", + "is-glob": "4.0.1", + "normalize-path": "3.0.0", + "path-is-absolute": "1.0.1", + "readdirp": "2.2.1", + "upath": "1.2.0" } }, "fsevents": { @@ -6340,7 +6339,7 @@ "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "optional": true, "requires": { - "nan": "^2.12.1" + "nan": "2.14.2" } }, "glob-parent": { @@ -6349,8 +6348,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "optional": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "3.1.0", + "path-dirname": "1.0.2" }, "dependencies": { "is-glob": { @@ -6359,7 +6358,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "optional": true, "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "2.1.1" } } } @@ -6370,7 +6369,7 @@ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "optional": true, "requires": { - "binary-extensions": "^1.0.0" + "binary-extensions": "1.13.1" } }, "readable-stream": { @@ -6379,13 +6378,13 @@ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "optional": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "readdirp": { @@ -6394,16 +6393,15 @@ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "optional": true, "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "graceful-fs": "4.2.6", + "micromatch": "3.1.10", + "readable-stream": "2.3.7" } }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "optional": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "string_decoder": { "version": "1.1.1", @@ -6411,7 +6409,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "optional": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } } } @@ -6421,7 +6419,7 @@ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "requires": { - "minimalistic-assert": "^1.0.0" + "minimalistic-assert": "1.0.1" } }, "webpack": { @@ -6433,25 +6431,25 @@ "@webassemblyjs/helper-module-context": "1.9.0", "@webassemblyjs/wasm-edit": "1.9.0", "@webassemblyjs/wasm-parser": "1.9.0", - "acorn": "^6.4.1", - "ajv": "^6.10.2", - "ajv-keywords": "^3.4.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^4.5.0", - "eslint-scope": "^4.0.3", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.4.0", - "loader-utils": "^1.2.3", - "memory-fs": "^0.4.1", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.3", - "neo-async": "^2.6.1", - "node-libs-browser": "^2.2.1", - "schema-utils": "^1.0.0", - "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.3", - "watchpack": "^1.7.4", - "webpack-sources": "^1.4.1" + "acorn": "6.4.2", + "ajv": "6.12.6", + "ajv-keywords": "3.5.2", + "chrome-trace-event": "1.0.3", + "enhanced-resolve": "4.5.0", + "eslint-scope": "4.0.3", + "json-parse-better-errors": "1.0.2", + "loader-runner": "2.4.0", + "loader-utils": "1.4.0", + "memory-fs": "0.4.1", + "micromatch": "3.1.10", + "mkdirp": "0.5.5", + "neo-async": "2.6.2", + "node-libs-browser": "2.2.1", + "schema-utils": "1.0.0", + "tapable": "1.1.3", + "terser-webpack-plugin": "1.4.5", + "watchpack": "1.7.5", + "webpack-sources": "1.4.3" }, "dependencies": { "ajv": { @@ -6459,10 +6457,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "3.1.3", + "fast-json-stable-stringify": "2.1.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.4.1" } }, "fast-deep-equal": { @@ -6480,9 +6478,9 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "ajv": "6.12.6", + "ajv-errors": "1.0.1", + "ajv-keywords": "3.5.2" } } } @@ -6492,17 +6490,17 @@ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz", "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==", "requires": { - "chalk": "^2.4.2", - "cross-spawn": "^6.0.5", - "enhanced-resolve": "^4.1.1", - "findup-sync": "^3.0.0", - "global-modules": "^2.0.0", - "import-local": "^2.0.0", - "interpret": "^1.4.0", - "loader-utils": "^1.4.0", - "supports-color": "^6.1.0", - "v8-compile-cache": "^2.1.1", - "yargs": "^13.3.2" + "chalk": "2.4.2", + "cross-spawn": "6.0.5", + "enhanced-resolve": "4.5.0", + "findup-sync": "3.0.0", + "global-modules": "2.0.0", + "import-local": "2.0.0", + "interpret": "1.4.0", + "loader-utils": "1.4.0", + "supports-color": "6.1.0", + "v8-compile-cache": "2.3.0", + "yargs": "13.3.2" }, "dependencies": { "ansi-styles": { @@ -6510,7 +6508,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.3" } }, "chalk": { @@ -6518,9 +6516,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.5.0" }, "dependencies": { "supports-color": { @@ -6528,7 +6526,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -6538,11 +6536,11 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "nice-try": "1.0.5", + "path-key": "2.0.1", + "semver": "5.7.1", + "shebang-command": "1.2.0", + "which": "1.3.1" } }, "supports-color": { @@ -6550,7 +6548,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -6560,11 +6558,11 @@ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", "requires": { - "memory-fs": "^0.4.1", - "mime": "^2.4.4", - "mkdirp": "^0.5.1", - "range-parser": "^1.2.1", - "webpack-log": "^2.0.0" + "memory-fs": "0.4.1", + "mime": "2.5.2", + "mkdirp": "0.5.5", + "range-parser": "1.2.1", + "webpack-log": "2.0.0" } }, "webpack-dev-server": { @@ -6573,38 +6571,38 @@ "integrity": "sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ==", "requires": { "ansi-html": "0.0.7", - "bonjour": "^3.5.0", - "chokidar": "^2.1.8", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "debug": "^4.1.1", - "del": "^4.1.1", - "express": "^4.17.1", - "html-entities": "^1.3.1", + "bonjour": "3.5.0", + "chokidar": "2.1.8", + "compression": "1.7.4", + "connect-history-api-fallback": "1.6.0", + "debug": "4.3.1", + "del": "4.1.1", + "express": "4.17.1", + "html-entities": "1.4.0", "http-proxy-middleware": "0.19.1", - "import-local": "^2.0.0", - "internal-ip": "^4.3.0", - "ip": "^1.1.5", - "is-absolute-url": "^3.0.3", - "killable": "^1.0.1", - "loglevel": "^1.6.8", - "opn": "^5.5.0", - "p-retry": "^3.0.1", - "portfinder": "^1.0.26", - "schema-utils": "^1.0.0", - "selfsigned": "^1.10.8", - "semver": "^6.3.0", - "serve-index": "^1.9.1", - "sockjs": "^0.3.21", - "sockjs-client": "^1.5.0", - "spdy": "^4.0.2", - "strip-ansi": "^3.0.1", - "supports-color": "^6.1.0", - "url": "^0.11.0", - "webpack-dev-middleware": "^3.7.2", - "webpack-log": "^2.0.0", - "ws": "^6.2.1", - "yargs": "^13.3.2" + "import-local": "2.0.0", + "internal-ip": "4.3.0", + "ip": "1.1.5", + "is-absolute-url": "3.0.3", + "killable": "1.0.1", + "loglevel": "1.7.1", + "opn": "5.5.0", + "p-retry": "3.0.1", + "portfinder": "1.0.28", + "schema-utils": "1.0.0", + "selfsigned": "1.10.11", + "semver": "6.3.0", + "serve-index": "1.9.1", + "sockjs": "0.3.21", + "sockjs-client": "1.5.1", + "spdy": "4.0.2", + "strip-ansi": "3.0.1", + "supports-color": "6.1.0", + "url": "0.11.0", + "webpack-dev-middleware": "3.7.3", + "webpack-log": "2.0.0", + "ws": "6.2.2", + "yargs": "13.3.2" }, "dependencies": { "ajv": { @@ -6612,10 +6610,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "3.1.3", + "fast-json-stable-stringify": "2.1.0", + "json-schema-traverse": "0.4.1", + "uri-js": "4.4.1" } }, "anymatch": { @@ -6623,8 +6621,8 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "micromatch": "3.1.10", + "normalize-path": "2.1.1" }, "dependencies": { "normalize-path": { @@ -6632,7 +6630,7 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "requires": { - "remove-trailing-separator": "^1.0.1" + "remove-trailing-separator": "1.1.0" } } } @@ -6647,18 +6645,18 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "anymatch": "2.0.0", + "async-each": "1.0.3", + "braces": "2.3.2", + "fsevents": "1.2.13", + "glob-parent": "3.1.0", + "inherits": "2.0.4", + "is-binary-path": "1.0.1", + "is-glob": "4.0.1", + "normalize-path": "3.0.0", + "path-is-absolute": "1.0.1", + "readdirp": "2.2.1", + "upath": "1.2.0" } }, "debug": { @@ -6680,7 +6678,7 @@ "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "optional": true, "requires": { - "nan": "^2.12.1" + "nan": "2.14.2" } }, "glob-parent": { @@ -6688,8 +6686,8 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "3.1.0", + "path-dirname": "1.0.2" }, "dependencies": { "is-glob": { @@ -6697,7 +6695,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "2.1.1" } } } @@ -6707,7 +6705,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "requires": { - "binary-extensions": "^1.0.0" + "binary-extensions": "1.13.1" } }, "json-schema-traverse": { @@ -6725,13 +6723,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "core-util-is": "1.0.2", + "inherits": "2.0.4", + "isarray": "1.0.0", + "process-nextick-args": "2.0.1", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" } }, "readdirp": { @@ -6739,9 +6737,9 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "graceful-fs": "4.2.6", + "micromatch": "3.1.10", + "readable-stream": "2.3.7" } }, "safe-buffer": { @@ -6754,9 +6752,9 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" + "ajv": "6.12.6", + "ajv-errors": "1.0.1", + "ajv-keywords": "3.5.2" } }, "semver": { @@ -6769,7 +6767,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "5.1.2" } }, "supports-color": { @@ -6777,7 +6775,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "requires": { - "has-flag": "^3.0.0" + "has-flag": "3.0.0" } } } @@ -6787,8 +6785,8 @@ "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", "requires": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" + "ansi-colors": "3.2.4", + "uuid": "3.4.0" }, "dependencies": { "uuid": { @@ -6803,8 +6801,8 @@ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" + "source-list-map": "2.0.1", + "source-map": "0.6.1" } }, "websocket-driver": { @@ -6812,9 +6810,9 @@ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "requires": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" + "http-parser-js": "0.5.3", + "safe-buffer": "5.2.1", + "websocket-extensions": "0.1.4" } }, "websocket-extensions": { @@ -6827,7 +6825,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "requires": { - "isexe": "^2.0.0" + "isexe": "2.0.0" } }, "which-boxed-primitive": { @@ -6835,11 +6833,11 @@ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "is-bigint": "1.0.2", + "is-boolean-object": "1.1.1", + "is-number-object": "1.0.5", + "is-string": "1.0.6", + "is-symbol": "1.0.4" } }, "which-module": { @@ -6852,7 +6850,7 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "requires": { - "string-width": "^1.0.2 || 2" + "string-width": "1.0.2" } }, "worker-farm": { @@ -6860,7 +6858,7 @@ "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", "requires": { - "errno": "~0.1.7" + "errno": "0.1.8" } }, "wrap-ansi": { @@ -6868,9 +6866,9 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "ansi-styles": "3.2.1", + "string-width": "3.1.0", + "strip-ansi": "5.2.0" }, "dependencies": { "ansi-regex": { @@ -6883,7 +6881,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "^1.9.0" + "color-convert": "1.9.3" } }, "is-fullwidth-code-point": { @@ -6896,9 +6894,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "7.0.3", + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "5.2.0" } }, "strip-ansi": { @@ -6906,7 +6904,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "4.1.0" } } } @@ -6921,7 +6919,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", "requires": { - "async-limiter": "~1.0.0" + "async-limiter": "1.0.1" } }, "xhr2": { @@ -6949,16 +6947,16 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" + "cliui": "5.0.0", + "find-up": "3.0.0", + "get-caller-file": "2.0.5", + "require-directory": "2.1.1", + "require-main-filename": "2.0.0", + "set-blocking": "2.0.0", + "string-width": "3.1.0", + "which-module": "2.0.0", + "y18n": "4.0.3", + "yargs-parser": "13.1.2" }, "dependencies": { "ansi-regex": { @@ -6971,7 +6969,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { - "locate-path": "^3.0.0" + "locate-path": "3.0.0" } }, "is-fullwidth-code-point": { @@ -6984,9 +6982,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "7.0.3", + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "5.2.0" } }, "strip-ansi": { @@ -6994,7 +6992,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "4.1.0" } } } @@ -7004,8 +7002,8 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "camelcase": "5.3.1", + "decamelize": "1.2.0" }, "dependencies": { "camelcase": { diff --git a/MetaLamp/lending-pool/generate-purs/Main.hs b/MetaLamp/lending-pool/generate-purs/Main.hs index 0aa6125a8..276c0e45f 100644 --- a/MetaLamp/lending-pool/generate-purs/Main.hs +++ b/MetaLamp/lending-pool/generate-purs/Main.hs @@ -43,13 +43,11 @@ import Language.PureScript.Bridge.CodeGenSwitches (ForeignOptions (For genForeign, unwrapSingleConstructors) import Language.PureScript.Bridge.TypeParameters (A) -import Ledger.Constraints.OffChain (UnbalancedTx) import qualified PSGenerator.Common import Plutus.Contract.Checkpoint (CheckpointKey, CheckpointStore, CheckpointStoreItem) -import Plutus.Contract.Effects (TxConfirmed, ActiveEndpoint, UtxoAtAddress, WriteTxResponse, PABReq(..), PABResp(..)) -import Wallet.Types (EndpointValue) +import Plutus.Contract.Effects (TxConfirmed) import Plutus.Contract.Resumable (Responses) import Plutus.PAB.Effects.Contract.ContractExe (ContractExe) import Plutus.PAB.Events.ContractInstanceState (PartiallyDecodedResponse) @@ -76,8 +74,6 @@ import Servant.PureScript (HasBridge, writeAPIModuleWithSettings) import System.Directory (doesDirectoryExist, removeDirectoryRecursive) -import Wallet.Effects (AddressChangeRequest (..), - AddressChangeResponse (..)) import Wallet.Emulator.Wallet (Wallet (..)) myBridge :: BridgePart @@ -125,22 +121,13 @@ myTypes = , (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractSignatureResponse A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(PartiallyDecodedResponse A)) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @PABReq) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @PABResp) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @UnbalancedTx) -- Contract request / response types - , (equal <*> (genericShow <*> mkSumType)) (Proxy @ActiveEndpoint) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @(EndpointValue A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @TxConfirmed) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @UtxoAtAddress) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @WriteTxResponse) , (equal <*> (genericShow <*> mkSumType)) (Proxy @CheckpointStore) , (order <*> (genericShow <*> mkSumType)) (Proxy @CheckpointKey) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(CheckpointStoreItem A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(Responses A)) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @AddressChangeRequest) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @AddressChangeResponse) -- Logging types , (equal <*> (genericShow <*> mkSumType)) (Proxy @(LogMessage A)) diff --git a/MetaLamp/lending-pool/nix/pkgs/default.nix b/MetaLamp/lending-pool/nix/pkgs/default.nix index 73ff41e3f..39318a7a2 100644 --- a/MetaLamp/lending-pool/nix/pkgs/default.nix +++ b/MetaLamp/lending-pool/nix/pkgs/default.nix @@ -17,6 +17,10 @@ let cabal-install = plutus.plutus.cabal-install; + purs = plutus.plutus.purs; + + spago = plutus.plutus.spago; + stylish-haskell = plutus.plutus.stylish-haskell; haskell-language-server = plutus.plutus.haskell-language-server; @@ -24,5 +28,5 @@ let cardano-repo-tool = plutus.plutus.cardano-repo-tool; in { - inherit haskell hlint cabal-install stylish-haskell haskell-language-server cardano-repo-tool; + inherit haskell hlint cabal-install purs spago stylish-haskell haskell-language-server cardano-repo-tool; } diff --git a/MetaLamp/lending-pool/package-lock.json b/MetaLamp/lending-pool/package-lock.json new file mode 100644 index 000000000..48e341a09 --- /dev/null +++ b/MetaLamp/lending-pool/package-lock.json @@ -0,0 +1,3 @@ +{ + "lockfileVersion": 1 +} diff --git a/MetaLamp/lending-pool/shell.nix b/MetaLamp/lending-pool/shell.nix index 76d271966..039a57811 100644 --- a/MetaLamp/lending-pool/shell.nix +++ b/MetaLamp/lending-pool/shell.nix @@ -10,6 +10,8 @@ in nativeBuildInputs = with plutus-starter; [ hlint cabal-install + purs + spago haskell-language-server stylish-haskell pkgs.niv diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 8f69978e5..868619e75 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -273,11 +273,11 @@ handleAaveContract :: ~> Eff effs handleAaveContract = Builtin.handleBuiltin getSchema getContract where getSchema = \case - AaveUser _ -> Builtin.endpointsToSchemas @Aave.AaveUserSchema - AaveInfo _ -> Builtin.endpointsToSchemas @Aave.AaveInfoSchema - AaveStart -> Builtin.endpointsToSchemas @Aave.AaveOwnerSchema - DistributeFunds _ _ -> Builtin.endpointsToSchemas @Empty - CreateOracles _ -> Builtin.endpointsToSchemas @Empty + AaveUser _ -> Builtin.endpointsToSchemas @Aave.AaveUserSchema + AaveInfo _ -> Builtin.endpointsToSchemas @Aave.AaveInfoSchema + AaveStart -> Builtin.endpointsToSchemas @Aave.AaveOwnerSchema + DistributeFunds _ _ -> Builtin.endpointsToSchemas @Empty + CreateOracles _ -> Builtin.endpointsToSchemas @Empty getContract = \case AaveInfo aave -> SomeBuiltin $ Aave.infoEndpoints aave AaveUser aave -> SomeBuiltin $ Aave.userEndpoints aave From 1baae03abe8cc9418cdaf9b10eef5afe70e4b8be Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Tue, 13 Jul 2021 12:53:06 +0700 Subject: [PATCH 159/169] change readme --- MetaLamp/lending-pool/README.md | 3 +-- MetaLamp/lending-pool/client/README.md | 3 +-- MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/MetaLamp/lending-pool/README.md b/MetaLamp/lending-pool/README.md index c1aaaa9c4..3d3d6db7e 100644 --- a/MetaLamp/lending-pool/README.md +++ b/MetaLamp/lending-pool/README.md @@ -14,10 +14,9 @@ The smart contract protocol is based on [Aave](https://aave.com/), but does not We have provided two PAB applications in `./pab` and `./pab-simulation`. The first one is made for real world usage and interaction through frontend [client](client/README.md), the second one is a big test scenario. With the PAB we can serve and interact with contracts over a web API. You can read more about the PAB here: [PAB Architecture](https://github.com/input-output-hk/plutus/blob/master/plutus-pab/ARCHITECTURE.adoc). -1. Enter the nix shell (cd to the cloned Plutus repo): +1. Enter the nix shell (from `lending-pool` directory): ``` -git checkout 5cdd2c3d708bf4c33514681dee096da6463273b7 nix-shell ``` diff --git a/MetaLamp/lending-pool/client/README.md b/MetaLamp/lending-pool/client/README.md index 155196fcf..9cde50aad 100644 --- a/MetaLamp/lending-pool/client/README.md +++ b/MetaLamp/lending-pool/client/README.md @@ -12,10 +12,9 @@ npm install 2. Generate necessary PureScript code from Haskell source. This step runs an executable(`generate-purs`) from `lending-pool` directory, which requires a certain environment. The setup steps are described in `lending-pool/README`. Provided that you are able to build the backend, you can use the same approach to run purescript generation from `client` folder, i.e. -Enter the nix shell (cd to the cloned Plutus repo): +Enter the nix shell (from `lending-pool` directory): ``` -git checkout 5cdd2c3d708bf4c33514681dee096da6463273b7 nix-shell ``` diff --git a/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh b/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh index 745d22fa7..a06d909de 100755 --- a/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh +++ b/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh @@ -6,4 +6,4 @@ git remote add origin -f https://github.com/input-output-hk/plutus git config core.sparseCheckout true echo 'web-common-plutus/*' >> .git/info/sparse-checkout echo 'web-common/*' >> .git/info/sparse-checkout -git pull origin 5cdd2c3d708bf4c33514681dee096da6463273b7 +git pull origin plutus-starter-devcontainer/v1.0.6 From 1af131516802bc9fea0521b5999f118137133043 Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Tue, 13 Jul 2021 14:45:38 +0700 Subject: [PATCH 160/169] use commit sha in fetch-plutus-purs script --- MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh b/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh index a06d909de..4b185c343 100755 --- a/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh +++ b/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh @@ -6,4 +6,4 @@ git remote add origin -f https://github.com/input-output-hk/plutus git config core.sparseCheckout true echo 'web-common-plutus/*' >> .git/info/sparse-checkout echo 'web-common/*' >> .git/info/sparse-checkout -git pull origin plutus-starter-devcontainer/v1.0.6 +git pull origin bd16cc29045ffc7eaa6beaabe3b985a56cb9292a # plutus-starter-devcontainer/v1.0.6 From 7d6e2c7a659a99941b0c8676410a8f6ac997afba Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Mon, 19 Jul 2021 16:49:23 +0700 Subject: [PATCH 161/169] add nodejs to nix shell --- MetaLamp/lending-pool/client/README.md | 18 +- .../lending-pool/client/package-lock.json | 2754 +++++++++-------- MetaLamp/lending-pool/nix/pkgs/default.nix | 4 +- MetaLamp/lending-pool/shell.nix | 1 + 4 files changed, 1392 insertions(+), 1385 deletions(-) diff --git a/MetaLamp/lending-pool/client/README.md b/MetaLamp/lending-pool/client/README.md index 9cde50aad..4a9bbdb90 100644 --- a/MetaLamp/lending-pool/client/README.md +++ b/MetaLamp/lending-pool/client/README.md @@ -4,33 +4,35 @@ The client application has a minimalistic interface to the PAB [server](/MetaLam ## Running the project -1. Install npm packages. +1. Enter the nix shell (from `lending-pool` directory): ``` -npm install +nix-shell ``` -2. Generate necessary PureScript code from Haskell source. This step runs an executable(`generate-purs`) from `lending-pool` directory, which requires a certain environment. The setup steps are described in `lending-pool/README`. Provided that you are able to build the backend, you can use the same approach to run purescript generation from `client` folder, i.e. +Cd to `./client` folder. + -Enter the nix shell (from `lending-pool` directory): +2. Install npm packages. ``` -nix-shell +npm install ``` -cd to `lending-pool/client` folder and execute +3. Generate necessary PureScript code from Haskell source. This step runs an executable(`generate-purs`) from `lending-pool` directory, which requires a certain environment. The setup steps are described in `lending-pool/README`. Provided that you are able to build the backend, you can use the same approach to run purescript generation from `client` folder, i.e. + ``` npm run generate-purs ``` -3. Start the client: +4. Start the client: ``` npm start ``` -4. Open browser to interact with the app at https://localhost:8009/. +5. Open browser to interact with the app at https://localhost:8009/. CORS protection needs to be disabled. You can use this script to launch chromium (note that first you need to close chromium completely, otherwise security won't be disabled): ``` diff --git a/MetaLamp/lending-pool/client/package-lock.json b/MetaLamp/lending-pool/client/package-lock.json index 801b20ea7..77b310829 100644 --- a/MetaLamp/lending-pool/client/package-lock.json +++ b/MetaLamp/lending-pool/client/package-lock.json @@ -14,8 +14,8 @@ "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", "requires": { - "@types/minimatch": "3.0.4", - "@types/node": "15.12.1" + "@types/minimatch": "*", + "@types/node": "*" } }, "@types/minimatch": { @@ -95,7 +95,7 @@ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", "requires": { - "@xtuc/ieee754": "1.2.0" + "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { @@ -205,7 +205,7 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "requires": { - "mime-types": "2.1.31", + "mime-types": "~2.1.24", "negotiator": "0.6.2" } }, @@ -219,10 +219,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.1.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "ajv-errors": { @@ -266,8 +266,8 @@ "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "optional": true, "requires": { - "normalize-path": "3.0.0", - "picomatch": "2.3.0" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, "aproba": { @@ -280,8 +280,8 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.7" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" }, "dependencies": { "readable-stream": { @@ -289,13 +289,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -308,7 +308,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -343,7 +343,7 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "requires": { - "array-uniq": "1.0.3" + "array-uniq": "^1.0.1" } }, "array-uniq": { @@ -366,7 +366,7 @@ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": "~2.1.0" } }, "asn1.js": { @@ -374,10 +374,10 @@ "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "requires": { - "bn.js": "4.12.0", - "inherits": "2.0.4", - "minimalistic-assert": "1.0.1", - "safer-buffer": "2.1.2" + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" }, "dependencies": { "bn.js": { @@ -392,7 +392,7 @@ "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", "requires": { - "object-assign": "4.1.1", + "object-assign": "^4.1.1", "util": "0.10.3" }, "dependencies": { @@ -426,7 +426,7 @@ "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "requires": { - "lodash": "4.17.21" + "lodash": "^4.17.14" } }, "async-each": { @@ -469,9 +469,9 @@ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "requires": { - "chalk": "1.1.3", - "esutils": "2.0.3", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" } }, "balanced-match": { @@ -484,13 +484,13 @@ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", "requires": { - "cache-base": "1.0.1", - "class-utils": "0.3.6", - "component-emitter": "1.3.0", - "define-property": "1.0.0", - "isobject": "3.0.1", - "mixin-deep": "1.3.2", - "pascalcase": "0.1.1" + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" }, "dependencies": { "define-property": { @@ -498,7 +498,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -506,7 +506,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "6.0.3" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -514,7 +514,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "6.0.3" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -522,9 +522,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.3" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -544,7 +544,7 @@ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "requires": { - "tweetnacl": "0.14.5" + "tweetnacl": "^0.14.3" } }, "big.js": { @@ -573,7 +573,7 @@ "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", "requires": { - "inherits": "2.0.4" + "inherits": "~2.0.0" } }, "bluebird": { @@ -592,15 +592,15 @@ "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", "requires": { "bytes": "3.1.0", - "content-type": "1.0.4", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", + "depd": "~1.1.2", "http-errors": "1.7.2", "iconv-lite": "0.4.24", - "on-finished": "2.3.0", + "on-finished": "~2.3.0", "qs": "6.7.0", "raw-body": "2.4.0", - "type-is": "1.6.18" + "type-is": "~1.6.17" }, "dependencies": { "bytes": { @@ -620,12 +620,12 @@ "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", "requires": { - "array-flatten": "2.1.2", - "deep-equal": "1.1.1", - "dns-equal": "1.0.0", - "dns-txt": "2.0.2", - "multicast-dns": "6.2.3", - "multicast-dns-service-types": "1.1.0" + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" } }, "boolbase": { @@ -643,7 +643,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { - "balanced-match": "1.0.2", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -652,16 +652,16 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", "requires": { - "arr-flatten": "1.1.0", - "array-unique": "0.3.2", - "extend-shallow": "2.0.1", - "fill-range": "4.0.0", - "isobject": "3.0.1", - "repeat-element": "1.1.4", - "snapdragon": "0.8.2", - "snapdragon-node": "2.1.1", - "split-string": "3.1.0", - "to-regex": "3.0.2" + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -669,7 +669,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -684,12 +684,12 @@ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { - "buffer-xor": "1.0.3", - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "inherits": "2.0.4", - "safe-buffer": "5.2.1" + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "browserify-cipher": { @@ -697,9 +697,9 @@ "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "requires": { - "browserify-aes": "1.2.0", - "browserify-des": "1.0.2", - "evp_bytestokey": "1.0.3" + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" } }, "browserify-des": { @@ -707,10 +707,10 @@ "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "requires": { - "cipher-base": "1.0.4", - "des.js": "1.0.1", - "inherits": "2.0.4", - "safe-buffer": "5.2.1" + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "browserify-rsa": { @@ -718,8 +718,8 @@ "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", "requires": { - "bn.js": "5.2.0", - "randombytes": "2.1.0" + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" } }, "browserify-sign": { @@ -727,15 +727,15 @@ "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", "requires": { - "bn.js": "5.2.0", - "browserify-rsa": "4.1.0", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "elliptic": "6.5.4", - "inherits": "2.0.4", - "parse-asn1": "5.1.6", - "readable-stream": "3.6.0", - "safe-buffer": "5.2.1" + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" } }, "browserify-zlib": { @@ -743,7 +743,7 @@ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "requires": { - "pako": "1.0.11" + "pako": "~1.0.5" } }, "buffer": { @@ -751,9 +751,9 @@ "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", "requires": { - "base64-js": "1.5.1", - "ieee754": "1.2.1", - "isarray": "1.0.0" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" } }, "buffer-from": { @@ -786,21 +786,21 @@ "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", "requires": { - "bluebird": "3.7.2", - "chownr": "1.1.4", - "figgy-pudding": "3.5.2", - "glob": "7.1.7", - "graceful-fs": "4.2.6", - "infer-owner": "1.0.4", - "lru-cache": "5.1.1", - "mississippi": "3.0.0", - "mkdirp": "0.5.5", - "move-concurrently": "1.0.1", - "promise-inflight": "1.0.1", - "rimraf": "2.7.1", - "ssri": "6.0.2", - "unique-filename": "1.1.1", - "y18n": "4.0.3" + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" }, "dependencies": { "lru-cache": { @@ -808,7 +808,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "requires": { - "yallist": "3.1.1" + "yallist": "^3.0.2" } }, "yallist": { @@ -823,15 +823,15 @@ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", "requires": { - "collection-visit": "1.0.0", - "component-emitter": "1.3.0", - "get-value": "2.0.6", - "has-value": "1.0.0", - "isobject": "3.0.1", - "set-value": "2.0.1", - "to-object-path": "0.3.0", - "union-value": "1.0.1", - "unset-value": "1.0.0" + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" } }, "call-bind": { @@ -839,8 +839,8 @@ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "requires": { - "function-bind": "1.1.1", - "get-intrinsic": "1.1.1" + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" } }, "camel-case": { @@ -848,8 +848,8 @@ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", "requires": { - "no-case": "2.3.2", - "upper-case": "1.1.3" + "no-case": "^2.2.0", + "upper-case": "^1.1.1" } }, "camelcase": { @@ -862,8 +862,8 @@ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "requires": { - "camelcase": "2.1.1", - "map-obj": "1.0.1" + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" } }, "caseless": { @@ -876,11 +876,11 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, "chokidar": { @@ -889,14 +889,14 @@ "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", "optional": true, "requires": { - "anymatch": "3.1.2", - "braces": "3.0.2", - "fsevents": "2.3.2", - "glob-parent": "5.1.2", - "is-binary-path": "2.1.0", - "is-glob": "4.0.1", - "normalize-path": "3.0.0", - "readdirp": "3.5.0" + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" }, "dependencies": { "braces": { @@ -905,7 +905,7 @@ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "optional": true, "requires": { - "fill-range": "7.0.1" + "fill-range": "^7.0.1" } }, "fill-range": { @@ -914,7 +914,7 @@ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "optional": true, "requires": { - "to-regex-range": "5.0.1" + "to-regex-range": "^5.0.1" } }, "is-number": { @@ -929,7 +929,7 @@ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "optional": true, "requires": { - "is-number": "7.0.0" + "is-number": "^7.0.0" } } } @@ -949,8 +949,8 @@ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "requires": { - "inherits": "2.0.4", - "safe-buffer": "5.2.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "class-utils": { @@ -958,10 +958,10 @@ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", "requires": { - "arr-union": "3.1.0", - "define-property": "0.2.5", - "isobject": "3.0.1", - "static-extend": "0.1.2" + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" }, "dependencies": { "define-property": { @@ -969,7 +969,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -979,7 +979,7 @@ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", "requires": { - "source-map": "0.6.1" + "source-map": "~0.6.0" } }, "cliui": { @@ -987,9 +987,9 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "requires": { - "string-width": "3.1.0", - "strip-ansi": "5.2.0", - "wrap-ansi": "5.1.0" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" }, "dependencies": { "ansi-regex": { @@ -1007,9 +1007,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "requires": { - "emoji-regex": "7.0.3", - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "5.2.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" } }, "strip-ansi": { @@ -1017,7 +1017,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "requires": { - "ansi-regex": "4.1.0" + "ansi-regex": "^4.1.0" } } } @@ -1027,9 +1027,9 @@ "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "requires": { - "is-plain-object": "2.0.4", - "kind-of": "6.0.3", - "shallow-clone": "3.0.1" + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" } }, "co": { @@ -1047,8 +1047,8 @@ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", "requires": { - "map-visit": "1.0.0", - "object-visit": "1.0.1" + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" } }, "color-convert": { @@ -1069,7 +1069,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "commander": { @@ -1092,7 +1092,7 @@ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "requires": { - "mime-db": "1.48.0" + "mime-db": ">= 1.43.0 < 2" } }, "compression": { @@ -1100,13 +1100,13 @@ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "requires": { - "accepts": "1.3.7", + "accepts": "~1.3.5", "bytes": "3.0.0", - "compressible": "2.0.18", + "compressible": "~2.0.16", "debug": "2.6.9", - "on-headers": "1.0.2", + "on-headers": "~1.0.2", "safe-buffer": "5.1.2", - "vary": "1.1.2" + "vary": "~1.1.2" }, "dependencies": { "safe-buffer": { @@ -1126,10 +1126,10 @@ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "requires": { - "buffer-from": "1.1.1", - "inherits": "2.0.4", - "readable-stream": "2.3.7", - "typedarray": "0.0.6" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" }, "dependencies": { "readable-stream": { @@ -1137,13 +1137,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -1156,7 +1156,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -1216,12 +1216,12 @@ "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", "requires": { - "aproba": "1.2.0", - "fs-write-stream-atomic": "1.0.10", - "iferr": "0.1.5", - "mkdirp": "0.5.5", - "rimraf": "2.7.1", - "run-queue": "1.0.3" + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" } }, "copy-descriptor": { @@ -1239,8 +1239,8 @@ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", "requires": { - "bn.js": "4.12.0", - "elliptic": "6.5.4" + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" }, "dependencies": { "bn.js": { @@ -1255,11 +1255,11 @@ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { - "cipher-base": "1.0.4", - "inherits": "2.0.4", - "md5.js": "1.3.5", - "ripemd160": "2.0.2", - "sha.js": "2.4.11" + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" } }, "create-hmac": { @@ -1267,12 +1267,12 @@ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "inherits": "2.0.4", - "ripemd160": "2.0.2", - "safe-buffer": "5.2.1", - "sha.js": "2.4.11" + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, "cross-spawn": { @@ -1280,8 +1280,8 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", "requires": { - "lru-cache": "4.1.5", - "which": "1.3.1" + "lru-cache": "^4.0.1", + "which": "^1.2.9" } }, "crypto-browserify": { @@ -1289,17 +1289,17 @@ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "requires": { - "browserify-cipher": "1.0.1", - "browserify-sign": "4.2.1", - "create-ecdh": "4.0.4", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "diffie-hellman": "5.0.3", - "inherits": "2.0.4", - "pbkdf2": "3.1.2", - "public-encrypt": "4.0.3", - "randombytes": "2.1.0", - "randomfill": "1.0.4" + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" } }, "css-loader": { @@ -1307,18 +1307,18 @@ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-1.0.1.tgz", "integrity": "sha512-+ZHAZm/yqvJ2kDtPne3uX0C+Vr3Zn5jFn2N4HywtS5ujwvsVkyg0VArEXpl3BgczDA8anieki1FIzhchX4yrDw==", "requires": { - "babel-code-frame": "6.26.0", - "css-selector-tokenizer": "0.7.3", - "icss-utils": "2.1.0", - "loader-utils": "1.4.0", - "lodash": "4.17.21", - "postcss": "6.0.23", - "postcss-modules-extract-imports": "1.2.1", - "postcss-modules-local-by-default": "1.2.0", - "postcss-modules-scope": "1.1.0", - "postcss-modules-values": "1.3.0", - "postcss-value-parser": "3.3.1", - "source-list-map": "2.0.1" + "babel-code-frame": "^6.26.0", + "css-selector-tokenizer": "^0.7.0", + "icss-utils": "^2.1.0", + "loader-utils": "^1.0.2", + "lodash": "^4.17.11", + "postcss": "^6.0.23", + "postcss-modules-extract-imports": "^1.2.0", + "postcss-modules-local-by-default": "^1.2.0", + "postcss-modules-scope": "^1.1.0", + "postcss-modules-values": "^1.3.0", + "postcss-value-parser": "^3.3.0", + "source-list-map": "^2.0.0" } }, "css-select": { @@ -1326,10 +1326,10 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", "requires": { - "boolbase": "1.0.0", - "css-what": "3.4.2", - "domutils": "1.7.0", - "nth-check": "1.0.2" + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" } }, "css-selector-tokenizer": { @@ -1337,8 +1337,8 @@ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", "requires": { - "cssesc": "3.0.0", - "fastparse": "1.1.2" + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" } }, "css-what": { @@ -1356,7 +1356,7 @@ "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", "requires": { - "array-find-index": "1.0.2" + "array-find-index": "^1.0.1" } }, "cyclist": { @@ -1374,7 +1374,7 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "debug": { @@ -1400,12 +1400,12 @@ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", "requires": { - "is-arguments": "1.1.0", - "is-date-object": "1.0.4", - "is-regex": "1.1.3", - "object-is": "1.1.5", - "object-keys": "1.1.1", - "regexp.prototype.flags": "1.3.1" + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" } }, "default-gateway": { @@ -1413,8 +1413,8 @@ "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", "requires": { - "execa": "1.0.0", - "ip-regex": "2.1.0" + "execa": "^1.0.0", + "ip-regex": "^2.1.0" } }, "define-properties": { @@ -1422,7 +1422,7 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "requires": { - "object-keys": "1.1.1" + "object-keys": "^1.0.12" } }, "define-property": { @@ -1430,8 +1430,8 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", "requires": { - "is-descriptor": "1.0.2", - "isobject": "3.0.1" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" }, "dependencies": { "is-accessor-descriptor": { @@ -1439,7 +1439,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "6.0.3" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -1447,7 +1447,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "6.0.3" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -1455,9 +1455,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.3" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -1467,13 +1467,13 @@ "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", "requires": { - "@types/glob": "7.1.3", - "globby": "6.1.0", - "is-path-cwd": "2.2.0", - "is-path-in-cwd": "2.1.0", - "p-map": "2.1.0", - "pify": "4.0.1", - "rimraf": "2.7.1" + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" }, "dependencies": { "globby": { @@ -1481,11 +1481,11 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "requires": { - "array-union": "1.0.2", - "glob": "7.1.7", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "dependencies": { "pify": { @@ -1522,8 +1522,8 @@ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "requires": { - "inherits": "2.0.4", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, "destroy": { @@ -1546,9 +1546,9 @@ "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "requires": { - "bn.js": "4.12.0", - "miller-rabin": "4.0.1", - "randombytes": "2.1.0" + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" }, "dependencies": { "bn.js": { @@ -1568,8 +1568,8 @@ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", "requires": { - "ip": "1.1.5", - "safe-buffer": "5.2.1" + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" } }, "dns-txt": { @@ -1577,7 +1577,7 @@ "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", "requires": { - "buffer-indexof": "1.1.1" + "buffer-indexof": "^1.0.0" } }, "dom-converter": { @@ -1585,7 +1585,7 @@ "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", "requires": { - "utila": "0.4.0" + "utila": "~0.4" } }, "dom-serializer": { @@ -1593,8 +1593,8 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", "requires": { - "domelementtype": "2.2.0", - "entities": "2.2.0" + "domelementtype": "^2.0.1", + "entities": "^2.0.0" }, "dependencies": { "domelementtype": { @@ -1619,7 +1619,7 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", "requires": { - "domelementtype": "1.3.1" + "domelementtype": "1" } }, "domutils": { @@ -1627,8 +1627,8 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", "requires": { - "dom-serializer": "0.2.2", - "domelementtype": "1.3.1" + "dom-serializer": "0", + "domelementtype": "1" } }, "duplexify": { @@ -1636,10 +1636,10 @@ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "requires": { - "end-of-stream": "1.4.4", - "inherits": "2.0.4", - "readable-stream": "2.3.7", - "stream-shift": "1.0.1" + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" }, "dependencies": { "readable-stream": { @@ -1647,13 +1647,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -1666,7 +1666,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -1676,8 +1676,8 @@ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "requires": { - "jsbn": "0.1.1", - "safer-buffer": "2.1.2" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "ee-first": { @@ -1690,13 +1690,13 @@ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "requires": { - "bn.js": "4.12.0", - "brorand": "1.1.0", - "hash.js": "1.1.7", - "hmac-drbg": "1.0.1", - "inherits": "2.0.4", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" }, "dependencies": { "bn.js": { @@ -1726,7 +1726,7 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "requires": { - "once": "1.4.0" + "once": "^1.4.0" } }, "enhanced-resolve": { @@ -1734,9 +1734,9 @@ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", "requires": { - "graceful-fs": "4.2.6", - "memory-fs": "0.5.0", - "tapable": "1.1.3" + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" }, "dependencies": { "memory-fs": { @@ -1744,8 +1744,8 @@ "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", "requires": { - "errno": "0.1.8", - "readable-stream": "2.3.7" + "errno": "^0.1.3", + "readable-stream": "^2.0.1" } }, "readable-stream": { @@ -1753,13 +1753,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -1772,7 +1772,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -1792,7 +1792,7 @@ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "requires": { - "prr": "1.0.1" + "prr": "~1.0.1" } }, "error-ex": { @@ -1800,7 +1800,7 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "requires": { - "is-arrayish": "0.2.1" + "is-arrayish": "^0.2.1" } }, "es-abstract": { @@ -1808,22 +1808,22 @@ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", "requires": { - "call-bind": "1.0.2", - "es-to-primitive": "1.2.1", - "function-bind": "1.1.1", - "get-intrinsic": "1.1.1", - "has": "1.0.3", - "has-symbols": "1.0.2", - "is-callable": "1.2.3", - "is-negative-zero": "2.0.1", - "is-regex": "1.1.3", - "is-string": "1.0.6", - "object-inspect": "1.10.3", - "object-keys": "1.1.1", - "object.assign": "4.1.2", - "string.prototype.trimend": "1.0.4", - "string.prototype.trimstart": "1.0.4", - "unbox-primitive": "1.0.1" + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" } }, "es-to-primitive": { @@ -1831,9 +1831,9 @@ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "requires": { - "is-callable": "1.2.3", - "is-date-object": "1.0.4", - "is-symbol": "1.0.4" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" } }, "escape-html": { @@ -1851,8 +1851,8 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", "requires": { - "esrecurse": "4.3.0", - "estraverse": "4.3.0" + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" } }, "esrecurse": { @@ -1860,7 +1860,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "requires": { - "estraverse": "5.2.0" + "estraverse": "^5.2.0" }, "dependencies": { "estraverse": { @@ -1900,7 +1900,7 @@ "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", "requires": { - "original": "1.0.2" + "original": "^1.0.0" } }, "evp_bytestokey": { @@ -1908,8 +1908,8 @@ "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "requires": { - "md5.js": "1.3.5", - "safe-buffer": "5.2.1" + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" } }, "execa": { @@ -1917,13 +1917,13 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "requires": { - "cross-spawn": "6.0.5", - "get-stream": "4.1.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.3", - "strip-eof": "1.0.0" + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" }, "dependencies": { "cross-spawn": { @@ -1931,11 +1931,11 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "requires": { - "nice-try": "1.0.5", - "path-key": "2.0.1", - "semver": "5.7.1", - "shebang-command": "1.2.0", - "which": "1.3.1" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } } } @@ -1945,13 +1945,13 @@ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", "requires": { - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "posix-character-classes": "0.1.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -1959,7 +1959,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -1967,7 +1967,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -1977,7 +1977,7 @@ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", "requires": { - "homedir-polyfill": "1.0.3" + "homedir-polyfill": "^1.0.1" } }, "express": { @@ -1985,36 +1985,36 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", "requires": { - "accepts": "1.3.7", + "accepts": "~1.3.7", "array-flatten": "1.1.1", "body-parser": "1.19.0", "content-disposition": "0.5.3", - "content-type": "1.0.4", + "content-type": "~1.0.4", "cookie": "0.4.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "1.1.2", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", - "finalhandler": "1.1.2", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", "fresh": "0.5.2", "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.3", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.7", + "proxy-addr": "~2.0.5", "qs": "6.7.0", - "range-parser": "1.2.1", + "range-parser": "~1.2.1", "safe-buffer": "5.1.2", "send": "0.17.1", "serve-static": "1.14.1", "setprototypeof": "1.1.1", - "statuses": "1.5.0", - "type-is": "1.6.18", + "statuses": "~1.5.0", + "type-is": "~1.6.18", "utils-merge": "1.0.1", - "vary": "1.1.2" + "vary": "~1.1.2" }, "dependencies": { "array-flatten": { @@ -2044,8 +2044,8 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", "requires": { - "assign-symbols": "1.0.0", - "is-extendable": "1.0.1" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -2053,7 +2053,7 @@ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -2063,14 +2063,14 @@ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", "requires": { - "array-unique": "0.3.2", - "define-property": "1.0.0", - "expand-brackets": "2.1.4", - "extend-shallow": "2.0.1", - "fragment-cache": "0.2.1", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { "define-property": { @@ -2078,7 +2078,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "extend-shallow": { @@ -2086,7 +2086,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "is-accessor-descriptor": { @@ -2094,7 +2094,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "6.0.3" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -2102,7 +2102,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "6.0.3" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -2110,9 +2110,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.3" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -2122,10 +2122,10 @@ "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz", "integrity": "sha512-bt/LZ4m5Rqt/Crl2HiKuAl/oqg0psx1tsTLkvWbJen1CtD+fftkZhMaQ9HOtY2gWsl2Wq+sABmMVi9z3DhKWQQ==", "requires": { - "async": "2.6.3", - "loader-utils": "1.4.0", - "schema-utils": "0.3.0", - "webpack-sources": "1.4.3" + "async": "^2.4.1", + "loader-utils": "^1.1.0", + "schema-utils": "^0.3.0", + "webpack-sources": "^1.0.1" } }, "extsprintf": { @@ -2153,7 +2153,7 @@ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "requires": { - "websocket-driver": "0.7.4" + "websocket-driver": ">=0.5.1" } }, "figgy-pudding": { @@ -2166,8 +2166,8 @@ "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-2.0.0.tgz", "integrity": "sha512-YCsBfd1ZGCyonOKLxPiKPdu+8ld9HAaMEvJewzz+b2eTF7uL5Zm/HdBF6FjCrpCMRq25Mi0U1gl4pwn2TlH7hQ==", "requires": { - "loader-utils": "1.4.0", - "schema-utils": "1.0.0" + "loader-utils": "^1.0.2", + "schema-utils": "^1.0.0" }, "dependencies": { "ajv": { @@ -2175,10 +2175,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "3.1.3", - "fast-json-stable-stringify": "2.1.0", - "json-schema-traverse": "0.4.1", - "uri-js": "4.4.1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "fast-deep-equal": { @@ -2196,9 +2196,9 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { - "ajv": "6.12.6", - "ajv-errors": "1.0.1", - "ajv-keywords": "3.5.2" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } } } @@ -2208,10 +2208,10 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", "requires": { - "extend-shallow": "2.0.1", - "is-number": "3.0.0", - "repeat-string": "1.6.1", - "to-regex-range": "2.1.1" + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" }, "dependencies": { "extend-shallow": { @@ -2219,7 +2219,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -2230,12 +2230,12 @@ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "requires": { "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.3", - "statuses": "1.5.0", - "unpipe": "1.0.0" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" } }, "find-cache-dir": { @@ -2243,9 +2243,9 @@ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", "requires": { - "commondir": "1.0.1", - "make-dir": "2.1.0", - "pkg-dir": "3.0.0" + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" } }, "find-up": { @@ -2253,8 +2253,8 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "findup-sync": { @@ -2262,10 +2262,10 @@ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", "requires": { - "detect-file": "1.0.0", - "is-glob": "4.0.1", - "micromatch": "3.1.10", - "resolve-dir": "1.0.1" + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" } }, "flush-write-stream": { @@ -2273,8 +2273,8 @@ "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", "requires": { - "inherits": "2.0.4", - "readable-stream": "2.3.7" + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" }, "dependencies": { "readable-stream": { @@ -2282,13 +2282,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -2301,7 +2301,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -2326,9 +2326,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.8", - "mime-types": "2.1.31" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" } }, "forwarded": { @@ -2341,7 +2341,7 @@ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", "requires": { - "map-cache": "0.2.2" + "map-cache": "^0.2.2" } }, "fresh": { @@ -2354,8 +2354,8 @@ "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", "requires": { - "inherits": "2.0.4", - "readable-stream": "2.3.7" + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" }, "dependencies": { "readable-stream": { @@ -2363,13 +2363,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -2382,7 +2382,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -2392,10 +2392,10 @@ "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", "requires": { - "graceful-fs": "4.2.6", - "iferr": "0.1.5", - "imurmurhash": "0.1.4", - "readable-stream": "2.3.7" + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" }, "dependencies": { "readable-stream": { @@ -2403,13 +2403,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -2422,7 +2422,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -2443,10 +2443,10 @@ "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", "requires": { - "graceful-fs": "4.2.6", - "inherits": "2.0.4", - "mkdirp": "0.5.5", - "rimraf": "2.7.1" + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" } }, "function-bind": { @@ -2459,14 +2459,14 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.3", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.3" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" } }, "gaze": { @@ -2474,7 +2474,7 @@ "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", "requires": { - "globule": "1.3.2" + "globule": "^1.0.0" } }, "get-caller-file": { @@ -2487,9 +2487,9 @@ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "requires": { - "function-bind": "1.1.1", - "has": "1.0.3", - "has-symbols": "1.0.2" + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" } }, "get-stdin": { @@ -2502,7 +2502,7 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "requires": { - "pump": "3.0.0" + "pump": "^3.0.0" } }, "get-value": { @@ -2515,7 +2515,7 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { - "assert-plus": "1.0.0" + "assert-plus": "^1.0.0" } }, "glob": { @@ -2523,12 +2523,12 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.4", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "glob-parent": { @@ -2537,7 +2537,7 @@ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "optional": true, "requires": { - "is-glob": "4.0.1" + "is-glob": "^4.0.1" } }, "global-modules": { @@ -2545,7 +2545,7 @@ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", "requires": { - "global-prefix": "3.0.0" + "global-prefix": "^3.0.0" }, "dependencies": { "global-prefix": { @@ -2553,9 +2553,9 @@ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", "requires": { - "ini": "1.3.8", - "kind-of": "6.0.3", - "which": "1.3.1" + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" } } } @@ -2565,11 +2565,11 @@ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", "requires": { - "expand-tilde": "2.0.2", - "homedir-polyfill": "1.0.3", - "ini": "1.3.8", - "is-windows": "1.0.2", - "which": "1.3.1" + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" } }, "globby": { @@ -2577,12 +2577,12 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-4.1.0.tgz", "integrity": "sha1-CA9UVJ7BuCpsYOYx/ILhIR2+lfg=", "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "6.0.4", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^6.0.1", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "dependencies": { "glob": { @@ -2590,11 +2590,11 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", "requires": { - "inflight": "1.0.6", - "inherits": "2.0.4", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } @@ -2604,9 +2604,9 @@ "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz", "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==", "requires": { - "glob": "7.1.7", - "lodash": "4.17.21", - "minimatch": "3.0.4" + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" } }, "graceful-fs": { @@ -2629,8 +2629,8 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "requires": { - "ajv": "6.12.6", - "har-schema": "2.0.0" + "ajv": "^6.12.3", + "har-schema": "^2.0.0" }, "dependencies": { "ajv": { @@ -2638,10 +2638,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "3.1.3", - "fast-json-stable-stringify": "2.1.0", - "json-schema-traverse": "0.4.1", - "uri-js": "4.4.1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "fast-deep-equal": { @@ -2661,7 +2661,7 @@ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "requires": { - "function-bind": "1.1.1" + "function-bind": "^1.1.1" } }, "has-ansi": { @@ -2669,7 +2669,7 @@ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-bigints": { @@ -2697,9 +2697,9 @@ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", "requires": { - "get-value": "2.0.6", - "has-values": "1.0.0", - "isobject": "3.0.1" + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" } }, "has-values": { @@ -2707,8 +2707,8 @@ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { "kind-of": { @@ -2716,7 +2716,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -2726,9 +2726,9 @@ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "requires": { - "inherits": "2.0.4", - "readable-stream": "3.6.0", - "safe-buffer": "5.2.1" + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" } }, "hash.js": { @@ -2736,8 +2736,8 @@ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "requires": { - "inherits": "2.0.4", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" } }, "he": { @@ -2750,9 +2750,9 @@ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "requires": { - "hash.js": "1.1.7", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, "homedir-polyfill": { @@ -2760,7 +2760,7 @@ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "requires": { - "parse-passwd": "1.0.0" + "parse-passwd": "^1.0.0" } }, "hosted-git-info": { @@ -2773,10 +2773,10 @@ "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", "requires": { - "inherits": "2.0.4", - "obuf": "1.1.2", - "readable-stream": "2.3.7", - "wbuf": "1.7.3" + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" }, "dependencies": { "readable-stream": { @@ -2784,13 +2784,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -2803,7 +2803,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -2818,13 +2818,13 @@ "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", "requires": { - "camel-case": "3.0.0", - "clean-css": "4.2.3", - "commander": "2.17.1", - "he": "1.2.0", - "param-case": "2.1.1", - "relateurl": "0.2.7", - "uglify-js": "3.4.10" + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" } }, "html-webpack-plugin": { @@ -2832,12 +2832,12 @@ "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", "requires": { - "html-minifier": "3.5.21", - "loader-utils": "0.2.17", - "lodash": "4.17.21", - "pretty-error": "2.1.2", - "tapable": "1.1.3", - "toposort": "1.0.7", + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "tapable": "^1.0.0", + "toposort": "^1.0.0", "util.promisify": "1.0.0" }, "dependencies": { @@ -2861,10 +2861,10 @@ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", "requires": { - "big.js": "3.2.0", - "emojis-list": "2.1.0", - "json5": "0.5.1", - "object-assign": "4.1.1" + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" } } } @@ -2874,12 +2874,12 @@ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", "requires": { - "domelementtype": "1.3.1", - "domhandler": "2.4.2", - "domutils": "1.7.0", - "entities": "1.1.2", - "inherits": "2.0.4", - "readable-stream": "3.6.0" + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" }, "dependencies": { "entities": { @@ -2899,10 +2899,10 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", "requires": { - "depd": "1.1.2", + "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.1", - "statuses": "1.5.0", + "statuses": ">= 1.5.0 < 2", "toidentifier": "1.0.0" }, "dependencies": { @@ -2923,9 +2923,9 @@ "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "requires": { - "eventemitter3": "4.0.7", - "follow-redirects": "1.14.1", - "requires-port": "1.0.0" + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" } }, "http-proxy-middleware": { @@ -2933,10 +2933,10 @@ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", "requires": { - "http-proxy": "1.18.1", - "is-glob": "4.0.1", - "lodash": "4.17.21", - "micromatch": "3.1.10" + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" } }, "http-signature": { @@ -2944,9 +2944,9 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.16.1" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "https-browserify": { @@ -2959,7 +2959,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "icss-replace-symbols": { @@ -2972,7 +2972,7 @@ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", "requires": { - "postcss": "6.0.23" + "postcss": "^6.0.1" } }, "ieee754": { @@ -2990,8 +2990,8 @@ "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", "requires": { - "pkg-dir": "3.0.0", - "resolve-cwd": "2.0.0" + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" } }, "imurmurhash": { @@ -3009,7 +3009,7 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "requires": { - "repeating": "2.0.1" + "repeating": "^2.0.0" } }, "infer-owner": { @@ -3022,8 +3022,8 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -3041,8 +3041,8 @@ "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", "requires": { - "default-gateway": "4.2.0", - "ipaddr.js": "1.9.1" + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" } }, "interpret": { @@ -3075,7 +3075,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -3083,7 +3083,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -3093,7 +3093,7 @@ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", "requires": { - "call-bind": "1.0.2" + "call-bind": "^1.0.0" } }, "is-arrayish": { @@ -3112,7 +3112,7 @@ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "optional": true, "requires": { - "binary-extensions": "2.2.0" + "binary-extensions": "^2.0.0" } }, "is-boolean-object": { @@ -3120,7 +3120,7 @@ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", "requires": { - "call-bind": "1.0.2" + "call-bind": "^1.0.2" } }, "is-buffer": { @@ -3138,7 +3138,7 @@ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", "requires": { - "has": "1.0.3" + "has": "^1.0.3" } }, "is-data-descriptor": { @@ -3146,7 +3146,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -3154,7 +3154,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -3169,9 +3169,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "dependencies": { "kind-of": { @@ -3201,7 +3201,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-glob": { @@ -3209,7 +3209,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.1" } }, "is-negative-zero": { @@ -3222,7 +3222,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -3230,7 +3230,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -3250,7 +3250,7 @@ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", "requires": { - "is-path-inside": "2.1.0" + "is-path-inside": "^2.1.0" } }, "is-path-inside": { @@ -3258,7 +3258,7 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", "requires": { - "path-is-inside": "1.0.2" + "path-is-inside": "^1.0.2" } }, "is-plain-object": { @@ -3266,7 +3266,7 @@ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "is-regex": { @@ -3274,8 +3274,8 @@ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", "requires": { - "call-bind": "1.0.2", - "has-symbols": "1.0.2" + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" } }, "is-stream": { @@ -3293,7 +3293,7 @@ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "requires": { - "has-symbols": "1.0.2" + "has-symbols": "^1.0.2" } }, "is-typedarray": { @@ -3366,7 +3366,7 @@ "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", "requires": { - "bignumber.js": "9.0.1" + "bignumber.js": "^9.0.0" } }, "json-parse-better-errors": { @@ -3399,7 +3399,7 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "requires": { - "minimist": "1.2.5" + "minimist": "^1.2.0" } }, "jsprim": { @@ -3428,11 +3428,11 @@ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { - "graceful-fs": "4.2.6", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" } }, "loader-runner": { @@ -3445,9 +3445,9 @@ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", "requires": { - "big.js": "5.2.2", - "emojis-list": "3.0.0", - "json5": "1.0.1" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" } }, "locate-path": { @@ -3455,8 +3455,8 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "requires": { - "p-locate": "3.0.0", - "path-exists": "3.0.0" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" }, "dependencies": { "path-exists": { @@ -3486,8 +3486,8 @@ "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", "requires": { - "currently-unhandled": "0.4.1", - "signal-exit": "3.0.3" + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" } }, "lower-case": { @@ -3500,8 +3500,8 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, "make-dir": { @@ -3509,8 +3509,8 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "requires": { - "pify": "4.0.1", - "semver": "5.7.1" + "pify": "^4.0.1", + "semver": "^5.6.0" }, "dependencies": { "pify": { @@ -3535,7 +3535,7 @@ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", "requires": { - "object-visit": "1.0.1" + "object-visit": "^1.0.0" } }, "md5.js": { @@ -3543,9 +3543,9 @@ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "requires": { - "hash-base": "3.1.0", - "inherits": "2.0.4", - "safe-buffer": "5.2.1" + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "media-typer": { @@ -3558,8 +3558,8 @@ "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", "requires": { - "errno": "0.1.8", - "readable-stream": "2.3.7" + "errno": "^0.1.3", + "readable-stream": "^2.0.1" }, "dependencies": { "readable-stream": { @@ -3567,13 +3567,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -3586,7 +3586,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -3596,16 +3596,16 @@ "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "requires": { - "camelcase-keys": "2.1.0", - "decamelize": "1.2.0", - "loud-rejection": "1.6.0", - "map-obj": "1.0.1", - "minimist": "1.2.5", - "normalize-package-data": "2.5.0", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "redent": "1.0.0", - "trim-newlines": "1.0.0" + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" } }, "merge-descriptors": { @@ -3623,19 +3623,19 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "braces": "2.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "extglob": "2.0.4", - "fragment-cache": "0.2.1", - "kind-of": "6.0.3", - "nanomatch": "1.2.13", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" } }, "miller-rabin": { @@ -3643,8 +3643,8 @@ "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "requires": { - "bn.js": "4.12.0", - "brorand": "1.1.0" + "bn.js": "^4.0.0", + "brorand": "^1.0.1" }, "dependencies": { "bn.js": { @@ -3687,7 +3687,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -3700,16 +3700,16 @@ "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", "requires": { - "concat-stream": "1.6.2", - "duplexify": "3.7.1", - "end-of-stream": "1.4.4", - "flush-write-stream": "1.1.1", - "from2": "2.3.0", - "parallel-transform": "1.2.0", - "pump": "3.0.0", - "pumpify": "1.5.1", - "stream-each": "1.2.3", - "through2": "2.0.5" + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" } }, "mixin-deep": { @@ -3717,8 +3717,8 @@ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "requires": { - "for-in": "1.0.2", - "is-extendable": "1.0.1" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { "is-extendable": { @@ -3726,7 +3726,7 @@ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", "requires": { - "is-plain-object": "2.0.4" + "is-plain-object": "^2.0.4" } } } @@ -3736,7 +3736,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "requires": { - "minimist": "1.2.5" + "minimist": "^1.2.5" } }, "move-concurrently": { @@ -3744,12 +3744,12 @@ "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", "requires": { - "aproba": "1.2.0", - "copy-concurrently": "1.0.5", - "fs-write-stream-atomic": "1.0.10", - "mkdirp": "0.5.5", - "rimraf": "2.7.1", - "run-queue": "1.0.3" + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" } }, "ms": { @@ -3762,8 +3762,8 @@ "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", "requires": { - "dns-packet": "1.3.4", - "thunky": "1.1.0" + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" } }, "multicast-dns-service-types": { @@ -3781,17 +3781,17 @@ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "requires": { - "arr-diff": "4.0.0", - "array-unique": "0.3.2", - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "fragment-cache": "0.2.1", - "is-windows": "1.0.2", - "kind-of": "6.0.3", - "object.pick": "1.3.0", - "regex-not": "1.0.2", - "snapdragon": "0.8.2", - "to-regex": "3.0.2" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" } }, "negotiator": { @@ -3814,7 +3814,7 @@ "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", "requires": { - "lower-case": "1.1.4" + "lower-case": "^1.1.1" } }, "node-forge": { @@ -3827,18 +3827,18 @@ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", "requires": { - "fstream": "1.0.12", - "glob": "7.1.7", - "graceful-fs": "4.2.6", - "mkdirp": "0.5.5", - "nopt": "3.0.6", - "npmlog": "4.1.2", - "osenv": "0.1.5", - "request": "2.88.2", - "rimraf": "2.7.1", - "semver": "5.3.0", - "tar": "2.2.2", - "which": "1.3.1" + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" }, "dependencies": { "semver": { @@ -3853,29 +3853,29 @@ "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", "requires": { - "assert": "1.5.0", - "browserify-zlib": "0.2.0", - "buffer": "4.9.2", - "console-browserify": "1.2.0", - "constants-browserify": "1.0.0", - "crypto-browserify": "3.12.0", - "domain-browser": "1.2.0", - "events": "3.3.0", - "https-browserify": "1.0.0", - "os-browserify": "0.3.0", + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", "path-browserify": "0.0.1", - "process": "0.11.10", - "punycode": "1.4.1", - "querystring-es3": "0.2.1", - "readable-stream": "2.3.7", - "stream-browserify": "2.0.2", - "stream-http": "2.8.3", - "string_decoder": "1.3.0", - "timers-browserify": "2.0.12", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", "tty-browserify": "0.0.0", - "url": "0.11.0", - "util": "0.11.1", - "vm-browserify": "1.1.2" + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" }, "dependencies": { "punycode": { @@ -3888,13 +3888,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" }, "dependencies": { "string_decoder": { @@ -3902,7 +3902,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -3919,23 +3919,23 @@ "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz", "integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==", "requires": { - "async-foreach": "0.1.3", - "chalk": "1.1.3", - "cross-spawn": "3.0.1", - "gaze": "1.1.3", - "get-stdin": "4.0.1", - "glob": "7.1.7", - "in-publish": "2.0.1", - "lodash": "4.17.21", - "meow": "3.7.0", - "mkdirp": "0.5.5", - "nan": "2.14.2", - "node-gyp": "3.8.0", - "npmlog": "4.1.2", - "request": "2.88.2", + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash": "^4.17.15", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.13.2", + "node-gyp": "^3.8.0", + "npmlog": "^4.0.0", + "request": "^2.88.0", "sass-graph": "2.2.5", - "stdout-stream": "1.4.1", - "true-case-path": "1.0.3" + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" } }, "nopt": { @@ -3943,7 +3943,7 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "requires": { - "abbrev": "1.1.1" + "abbrev": "1" } }, "normalize-package-data": { @@ -3951,10 +3951,10 @@ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "requires": { - "hosted-git-info": "2.8.9", - "resolve": "1.20.0", - "semver": "5.7.1", - "validate-npm-package-license": "3.0.4" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "normalize-path": { @@ -3967,7 +3967,7 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "requires": { - "path-key": "2.0.1" + "path-key": "^2.0.0" } }, "npmlog": { @@ -3975,10 +3975,10 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "requires": { - "are-we-there-yet": "1.1.5", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, "nth-check": { @@ -3986,7 +3986,7 @@ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", "requires": { - "boolbase": "1.0.0" + "boolbase": "~1.0.0" } }, "number-is-nan": { @@ -4009,9 +4009,9 @@ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", "requires": { - "copy-descriptor": "0.1.1", - "define-property": "0.2.5", - "kind-of": "3.2.2" + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, "dependencies": { "define-property": { @@ -4019,7 +4019,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "kind-of": { @@ -4027,7 +4027,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -4042,8 +4042,8 @@ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", "requires": { - "call-bind": "1.0.2", - "define-properties": "1.1.3" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "object-keys": { @@ -4056,7 +4056,7 @@ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.0" } }, "object.assign": { @@ -4064,10 +4064,10 @@ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "requires": { - "call-bind": "1.0.2", - "define-properties": "1.1.3", - "has-symbols": "1.0.2", - "object-keys": "1.1.1" + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" } }, "object.getownpropertydescriptors": { @@ -4075,9 +4075,9 @@ "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", "requires": { - "call-bind": "1.0.2", - "define-properties": "1.1.3", - "es-abstract": "1.18.3" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" } }, "object.pick": { @@ -4085,7 +4085,7 @@ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", "requires": { - "isobject": "3.0.1" + "isobject": "^3.0.1" } }, "obuf": { @@ -4111,7 +4111,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "opn": { @@ -4119,7 +4119,7 @@ "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", "requires": { - "is-wsl": "1.1.0" + "is-wsl": "^1.1.0" } }, "original": { @@ -4127,7 +4127,7 @@ "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", "requires": { - "url-parse": "1.5.1" + "url-parse": "^1.4.3" } }, "os-browserify": { @@ -4150,8 +4150,8 @@ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" } }, "p-finally": { @@ -4164,7 +4164,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "requires": { - "p-try": "2.2.0" + "p-try": "^2.0.0" } }, "p-locate": { @@ -4172,7 +4172,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "requires": { - "p-limit": "2.3.0" + "p-limit": "^2.0.0" } }, "p-map": { @@ -4185,7 +4185,7 @@ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", "requires": { - "retry": "0.12.0" + "retry": "^0.12.0" }, "dependencies": { "retry": { @@ -4210,9 +4210,9 @@ "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", "requires": { - "cyclist": "1.0.1", - "inherits": "2.0.4", - "readable-stream": "2.3.7" + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" }, "dependencies": { "readable-stream": { @@ -4220,13 +4220,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -4239,7 +4239,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -4249,7 +4249,7 @@ "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", "requires": { - "no-case": "2.3.2" + "no-case": "^2.2.0" } }, "parse-asn1": { @@ -4257,11 +4257,11 @@ "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", "requires": { - "asn1.js": "5.4.1", - "browserify-aes": "1.2.0", - "evp_bytestokey": "1.0.3", - "pbkdf2": "3.1.2", - "safe-buffer": "5.2.1" + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" } }, "parse-json": { @@ -4269,7 +4269,7 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "requires": { - "error-ex": "1.3.2" + "error-ex": "^1.2.0" } }, "parse-passwd": { @@ -4302,7 +4302,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "requires": { - "pinkie-promise": "2.0.1" + "pinkie-promise": "^2.0.0" } }, "path-is-absolute": { @@ -4335,9 +4335,9 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "requires": { - "graceful-fs": "4.2.6", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "pbkdf2": { @@ -4345,11 +4345,11 @@ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "requires": { - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "ripemd160": "2.0.2", - "safe-buffer": "5.2.1", - "sha.js": "2.4.11" + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, "performance-now": { @@ -4360,7 +4360,8 @@ "picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "optional": true }, "pify": { "version": "2.3.0", @@ -4377,7 +4378,7 @@ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "pkg-dir": { @@ -4385,7 +4386,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "requires": { - "find-up": "3.0.0" + "find-up": "^3.0.0" }, "dependencies": { "find-up": { @@ -4393,7 +4394,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { - "locate-path": "3.0.0" + "locate-path": "^3.0.0" } } } @@ -4403,9 +4404,9 @@ "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", "requires": { - "async": "2.6.3", - "debug": "3.2.7", - "mkdirp": "0.5.5" + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" }, "dependencies": { "debug": { @@ -4413,7 +4414,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "requires": { - "ms": "2.1.3" + "ms": "^2.1.1" } }, "ms": { @@ -4433,9 +4434,9 @@ "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", "requires": { - "chalk": "2.4.2", - "source-map": "0.6.1", - "supports-color": "5.5.0" + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" }, "dependencies": { "ansi-styles": { @@ -4443,7 +4444,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "1.9.3" + "color-convert": "^1.9.0" } }, "chalk": { @@ -4451,9 +4452,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, "supports-color": { @@ -4461,7 +4462,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -4471,7 +4472,7 @@ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz", "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==", "requires": { - "postcss": "6.0.23" + "postcss": "^6.0.1" } }, "postcss-modules-local-by-default": { @@ -4479,8 +4480,8 @@ "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", "requires": { - "css-selector-tokenizer": "0.7.3", - "postcss": "6.0.23" + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" } }, "postcss-modules-scope": { @@ -4488,8 +4489,8 @@ "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", "requires": { - "css-selector-tokenizer": "0.7.3", - "postcss": "6.0.23" + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" } }, "postcss-modules-values": { @@ -4497,8 +4498,8 @@ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", "requires": { - "icss-replace-symbols": "1.1.0", - "postcss": "6.0.23" + "icss-replace-symbols": "^1.1.0", + "postcss": "^6.0.1" } }, "postcss-value-parser": { @@ -4511,8 +4512,8 @@ "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", "requires": { - "lodash": "4.17.21", - "renderkid": "2.0.5" + "lodash": "^4.17.20", + "renderkid": "^2.0.4" } }, "process": { @@ -4535,8 +4536,8 @@ "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", "requires": { - "err-code": "1.1.2", - "retry": "0.10.1" + "err-code": "^1.0.0", + "retry": "^0.10.0" } }, "proxy-addr": { @@ -4568,12 +4569,12 @@ "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "requires": { - "bn.js": "4.12.0", - "browserify-rsa": "4.1.0", - "create-hash": "1.2.0", - "parse-asn1": "5.1.6", - "randombytes": "2.1.0", - "safe-buffer": "5.2.1" + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" }, "dependencies": { "bn.js": { @@ -4588,8 +4589,8 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "requires": { - "end-of-stream": "1.4.4", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "pumpify": { @@ -4597,9 +4598,9 @@ "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "requires": { - "duplexify": "3.7.1", - "inherits": "2.0.4", - "pump": "2.0.1" + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" }, "dependencies": { "pump": { @@ -4607,8 +4608,8 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "requires": { - "end-of-stream": "1.4.4", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } } } @@ -4623,16 +4624,16 @@ "resolved": "https://registry.npmjs.org/purs-loader/-/purs-loader-3.7.2.tgz", "integrity": "sha512-Sidqk2RE1R2DTPt30I6G3p//c9pMaV9jd36NI3HXXSyf4Kf5X01FiP/2wMTJ8a5XKAXKdKCJ3WPqA8Whlxi0tg==", "requires": { - "bluebird": "3.7.2", - "chalk": "1.1.3", - "cross-spawn": "3.0.1", - "dargs": "5.1.0", - "debug": "2.6.9", - "globby": "4.1.0", - "js-string-escape": "1.0.1", - "loader-utils": "1.4.0", - "lodash.difference": "4.5.0", - "promise-retry": "1.1.1" + "bluebird": "^3.3.5", + "chalk": "^1.1.3", + "cross-spawn": "^3.0.1", + "dargs": "^5.1.0", + "debug": "^2.6.0", + "globby": "^4.0.0", + "js-string-escape": "^1.0.1", + "loader-utils": "^1.0.2", + "lodash.difference": "^4.5.0", + "promise-retry": "^1.1.0" } }, "qs": { @@ -4660,7 +4661,7 @@ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "requires": { - "safe-buffer": "5.2.1" + "safe-buffer": "^5.1.0" } }, "randomfill": { @@ -4668,8 +4669,8 @@ "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", "requires": { - "randombytes": "2.1.0", - "safe-buffer": "5.2.1" + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" } }, "range-parser": { @@ -4700,9 +4701,9 @@ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.5.0", - "path-type": "1.1.0" + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" } }, "read-pkg-up": { @@ -4710,8 +4711,8 @@ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" } }, "readable-stream": { @@ -4719,9 +4720,9 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { - "inherits": "2.0.4", - "string_decoder": "1.3.0", - "util-deprecate": "1.0.2" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, "readdirp": { @@ -4730,7 +4731,7 @@ "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", "optional": true, "requires": { - "picomatch": "2.3.0" + "picomatch": "^2.2.1" } }, "redent": { @@ -4738,8 +4739,8 @@ "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "requires": { - "indent-string": "2.1.0", - "strip-indent": "1.0.1" + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" } }, "regex-not": { @@ -4747,8 +4748,8 @@ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", "requires": { - "extend-shallow": "3.0.2", - "safe-regex": "1.1.0" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" } }, "regexp.prototype.flags": { @@ -4756,8 +4757,8 @@ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", "requires": { - "call-bind": "1.0.2", - "define-properties": "1.1.3" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "relateurl": { @@ -4775,11 +4776,11 @@ "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.5.tgz", "integrity": "sha512-ccqoLg+HLOHq1vdfYNm4TBeaCDIi1FLt3wGojTDSvdewUv65oTmI3cnT2E4hRjl1gzKZIPK+KZrXzlUYKnR+vQ==", "requires": { - "css-select": "2.1.0", - "dom-converter": "0.2.0", - "htmlparser2": "3.10.1", - "lodash": "4.17.21", - "strip-ansi": "3.0.1" + "css-select": "^2.0.2", + "dom-converter": "^0.2", + "htmlparser2": "^3.10.1", + "lodash": "^4.17.20", + "strip-ansi": "^3.0.0" } }, "repeat-element": { @@ -4797,7 +4798,7 @@ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "requires": { - "is-finite": "1.1.0" + "is-finite": "^1.0.0" } }, "request": { @@ -4805,26 +4806,26 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.11.0", - "caseless": "0.12.0", - "combined-stream": "1.0.8", - "extend": "3.0.2", - "forever-agent": "0.6.1", - "form-data": "2.3.3", - "har-validator": "5.1.5", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.31", - "oauth-sign": "0.9.0", - "performance-now": "2.1.0", - "qs": "6.5.2", - "safe-buffer": "5.2.1", - "tough-cookie": "2.5.0", - "tunnel-agent": "0.6.0", - "uuid": "3.4.0" + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" }, "dependencies": { "uuid": { @@ -4854,8 +4855,8 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "requires": { - "is-core-module": "2.4.0", - "path-parse": "1.0.7" + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" } }, "resolve-cwd": { @@ -4863,7 +4864,7 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", "requires": { - "resolve-from": "3.0.0" + "resolve-from": "^3.0.0" } }, "resolve-dir": { @@ -4871,8 +4872,8 @@ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", "requires": { - "expand-tilde": "2.0.2", - "global-modules": "1.0.0" + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" }, "dependencies": { "global-modules": { @@ -4880,9 +4881,9 @@ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "requires": { - "global-prefix": "1.0.2", - "is-windows": "1.0.2", - "resolve-dir": "1.0.1" + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" } } } @@ -4912,7 +4913,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { - "glob": "7.1.7" + "glob": "^7.1.3" } }, "ripemd160": { @@ -4920,8 +4921,8 @@ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "requires": { - "hash-base": "3.1.0", - "inherits": "2.0.4" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "run-queue": { @@ -4929,7 +4930,7 @@ "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", "requires": { - "aproba": "1.2.0" + "aproba": "^1.1.1" } }, "safe-buffer": { @@ -4942,7 +4943,7 @@ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "requires": { - "ret": "0.1.15" + "ret": "~0.1.10" } }, "safer-buffer": { @@ -4955,10 +4956,10 @@ "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", "requires": { - "glob": "7.1.7", - "lodash": "4.17.21", - "scss-tokenizer": "0.2.3", - "yargs": "13.3.2" + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^13.3.2" } }, "sass-loader": { @@ -4966,11 +4967,11 @@ "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.3.1.tgz", "integrity": "sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA==", "requires": { - "clone-deep": "4.0.1", - "loader-utils": "1.4.0", - "neo-async": "2.6.2", - "pify": "4.0.1", - "semver": "6.3.0" + "clone-deep": "^4.0.1", + "loader-utils": "^1.0.1", + "neo-async": "^2.5.0", + "pify": "^4.0.1", + "semver": "^6.3.0" }, "dependencies": { "pify": { @@ -4990,7 +4991,7 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", "requires": { - "ajv": "5.5.2" + "ajv": "^5.0.0" } }, "scss-tokenizer": { @@ -4998,8 +4999,8 @@ "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", "requires": { - "js-base64": "2.6.4", - "source-map": "0.4.4" + "js-base64": "^2.1.8", + "source-map": "^0.4.2" }, "dependencies": { "source-map": { @@ -5007,7 +5008,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "requires": { - "amdefine": "1.0.1" + "amdefine": ">=0.0.4" } } } @@ -5022,7 +5023,7 @@ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz", "integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==", "requires": { - "node-forge": "0.10.0" + "node-forge": "^0.10.0" } }, "semver": { @@ -5036,18 +5037,18 @@ "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", "requires": { "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.7.2", + "http-errors": "~1.7.2", "mime": "1.6.0", "ms": "2.1.1", - "on-finished": "2.3.0", - "range-parser": "1.2.1", - "statuses": "1.5.0" + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" }, "dependencies": { "mime": { @@ -5067,7 +5068,7 @@ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", "requires": { - "randombytes": "2.1.0" + "randombytes": "^2.1.0" } }, "serve-index": { @@ -5075,13 +5076,13 @@ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", "requires": { - "accepts": "1.3.7", + "accepts": "~1.3.4", "batch": "0.6.1", "debug": "2.6.9", - "escape-html": "1.0.3", - "http-errors": "1.6.3", - "mime-types": "2.1.31", - "parseurl": "1.3.3" + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" }, "dependencies": { "http-errors": { @@ -5089,10 +5090,10 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { - "depd": "1.1.2", + "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": "1.5.0" + "statuses": ">= 1.4.0 < 2" } }, "inherits": { @@ -5112,9 +5113,9 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.3", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", "send": "0.17.1" } }, @@ -5128,10 +5129,10 @@ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "requires": { - "extend-shallow": "2.0.1", - "is-extendable": "0.1.1", - "is-plain-object": "2.0.4", - "split-string": "3.1.0" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "dependencies": { "extend-shallow": { @@ -5139,7 +5140,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } } } @@ -5159,8 +5160,8 @@ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { - "inherits": "2.0.4", - "safe-buffer": "5.2.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "shallow-clone": { @@ -5168,7 +5169,7 @@ "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "requires": { - "kind-of": "6.0.3" + "kind-of": "^6.0.2" } }, "shebang-command": { @@ -5176,7 +5177,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "requires": { - "shebang-regex": "1.0.0" + "shebang-regex": "^1.0.0" } }, "shebang-regex": { @@ -5194,14 +5195,14 @@ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", "requires": { - "base": "0.11.2", - "debug": "2.6.9", - "define-property": "0.2.5", - "extend-shallow": "2.0.1", - "map-cache": "0.2.2", - "source-map": "0.5.7", - "source-map-resolve": "0.5.3", - "use": "3.1.1" + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" }, "dependencies": { "define-property": { @@ -5209,7 +5210,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } }, "extend-shallow": { @@ -5217,7 +5218,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "requires": { - "is-extendable": "0.1.1" + "is-extendable": "^0.1.0" } }, "source-map": { @@ -5232,9 +5233,9 @@ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", "requires": { - "define-property": "1.0.0", - "isobject": "3.0.1", - "snapdragon-util": "3.0.1" + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" }, "dependencies": { "define-property": { @@ -5242,7 +5243,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", "requires": { - "is-descriptor": "1.0.2" + "is-descriptor": "^1.0.0" } }, "is-accessor-descriptor": { @@ -5250,7 +5251,7 @@ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", "requires": { - "kind-of": "6.0.3" + "kind-of": "^6.0.0" } }, "is-data-descriptor": { @@ -5258,7 +5259,7 @@ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", "requires": { - "kind-of": "6.0.3" + "kind-of": "^6.0.0" } }, "is-descriptor": { @@ -5266,9 +5267,9 @@ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", "requires": { - "is-accessor-descriptor": "1.0.0", - "is-data-descriptor": "1.0.0", - "kind-of": "6.0.3" + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" } } } @@ -5278,7 +5279,7 @@ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.2.0" }, "dependencies": { "kind-of": { @@ -5286,7 +5287,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -5296,9 +5297,9 @@ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", "requires": { - "faye-websocket": "0.11.4", - "uuid": "3.4.0", - "websocket-driver": "0.7.4" + "faye-websocket": "^0.11.3", + "uuid": "^3.4.0", + "websocket-driver": "^0.7.4" }, "dependencies": { "uuid": { @@ -5313,12 +5314,12 @@ "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.1.tgz", "integrity": "sha512-VnVAb663fosipI/m6pqRXakEOw7nvd7TUgdr3PlR/8V2I95QIdwT8L4nMxhyU8SmDBHYXU1TOElaKOmKLfYzeQ==", "requires": { - "debug": "3.2.7", - "eventsource": "1.1.0", - "faye-websocket": "0.11.4", - "inherits": "2.0.4", - "json3": "3.3.3", - "url-parse": "1.5.1" + "debug": "^3.2.6", + "eventsource": "^1.0.7", + "faye-websocket": "^0.11.3", + "inherits": "^2.0.4", + "json3": "^3.3.3", + "url-parse": "^1.5.1" }, "dependencies": { "debug": { @@ -5326,7 +5327,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "requires": { - "ms": "2.1.3" + "ms": "^2.1.1" } }, "ms": { @@ -5351,11 +5352,11 @@ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", "requires": { - "atob": "2.1.2", - "decode-uri-component": "0.2.0", - "resolve-url": "0.2.1", - "source-map-url": "0.4.1", - "urix": "0.1.0" + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, "source-map-support": { @@ -5363,8 +5364,8 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", "requires": { - "buffer-from": "1.1.1", - "source-map": "0.6.1" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, "source-map-url": { @@ -5377,8 +5378,8 @@ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "requires": { - "spdx-expression-parse": "3.0.1", - "spdx-license-ids": "3.0.9" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-exceptions": { @@ -5391,8 +5392,8 @@ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "requires": { - "spdx-exceptions": "2.3.0", - "spdx-license-ids": "3.0.9" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, "spdx-license-ids": { @@ -5405,11 +5406,11 @@ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "requires": { - "debug": "4.3.1", - "handle-thing": "2.0.1", - "http-deceiver": "1.2.7", - "select-hose": "2.0.0", - "spdy-transport": "3.0.0" + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" }, "dependencies": { "debug": { @@ -5432,12 +5433,12 @@ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "requires": { - "debug": "4.3.1", - "detect-node": "2.1.0", - "hpack.js": "2.1.6", - "obuf": "1.1.2", - "readable-stream": "3.6.0", - "wbuf": "1.7.3" + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" }, "dependencies": { "debug": { @@ -5460,7 +5461,7 @@ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", "requires": { - "extend-shallow": "3.0.2" + "extend-shallow": "^3.0.0" } }, "sshpk": { @@ -5468,15 +5469,15 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "requires": { - "asn1": "0.2.4", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.2", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.2", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "safer-buffer": "2.1.2", - "tweetnacl": "0.14.5" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" } }, "ssri": { @@ -5484,7 +5485,7 @@ "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", "requires": { - "figgy-pudding": "3.5.2" + "figgy-pudding": "^3.5.1" } }, "static-extend": { @@ -5492,8 +5493,8 @@ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", "requires": { - "define-property": "0.2.5", - "object-copy": "0.1.0" + "define-property": "^0.2.5", + "object-copy": "^0.1.0" }, "dependencies": { "define-property": { @@ -5501,7 +5502,7 @@ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", "requires": { - "is-descriptor": "0.1.6" + "is-descriptor": "^0.1.0" } } } @@ -5516,7 +5517,7 @@ "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", "requires": { - "readable-stream": "2.3.7" + "readable-stream": "^2.0.1" }, "dependencies": { "readable-stream": { @@ -5524,13 +5525,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -5543,7 +5544,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -5553,8 +5554,8 @@ "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "requires": { - "inherits": "2.0.4", - "readable-stream": "2.3.7" + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" }, "dependencies": { "readable-stream": { @@ -5562,13 +5563,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -5581,7 +5582,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -5591,8 +5592,8 @@ "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", "requires": { - "end-of-stream": "1.4.4", - "stream-shift": "1.0.1" + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" } }, "stream-http": { @@ -5600,11 +5601,11 @@ "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", "requires": { - "builtin-status-codes": "3.0.0", - "inherits": "2.0.4", - "readable-stream": "2.3.7", - "to-arraybuffer": "1.0.1", - "xtend": "4.0.2" + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" }, "dependencies": { "readable-stream": { @@ -5612,13 +5613,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -5631,7 +5632,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -5646,9 +5647,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string.prototype.trimend": { @@ -5656,8 +5657,8 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", "requires": { - "call-bind": "1.0.2", - "define-properties": "1.1.3" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "string.prototype.trimstart": { @@ -5665,8 +5666,8 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", "requires": { - "call-bind": "1.0.2", - "define-properties": "1.1.3" + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "string_decoder": { @@ -5674,7 +5675,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "requires": { - "safe-buffer": "5.2.1" + "safe-buffer": "~5.2.0" } }, "strip-ansi": { @@ -5682,7 +5683,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -5690,7 +5691,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "requires": { - "is-utf8": "0.2.1" + "is-utf8": "^0.2.0" } }, "strip-eof": { @@ -5703,7 +5704,7 @@ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", "requires": { - "get-stdin": "4.0.1" + "get-stdin": "^4.0.1" } }, "style-loader": { @@ -5711,8 +5712,8 @@ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", "integrity": "sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg==", "requires": { - "loader-utils": "1.4.0", - "schema-utils": "1.0.0" + "loader-utils": "^1.1.0", + "schema-utils": "^1.0.0" }, "dependencies": { "ajv": { @@ -5720,10 +5721,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "3.1.3", - "fast-json-stable-stringify": "2.1.0", - "json-schema-traverse": "0.4.1", - "uri-js": "4.4.1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "fast-deep-equal": { @@ -5741,9 +5742,9 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { - "ajv": "6.12.6", - "ajv-errors": "1.0.1", - "ajv-keywords": "3.5.2" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } } } @@ -5763,9 +5764,9 @@ "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.12", - "inherits": "2.0.4" + "block-stream": "*", + "fstream": "^1.0.12", + "inherits": "2" } }, "terser": { @@ -5773,9 +5774,9 @@ "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", "requires": { - "commander": "2.20.3", - "source-map": "0.6.1", - "source-map-support": "0.5.19" + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" }, "dependencies": { "commander": { @@ -5790,15 +5791,15 @@ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", "requires": { - "cacache": "12.0.4", - "find-cache-dir": "2.1.0", - "is-wsl": "1.1.0", - "schema-utils": "1.0.0", - "serialize-javascript": "4.0.0", - "source-map": "0.6.1", - "terser": "4.8.0", - "webpack-sources": "1.4.3", - "worker-farm": "1.7.0" + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" }, "dependencies": { "ajv": { @@ -5806,10 +5807,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "3.1.3", - "fast-json-stable-stringify": "2.1.0", - "json-schema-traverse": "0.4.1", - "uri-js": "4.4.1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "fast-deep-equal": { @@ -5827,9 +5828,9 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { - "ajv": "6.12.6", - "ajv-errors": "1.0.1", - "ajv-keywords": "3.5.2" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } } } @@ -5839,8 +5840,8 @@ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", "requires": { - "readable-stream": "2.3.7", - "xtend": "4.0.2" + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" }, "dependencies": { "readable-stream": { @@ -5848,13 +5849,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -5867,7 +5868,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -5882,7 +5883,7 @@ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", "requires": { - "setimmediate": "1.0.5" + "setimmediate": "^1.0.4" } }, "to-arraybuffer": { @@ -5895,7 +5896,7 @@ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", "requires": { - "kind-of": "3.2.2" + "kind-of": "^3.0.2" }, "dependencies": { "kind-of": { @@ -5903,7 +5904,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "requires": { - "is-buffer": "1.1.6" + "is-buffer": "^1.1.5" } } } @@ -5913,10 +5914,10 @@ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "requires": { - "define-property": "2.0.2", - "extend-shallow": "3.0.2", - "regex-not": "1.0.2", - "safe-regex": "1.1.0" + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" } }, "to-regex-range": { @@ -5924,8 +5925,8 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", "requires": { - "is-number": "3.0.0", - "repeat-string": "1.6.1" + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" } }, "toidentifier": { @@ -5943,8 +5944,8 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "requires": { - "psl": "1.8.0", - "punycode": "2.1.1" + "psl": "^1.1.28", + "punycode": "^2.1.1" } }, "trim-newlines": { @@ -5957,7 +5958,7 @@ "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", "requires": { - "glob": "7.1.7" + "glob": "^7.1.2" } }, "tty-browserify": { @@ -5970,7 +5971,7 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "5.2.1" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { @@ -5984,7 +5985,7 @@ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.31" + "mime-types": "~2.1.24" } }, "typedarray": { @@ -5997,8 +5998,8 @@ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", "requires": { - "commander": "2.19.0", - "source-map": "0.6.1" + "commander": "~2.19.0", + "source-map": "~0.6.1" }, "dependencies": { "commander": { @@ -6013,10 +6014,10 @@ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", "requires": { - "function-bind": "1.1.1", - "has-bigints": "1.0.1", - "has-symbols": "1.0.2", - "which-boxed-primitive": "1.0.2" + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" } }, "union-value": { @@ -6024,10 +6025,10 @@ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "requires": { - "arr-union": "3.1.0", - "get-value": "2.0.6", - "is-extendable": "0.1.1", - "set-value": "2.0.1" + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" } }, "unique-filename": { @@ -6035,7 +6036,7 @@ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "requires": { - "unique-slug": "2.0.2" + "unique-slug": "^2.0.0" } }, "unique-slug": { @@ -6043,7 +6044,7 @@ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", "requires": { - "imurmurhash": "0.1.4" + "imurmurhash": "^0.1.4" } }, "unpipe": { @@ -6056,8 +6057,8 @@ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "requires": { - "has-value": "0.3.1", - "isobject": "3.0.1" + "has-value": "^0.3.1", + "isobject": "^3.0.0" }, "dependencies": { "has-value": { @@ -6065,9 +6066,9 @@ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", "requires": { - "get-value": "2.0.6", - "has-values": "0.1.4", - "isobject": "2.1.0" + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" }, "dependencies": { "isobject": { @@ -6102,7 +6103,7 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "requires": { - "punycode": "2.1.1" + "punycode": "^2.1.0" } }, "urix": { @@ -6131,9 +6132,9 @@ "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.2.tgz", "integrity": "sha512-dXHkKmw8FhPqu8asTc1puBfe3TehOCo2+RmOOev5suNCIYBcT626kxiWg1NBVkwc4rO8BGa7gP70W7VXuqHrjg==", "requires": { - "loader-utils": "1.4.0", - "mime": "2.5.2", - "schema-utils": "1.0.0" + "loader-utils": "^1.1.0", + "mime": "^2.0.3", + "schema-utils": "^1.0.0" }, "dependencies": { "ajv": { @@ -6141,10 +6142,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "3.1.3", - "fast-json-stable-stringify": "2.1.0", - "json-schema-traverse": "0.4.1", - "uri-js": "4.4.1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "fast-deep-equal": { @@ -6162,9 +6163,9 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { - "ajv": "6.12.6", - "ajv-errors": "1.0.1", - "ajv-keywords": "3.5.2" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } } } @@ -6174,8 +6175,8 @@ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", "requires": { - "querystringify": "2.2.0", - "requires-port": "1.0.0" + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" } }, "use": { @@ -6208,8 +6209,8 @@ "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", "requires": { - "define-properties": "1.1.3", - "object.getownpropertydescriptors": "2.1.2" + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" } }, "utila": { @@ -6242,8 +6243,8 @@ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "requires": { - "spdx-correct": "3.1.1", - "spdx-expression-parse": "3.0.1" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, "vary": { @@ -6256,9 +6257,9 @@ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { - "assert-plus": "1.0.0", + "assert-plus": "^1.0.0", "core-util-is": "1.0.2", - "extsprintf": "1.3.0" + "extsprintf": "^1.2.0" } }, "vm-browserify": { @@ -6271,10 +6272,10 @@ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", "requires": { - "chokidar": "3.5.1", - "graceful-fs": "4.2.6", - "neo-async": "2.6.2", - "watchpack-chokidar2": "2.0.1" + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" } }, "watchpack-chokidar2": { @@ -6283,7 +6284,7 @@ "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", "optional": true, "requires": { - "chokidar": "2.1.8" + "chokidar": "^2.1.8" }, "dependencies": { "anymatch": { @@ -6292,8 +6293,8 @@ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "optional": true, "requires": { - "micromatch": "3.1.10", - "normalize-path": "2.1.1" + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" }, "dependencies": { "normalize-path": { @@ -6302,7 +6303,7 @@ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "optional": true, "requires": { - "remove-trailing-separator": "1.1.0" + "remove-trailing-separator": "^1.0.1" } } } @@ -6319,18 +6320,18 @@ "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "optional": true, "requires": { - "anymatch": "2.0.0", - "async-each": "1.0.3", - "braces": "2.3.2", - "fsevents": "1.2.13", - "glob-parent": "3.1.0", - "inherits": "2.0.4", - "is-binary-path": "1.0.1", - "is-glob": "4.0.1", - "normalize-path": "3.0.0", - "path-is-absolute": "1.0.1", - "readdirp": "2.2.1", - "upath": "1.2.0" + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" } }, "fsevents": { @@ -6339,7 +6340,7 @@ "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "optional": true, "requires": { - "nan": "2.14.2" + "nan": "^2.12.1" } }, "glob-parent": { @@ -6348,8 +6349,8 @@ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "optional": true, "requires": { - "is-glob": "3.1.0", - "path-dirname": "1.0.2" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" }, "dependencies": { "is-glob": { @@ -6358,7 +6359,7 @@ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "optional": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.0" } } } @@ -6369,7 +6370,7 @@ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "optional": true, "requires": { - "binary-extensions": "1.13.1" + "binary-extensions": "^1.0.0" } }, "readable-stream": { @@ -6378,13 +6379,13 @@ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "optional": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "readdirp": { @@ -6393,15 +6394,16 @@ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "optional": true, "requires": { - "graceful-fs": "4.2.6", - "micromatch": "3.1.10", - "readable-stream": "2.3.7" + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" } }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true }, "string_decoder": { "version": "1.1.1", @@ -6409,7 +6411,7 @@ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "optional": true, "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -6419,7 +6421,7 @@ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "requires": { - "minimalistic-assert": "1.0.1" + "minimalistic-assert": "^1.0.0" } }, "webpack": { @@ -6431,25 +6433,25 @@ "@webassemblyjs/helper-module-context": "1.9.0", "@webassemblyjs/wasm-edit": "1.9.0", "@webassemblyjs/wasm-parser": "1.9.0", - "acorn": "6.4.2", - "ajv": "6.12.6", - "ajv-keywords": "3.5.2", - "chrome-trace-event": "1.0.3", - "enhanced-resolve": "4.5.0", - "eslint-scope": "4.0.3", - "json-parse-better-errors": "1.0.2", - "loader-runner": "2.4.0", - "loader-utils": "1.4.0", - "memory-fs": "0.4.1", - "micromatch": "3.1.10", - "mkdirp": "0.5.5", - "neo-async": "2.6.2", - "node-libs-browser": "2.2.1", - "schema-utils": "1.0.0", - "tapable": "1.1.3", - "terser-webpack-plugin": "1.4.5", - "watchpack": "1.7.5", - "webpack-sources": "1.4.3" + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" }, "dependencies": { "ajv": { @@ -6457,10 +6459,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "3.1.3", - "fast-json-stable-stringify": "2.1.0", - "json-schema-traverse": "0.4.1", - "uri-js": "4.4.1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "fast-deep-equal": { @@ -6478,9 +6480,9 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { - "ajv": "6.12.6", - "ajv-errors": "1.0.1", - "ajv-keywords": "3.5.2" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } } } @@ -6490,17 +6492,17 @@ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz", "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==", "requires": { - "chalk": "2.4.2", - "cross-spawn": "6.0.5", - "enhanced-resolve": "4.5.0", - "findup-sync": "3.0.0", - "global-modules": "2.0.0", - "import-local": "2.0.0", - "interpret": "1.4.0", - "loader-utils": "1.4.0", - "supports-color": "6.1.0", - "v8-compile-cache": "2.3.0", - "yargs": "13.3.2" + "chalk": "^2.4.2", + "cross-spawn": "^6.0.5", + "enhanced-resolve": "^4.1.1", + "findup-sync": "^3.0.0", + "global-modules": "^2.0.0", + "import-local": "^2.0.0", + "interpret": "^1.4.0", + "loader-utils": "^1.4.0", + "supports-color": "^6.1.0", + "v8-compile-cache": "^2.1.1", + "yargs": "^13.3.2" }, "dependencies": { "ansi-styles": { @@ -6508,7 +6510,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "1.9.3" + "color-convert": "^1.9.0" } }, "chalk": { @@ -6516,9 +6518,9 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "dependencies": { "supports-color": { @@ -6526,7 +6528,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -6536,11 +6538,11 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "requires": { - "nice-try": "1.0.5", - "path-key": "2.0.1", - "semver": "5.7.1", - "shebang-command": "1.2.0", - "which": "1.3.1" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, "supports-color": { @@ -6548,7 +6550,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -6558,11 +6560,11 @@ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz", "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==", "requires": { - "memory-fs": "0.4.1", - "mime": "2.5.2", - "mkdirp": "0.5.5", - "range-parser": "1.2.1", - "webpack-log": "2.0.0" + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" } }, "webpack-dev-server": { @@ -6571,38 +6573,38 @@ "integrity": "sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ==", "requires": { "ansi-html": "0.0.7", - "bonjour": "3.5.0", - "chokidar": "2.1.8", - "compression": "1.7.4", - "connect-history-api-fallback": "1.6.0", - "debug": "4.3.1", - "del": "4.1.1", - "express": "4.17.1", - "html-entities": "1.4.0", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", "http-proxy-middleware": "0.19.1", - "import-local": "2.0.0", - "internal-ip": "4.3.0", - "ip": "1.1.5", - "is-absolute-url": "3.0.3", - "killable": "1.0.1", - "loglevel": "1.7.1", - "opn": "5.5.0", - "p-retry": "3.0.1", - "portfinder": "1.0.28", - "schema-utils": "1.0.0", - "selfsigned": "1.10.11", - "semver": "6.3.0", - "serve-index": "1.9.1", - "sockjs": "0.3.21", - "sockjs-client": "1.5.1", - "spdy": "4.0.2", - "strip-ansi": "3.0.1", - "supports-color": "6.1.0", - "url": "0.11.0", - "webpack-dev-middleware": "3.7.3", - "webpack-log": "2.0.0", - "ws": "6.2.2", - "yargs": "13.3.2" + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.8", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.21", + "sockjs-client": "^1.5.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" }, "dependencies": { "ajv": { @@ -6610,10 +6612,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "3.1.3", - "fast-json-stable-stringify": "2.1.0", - "json-schema-traverse": "0.4.1", - "uri-js": "4.4.1" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "anymatch": { @@ -6621,8 +6623,8 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "requires": { - "micromatch": "3.1.10", - "normalize-path": "2.1.1" + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" }, "dependencies": { "normalize-path": { @@ -6630,7 +6632,7 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "requires": { - "remove-trailing-separator": "1.1.0" + "remove-trailing-separator": "^1.0.1" } } } @@ -6645,18 +6647,18 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", "requires": { - "anymatch": "2.0.0", - "async-each": "1.0.3", - "braces": "2.3.2", - "fsevents": "1.2.13", - "glob-parent": "3.1.0", - "inherits": "2.0.4", - "is-binary-path": "1.0.1", - "is-glob": "4.0.1", - "normalize-path": "3.0.0", - "path-is-absolute": "1.0.1", - "readdirp": "2.2.1", - "upath": "1.2.0" + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" } }, "debug": { @@ -6678,7 +6680,7 @@ "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "optional": true, "requires": { - "nan": "2.14.2" + "nan": "^2.12.1" } }, "glob-parent": { @@ -6686,8 +6688,8 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", "requires": { - "is-glob": "3.1.0", - "path-dirname": "1.0.2" + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" }, "dependencies": { "is-glob": { @@ -6695,7 +6697,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.0" } } } @@ -6705,7 +6707,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", "requires": { - "binary-extensions": "1.13.1" + "binary-extensions": "^1.0.0" } }, "json-schema-traverse": { @@ -6723,13 +6725,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "readdirp": { @@ -6737,9 +6739,9 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "requires": { - "graceful-fs": "4.2.6", - "micromatch": "3.1.10", - "readable-stream": "2.3.7" + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" } }, "safe-buffer": { @@ -6752,9 +6754,9 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "requires": { - "ajv": "6.12.6", - "ajv-errors": "1.0.1", - "ajv-keywords": "3.5.2" + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" } }, "semver": { @@ -6767,7 +6769,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } }, "supports-color": { @@ -6775,7 +6777,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -6785,8 +6787,8 @@ "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", "requires": { - "ansi-colors": "3.2.4", - "uuid": "3.4.0" + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" }, "dependencies": { "uuid": { @@ -6801,8 +6803,8 @@ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", "requires": { - "source-list-map": "2.0.1", - "source-map": "0.6.1" + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" } }, "websocket-driver": { @@ -6810,9 +6812,9 @@ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "requires": { - "http-parser-js": "0.5.3", - "safe-buffer": "5.2.1", - "websocket-extensions": "0.1.4" + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" } }, "websocket-extensions": { @@ -6825,7 +6827,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "which-boxed-primitive": { @@ -6833,11 +6835,11 @@ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "requires": { - "is-bigint": "1.0.2", - "is-boolean-object": "1.1.1", - "is-number-object": "1.0.5", - "is-string": "1.0.6", - "is-symbol": "1.0.4" + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" } }, "which-module": { @@ -6850,7 +6852,7 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.2 || 2" } }, "worker-farm": { @@ -6858,7 +6860,7 @@ "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", "requires": { - "errno": "0.1.8" + "errno": "~0.1.7" } }, "wrap-ansi": { @@ -6866,9 +6868,9 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "requires": { - "ansi-styles": "3.2.1", - "string-width": "3.1.0", - "strip-ansi": "5.2.0" + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" }, "dependencies": { "ansi-regex": { @@ -6881,7 +6883,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "1.9.3" + "color-convert": "^1.9.0" } }, "is-fullwidth-code-point": { @@ -6894,9 +6896,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "requires": { - "emoji-regex": "7.0.3", - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "5.2.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" } }, "strip-ansi": { @@ -6904,7 +6906,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "requires": { - "ansi-regex": "4.1.0" + "ansi-regex": "^4.1.0" } } } @@ -6919,7 +6921,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", "requires": { - "async-limiter": "1.0.1" + "async-limiter": "~1.0.0" } }, "xhr2": { @@ -6947,16 +6949,16 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "requires": { - "cliui": "5.0.0", - "find-up": "3.0.0", - "get-caller-file": "2.0.5", - "require-directory": "2.1.1", - "require-main-filename": "2.0.0", - "set-blocking": "2.0.0", - "string-width": "3.1.0", - "which-module": "2.0.0", - "y18n": "4.0.3", - "yargs-parser": "13.1.2" + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" }, "dependencies": { "ansi-regex": { @@ -6969,7 +6971,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { - "locate-path": "3.0.0" + "locate-path": "^3.0.0" } }, "is-fullwidth-code-point": { @@ -6982,9 +6984,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "requires": { - "emoji-regex": "7.0.3", - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "5.2.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" } }, "strip-ansi": { @@ -6992,7 +6994,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "requires": { - "ansi-regex": "4.1.0" + "ansi-regex": "^4.1.0" } } } @@ -7002,8 +7004,8 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "requires": { - "camelcase": "5.3.1", - "decamelize": "1.2.0" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" }, "dependencies": { "camelcase": { diff --git a/MetaLamp/lending-pool/nix/pkgs/default.nix b/MetaLamp/lending-pool/nix/pkgs/default.nix index 39318a7a2..18cef4750 100644 --- a/MetaLamp/lending-pool/nix/pkgs/default.nix +++ b/MetaLamp/lending-pool/nix/pkgs/default.nix @@ -17,6 +17,8 @@ let cabal-install = plutus.plutus.cabal-install; + nodejs = plutus.pkgs.nodejs; + purs = plutus.plutus.purs; spago = plutus.plutus.spago; @@ -28,5 +30,5 @@ let cardano-repo-tool = plutus.plutus.cardano-repo-tool; in { - inherit haskell hlint cabal-install purs spago stylish-haskell haskell-language-server cardano-repo-tool; + inherit haskell hlint cabal-install nodejs purs spago stylish-haskell haskell-language-server cardano-repo-tool; } diff --git a/MetaLamp/lending-pool/shell.nix b/MetaLamp/lending-pool/shell.nix index 039a57811..c3dca2a53 100644 --- a/MetaLamp/lending-pool/shell.nix +++ b/MetaLamp/lending-pool/shell.nix @@ -10,6 +10,7 @@ in nativeBuildInputs = with plutus-starter; [ hlint cabal-install + nodejs purs spago haskell-language-server From 26563e5136e89ead767600562a94024b0dd709ec Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Tue, 20 Jul 2021 13:05:52 +0700 Subject: [PATCH 162/169] add purty, fix-purty. fix-stylish-haskell --- MetaLamp/lending-pool/nix/pkgs/default.nix | 12 ++++++++++-- MetaLamp/lending-pool/shell.nix | 3 +++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/MetaLamp/lending-pool/nix/pkgs/default.nix b/MetaLamp/lending-pool/nix/pkgs/default.nix index 18cef4750..98ffcd0e2 100644 --- a/MetaLamp/lending-pool/nix/pkgs/default.nix +++ b/MetaLamp/lending-pool/nix/pkgs/default.nix @@ -23,12 +23,20 @@ let spago = plutus.plutus.spago; + purty = plutus.plutus.purty; + + fix-purty = plutus.plutus.fixPurty; + + fix-stylish-haskell = plutus.plutus.fixStylishHaskell; + stylish-haskell = plutus.plutus.stylish-haskell; haskell-language-server = plutus.plutus.haskell-language-server; cardano-repo-tool = plutus.plutus.cardano-repo-tool; in -{ - inherit haskell hlint cabal-install nodejs purs spago stylish-haskell haskell-language-server cardano-repo-tool; +{ + inherit nodejs purs spago purty fix-purty; + inherit haskell hlint cabal-install stylish-haskell fix-stylish-haskell haskell-language-server; + inherit cardano-repo-tool; } diff --git a/MetaLamp/lending-pool/shell.nix b/MetaLamp/lending-pool/shell.nix index c3dca2a53..69f0ba40d 100644 --- a/MetaLamp/lending-pool/shell.nix +++ b/MetaLamp/lending-pool/shell.nix @@ -13,8 +13,11 @@ in nodejs purs spago + purty + fix-purty haskell-language-server stylish-haskell + fix-stylish-haskell pkgs.niv cardano-repo-tool ]; From 2a1986683150998585f711d3b8664cd9b108c915 Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Tue, 20 Jul 2021 13:42:48 +0700 Subject: [PATCH 163/169] remove package-lock --- MetaLamp/lending-pool/package-lock.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 MetaLamp/lending-pool/package-lock.json diff --git a/MetaLamp/lending-pool/package-lock.json b/MetaLamp/lending-pool/package-lock.json deleted file mode 100644 index 48e341a09..000000000 --- a/MetaLamp/lending-pool/package-lock.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "lockfileVersion": 1 -} From 62788264f7bf7f8ba6ce7c32aefa80b5caa23c6d Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Tue, 14 Sep 2021 11:15:51 +0700 Subject: [PATCH 164/169] update backend --- MetaLamp/lending-pool/cabal.project | 114 ++++++++++++------ .../client/scripts/fetch-plutus-purs.sh | 2 +- MetaLamp/lending-pool/nix/pkgs/default.nix | 9 +- .../lending-pool/nix/pkgs/haskell/default.nix | 5 +- .../lending-pool/nix/pkgs/haskell/haskell.nix | 35 +++--- MetaLamp/lending-pool/nix/sources.json | 6 +- MetaLamp/lending-pool/plutus-starter.cabal | 1 + .../src/Ext/Plutus/Ledger/Contexts.hs | 4 +- .../src/Plutus/Abstract/ContractResponse.hs | 27 +++-- .../src/Plutus/Abstract/State/Select.hs | 10 +- .../src/Plutus/Abstract/State/Update.hs | 20 +-- .../src/Plutus/Abstract/TxUtils.hs | 16 +-- .../Contracts/LendingPool/OffChain/AToken.hs | 7 +- .../Contracts/LendingPool/OffChain/Info.hs | 8 +- .../Contracts/LendingPool/OffChain/Owner.hs | 6 +- .../Contracts/LendingPool/OffChain/User.hs | 10 +- .../Contracts/LendingPool/OnChain/AToken.hs | 18 +-- .../LendingPool/OnChain/Core/Logic.hs | 4 +- .../Plutus/Contracts/Service/FungibleToken.hs | 12 +- .../src/Plutus/Contracts/Service/Oracle.hs | 19 +-- .../lending-pool/src/Plutus/PAB/Simulation.hs | 47 ++++---- MetaLamp/lending-pool/test/Fixtures/Init.hs | 2 +- MetaLamp/lending-pool/test/Fixtures/Symbol.hs | 12 +- MetaLamp/lending-pool/test/Spec/Shared.hs | 1 - MetaLamp/lending-pool/test/Utils/Data.hs | 3 +- MetaLamp/lending-pool/test/Utils/Trace.hs | 10 +- 26 files changed, 228 insertions(+), 180 deletions(-) diff --git a/MetaLamp/lending-pool/cabal.project b/MetaLamp/lending-pool/cabal.project index ad1a2aaad..710c15c7a 100644 --- a/MetaLamp/lending-pool/cabal.project +++ b/MetaLamp/lending-pool/cabal.project @@ -1,4 +1,4 @@ -index-state: 2021-04-13T00:00:00Z +index-state: 2021-08-14T00:00:00Z packages: ./. @@ -9,6 +9,7 @@ write-ghc-environment-files: never tests: true benchmarks: true +-- Plutus revision from 2021/08/16 source-repository-package type: git location: https://github.com/input-output-hk/plutus.git @@ -17,6 +18,7 @@ source-repository-package playground-common plutus-core plutus-contract + plutus-chain-index plutus-ledger plutus-ledger-api plutus-tx @@ -26,41 +28,66 @@ source-repository-package prettyprinter-configurable quickcheck-dynamic word-array - tag: plutus-starter-devcontainer/v1.0.6 + tag: plutus-starter-devcontainer/v1.0.8 + -- The following sections are copied from the 'plutus' repository cabal.project at the revision -- given above. -- This is necessary because the 'plutus' libraries depend on a number of other libraries which are -- not on Hackage, and so need to be pulled in as `source-repository-package`s themselves. Make sure to -- re-update this section from the template when you do an upgrade. -package eventful-sql-common - ghc-options: -XDerivingStrategies -XStandaloneDeriving -XUndecidableInstances -XDataKinds -XFlexibleInstances + +-- We never, ever, want this. +write-ghc-environment-files: never + +-- Always build tests and benchmarks. +tests: true +benchmarks: true + +-- The only sensible test display option +test-show-details: streaming allow-newer: - -- Has a commit to allow newer aeson, not on Hackage yet - monoidal-containers:aeson -- Pins to an old version of Template Haskell, unclear if/when it will be updated - , size-based:template-haskell - - -- The following two dependencies are needed by plutus. - , eventful-sql-common:persistent - , eventful-sql-common:persistent-template + size-based:template-haskell + , ouroboros-consensus-byron:formatting + , beam-core:aeson + , beam-sqlite:aeson + , beam-sqlite:dlist + , beam-migrate:aeson constraints: - -- aws-lambda-haskell-runtime-wai doesn't compile with newer versions - aws-lambda-haskell-runtime <= 3.0.3 -- big breaking change here, inline-r doens't have an upper bound - , singletons < 3.0 - -- breaks eventful even more than it already was - , persistent-template < 2.12 - + singletons < 3.0 + -- bizarre issue: in earlier versions they define their own 'GEq', in newer + -- ones they reuse the one from 'some', but there isn't e.g. a proper version + -- constraint from dependent-sum-template (which is the library we actually use). + , dependent-sum > 0.6.2.0 + +-- See the note on nix/pkgs/default.nix:agdaPackages for why this is here. +-- (NOTE this will change to ieee754 in newer versions of nixpkgs). extra-packages: ieee, filemanip --- Drops an instance breaking our code. Should be released to Hackage eventually. +-- These packages appear in our dependency tree and are very slow to build. +-- Empirically, turning off optimization shaves off ~50% build time. +-- It also mildly improves recompilation avoidance. +-- For deve work we don't care about performance so much, so this is okay. +package cardano-ledger-alonzo + optimization: False +package ouroboros-consensus-shelley + optimization: False +package ouroboros-consensus-cardano + optimization: False +package cardano-api + optimization: False + +-- https://github.com/Quid2/flat/pull/22 fixes a potential exception +-- when decoding invalid (e.g. malicious) text literals. source-repository-package type: git - location: https://github.com/Quid2/flat.git - tag: 95e5d7488451e43062ca84d5376b3adcc465f1cd + -- location: https://github.com/Quid2/flat.git + location: https://github.com/michaelpj/flat.git + tag: ee59880f47ab835dbd73bea0847dab7869fc20d8 -- Needs some patches, but upstream seems to be fairly dead (no activity in > 1 year) source-repository-package @@ -76,25 +103,22 @@ source-repository-package source-repository-package type: git location: https://github.com/input-output-hk/cardano-crypto.git - tag: ce8f1934e4b6252084710975bd9bbc0a4648ece4 - --- Needs a fix (https://github.com/wenkokke/unlit/pull/11) and a Hackage release -source-repository-package - type: git - location: https://github.com/michaelpj/unlit.git - tag: 9ca1112093c5ffd356fc99c7dafa080e686dd748 + tag: 07397f0e50da97eaa0575d93bee7ac4b2b2576ec source-repository-package type: git location: https://github.com/input-output-hk/cardano-base - tag: a715c7f420770b70bbe95ca51d3dec83866cb1bd + tag: cb0f19c85e5bb5299839ad4ed66af6fa61322cc4 subdir: + base-deriving-via binary binary/test - slotting cardano-crypto-class cardano-crypto-praos cardano-crypto-tests + measures + orphans-deriving-via + slotting strict-containers source-repository-package @@ -108,8 +132,9 @@ source-repository-package source-repository-package type: git location: https://github.com/input-output-hk/ouroboros-network - tag: e50613562d6d4a0f933741fcf590b0f69a1eda67 + tag: 877ce057ff6fb086474c8eaad53f2b7f0e0fce6b subdir: + monoidal-synchronisation typed-protocols typed-protocols-examples ouroboros-network @@ -120,23 +145,27 @@ source-repository-package ouroboros-consensus-cardano ouroboros-consensus-shelley io-sim - io-sim-classes + io-classes network-mux source-repository-package type: git location: https://github.com/input-output-hk/iohk-monitoring-framework - tag: 34abfb7f4f5610cabb45396e0496472446a0b2ca + tag: 808724ff8a19a33d0ed06f9ef59fbd900b08553c subdir: iohk-monitoring tracer-transformers contra-tracer + plugins/backend-aggregation plugins/backend-ekg + plugins/backend-monitoring + plugins/backend-trace-forwarder + plugins/scribe-systemd source-repository-package type: git location: https://github.com/input-output-hk/cardano-ledger-specs - tag: a3ef848542961079b7cd53d599e5385198a3035c + tag: d5b184a820853c7ba202efd615b8fadca1acb52c subdir: byron/chain/executable-spec byron/crypto @@ -159,21 +188,34 @@ source-repository-package source-repository-package type: git location: https://github.com/input-output-hk/cardano-node.git - tag: b3cabae6b3bf30a0b1b4e78bc4b67282dabad0a6 + tag: ed11e8b6429d4af1cb2539460e5cb2283a06b2dc subdir: cardano-api + cardano-node + cardano-cli + cardano-config + +source-repository-package + type: git + location: https://github.com/input-output-hk/optparse-applicative + tag: 7497a29cb998721a9068d5725d49461f2bba0e7a source-repository-package type: git location: https://github.com/input-output-hk/Win32-network - tag: 94153b676617f8f33abe8d8182c37377d2784bd1 + tag: 3825d3abf75f83f406c1f7161883c438dac7277d source-repository-package type: git location: https://github.com/input-output-hk/hedgehog-extras - tag: 8bcd3c9dc22cc44f9fcfe161f4638a384fc7a187 + tag: edf6945007177a638fbeb8802397f3a6f4e47c14 source-repository-package type: git location: https://github.com/input-output-hk/goblins tag: cde90a2b27f79187ca8310b6549331e59595e7ba + +source-repository-package + type: git + location: https://github.com/sordina/servant-options + tag: aa9338b1925e7bc5d65bad35f02aec8c20f8365b diff --git a/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh b/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh index 4b185c343..526cde1c4 100755 --- a/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh +++ b/MetaLamp/lending-pool/client/scripts/fetch-plutus-purs.sh @@ -6,4 +6,4 @@ git remote add origin -f https://github.com/input-output-hk/plutus git config core.sparseCheckout true echo 'web-common-plutus/*' >> .git/info/sparse-checkout echo 'web-common/*' >> .git/info/sparse-checkout -git pull origin bd16cc29045ffc7eaa6beaabe3b985a56cb9292a # plutus-starter-devcontainer/v1.0.6 +git pull origin cc7bc06c4344cee6cd59bc170063fd627da25ed3 # plutus-starter-devcontainer/v1.0.8 diff --git a/MetaLamp/lending-pool/nix/pkgs/default.nix b/MetaLamp/lending-pool/nix/pkgs/default.nix index 98ffcd0e2..b1b740d11 100644 --- a/MetaLamp/lending-pool/nix/pkgs/default.nix +++ b/MetaLamp/lending-pool/nix/pkgs/default.nix @@ -11,6 +11,7 @@ let haskell = pkgs.callPackage ./haskell { inherit gitignore-nix sources haskell-nix; inherit compiler-nix-name; # Use the same GHC version as plutus + inherit (pkgs) libsodium-vrf; }; hlint = plutus.plutus.hlint; @@ -35,8 +36,8 @@ let cardano-repo-tool = plutus.plutus.cardano-repo-tool; in -{ - inherit nodejs purs spago purty fix-purty; - inherit haskell hlint cabal-install stylish-haskell fix-stylish-haskell haskell-language-server; +{ + inherit nodejs purs spago purty fix-purty; + inherit haskell hlint cabal-install stylish-haskell fix-stylish-haskell haskell-language-server; inherit cardano-repo-tool; -} +} \ No newline at end of file diff --git a/MetaLamp/lending-pool/nix/pkgs/haskell/default.nix b/MetaLamp/lending-pool/nix/pkgs/haskell/default.nix index 67036b9d5..5200f878e 100644 --- a/MetaLamp/lending-pool/nix/pkgs/haskell/default.nix +++ b/MetaLamp/lending-pool/nix/pkgs/haskell/default.nix @@ -3,6 +3,7 @@ , gitignore-nix , sources , compiler-nix-name +, libsodium-vrf }: let # The Hackage index-state from cabal.project @@ -21,7 +22,7 @@ let # The haskell project created by haskell-nix.cabalProject' project = import ./haskell.nix { - inherit haskell-nix compiler-nix-name gitignore-nix; + inherit lib haskell-nix compiler-nix-name gitignore-nix libsodium-vrf; }; # All the packages defined by our project, including dependencies @@ -32,4 +33,4 @@ let in rec { inherit project projectPackages packages; -} +} \ No newline at end of file diff --git a/MetaLamp/lending-pool/nix/pkgs/haskell/haskell.nix b/MetaLamp/lending-pool/nix/pkgs/haskell/haskell.nix index 517deaa42..68e51bdc8 100644 --- a/MetaLamp/lending-pool/nix/pkgs/haskell/haskell.nix +++ b/MetaLamp/lending-pool/nix/pkgs/haskell/haskell.nix @@ -4,6 +4,8 @@ { haskell-nix , gitignore-nix , compiler-nix-name +, lib +, libsodium-vrf }: let @@ -17,35 +19,34 @@ let inherit compiler-nix-name; sha256map = { - "https://github.com/Quid2/flat.git"."95e5d7488451e43062ca84d5376b3adcc465f1cd" = "06l31x3y93rjpryvlxnpsyq2zyxvb0z6lik6yq2fvh36i5zwvwa3"; - "https://github.com/input-output-hk/plutus.git"."plutus-starter-devcontainer/v1.0.6" = "1jzbcsdrv0b43dj7bwbd1fbk71f7gph6zzb8y29n9cn3j8illnyc"; + "https://github.com/input-output-hk/plutus.git"."plutus-starter-devcontainer/v1.0.8" = "0fas8kv57lyrsn3larvbfgif48d506w73y7g3g0mxfilfsl5nyfz"; + "https://github.com/michaelpj/flat.git"."ee59880f47ab835dbd73bea0847dab7869fc20d8" = "1lrzknw765pz2j97nvv9ip3l1mcpf2zr4n56hwlz0rk7wq7ls4cm"; "https://github.com/shmish111/purescript-bridge.git"."6a92d7853ea514be8b70bab5e72077bf5a510596" = "13j64vv116in3c204qsl1v0ajphac9fqvsjp7x3zzfr7n7g61drb"; "https://github.com/shmish111/servant-purescript.git"."a76104490499aa72d40c2790d10e9383e0dbde63" = "11nxxmi5bw66va7psvrgrw7b7n85fvqgfp58yva99w3v9q3a50v9"; - "https://github.com/input-output-hk/cardano-crypto.git"."ce8f1934e4b6252084710975bd9bbc0a4648ece4" = "1v2laq04piyj511b2m77hxjh9l1yd6k9kc7g6bjala4w3zdwa4ni"; - "https://github.com/michaelpj/unlit.git"."9ca1112093c5ffd356fc99c7dafa080e686dd748" = "145sffn8gbdn6xp9q5b75yd3m46ql5bnc02arzmpfs6wgjslfhff"; - "https://github.com/input-output-hk/cardano-base"."a715c7f420770b70bbe95ca51d3dec83866cb1bd" = "06l06mmb8cd4q37bnvfpgx1c5zgsl4xaf106dqva98738i8asj7j"; + "https://github.com/input-output-hk/cardano-base"."cb0f19c85e5bb5299839ad4ed66af6fa61322cc4" = "0dnkfqcvbifbk3m5pg8kyjqjy0zj1l4vd23p39n6ym4q0bnib1cq"; + "https://github.com/input-output-hk/cardano-crypto.git"."07397f0e50da97eaa0575d93bee7ac4b2b2576ec" = "06sdx5ndn2g722jhpicmg96vsrys89fl81k8290b3lr6b1b0w4m3"; + "https://github.com/input-output-hk/cardano-ledger-specs"."d5b184a820853c7ba202efd615b8fadca1acb52c" = "04k5p6qwmfdza65gl5319r1ahdfwjnyqgzpfxdx0x2g5jcbimar4"; "https://github.com/input-output-hk/cardano-prelude"."fd773f7a58412131512b9f694ab95653ac430852" = "02jddik1yw0222wd6q0vv10f7y8rdgrlqaiy83ph002f9kjx7mh6"; - "https://github.com/input-output-hk/ouroboros-network"."e50613562d6d4a0f933741fcf590b0f69a1eda67" = "0i192ksa69lpzjhzmhd2h1mramkvvikw04pqws18h5dly55f4z3k"; - "https://github.com/input-output-hk/iohk-monitoring-framework"."34abfb7f4f5610cabb45396e0496472446a0b2ca" = "1fdc0a02ipa385dnwa6r6jyc8jlg537i12hflfglkhjs2b7i92gs"; - "https://github.com/input-output-hk/cardano-ledger-specs"."a3ef848542961079b7cd53d599e5385198a3035c" = "02iwn2lcfcfvrnvcqnx586ncdnma23vdqvicxgr4f39vcacalzpd"; - "https://github.com/input-output-hk/cardano-node.git"."b3cabae6b3bf30a0b1b4e78bc4b67282dabad0a6" = "1csmji1bgi45wgrw7kqy19s4bbbpa78kjg3bz7mbiwb8vjgg9kvq"; - "https://github.com/input-output-hk/Win32-network"."94153b676617f8f33abe8d8182c37377d2784bd1" = "0pb7bg0936fldaa5r08nqbxvi2g8pcy4w3c7kdcg7pdgmimr30ss"; - "https://github.com/input-output-hk/hedgehog-extras"."8bcd3c9dc22cc44f9fcfe161f4638a384fc7a187" = "12viwpahjdfvlqpnzdgjp40nw31rvyznnab1hml9afpaxd6ixh70"; "https://github.com/input-output-hk/goblins"."cde90a2b27f79187ca8310b6549331e59595e7ba" = "17c88rbva3iw82yg9srlxjv2ia5wjb9cyqw44hik565f5v9svnyg"; + "https://github.com/sordina/servant-options"."aa9338b1925e7bc5d65bad35f02aec8c20f8365b" = "0vlp3y414f2i4nhmlp1gh9jns8jydbq1mgv8j7vzh62r506slb1j"; + "https://github.com/input-output-hk/iohk-monitoring-framework"."808724ff8a19a33d0ed06f9ef59fbd900b08553c" = "0298dpl29gxzs9as9ha6y0w18hqwc00ipa3hzkxv7nlfrjjz8hmz"; + "https://github.com/input-output-hk/optparse-applicative"."7497a29cb998721a9068d5725d49461f2bba0e7a" = "1gvsrg925vynwgqwplgjmp53vj953qyh3wbdf34pw21c8r47w35r"; + "https://github.com/input-output-hk/ouroboros-network"."877ce057ff6fb086474c8eaad53f2b7f0e0fce6b" = "1kp0qysfy3hl96a3a61rijascq36f1imh3z4jy0vyiygb6qrv47z"; + "https://github.com/input-output-hk/cardano-node.git"."ed11e8b6429d4af1cb2539460e5cb2283a06b2dc" = "1wvr3zzl37i1fn5y9ni027rqw5bhh25z1bacvcaapxxjgdn38lbq"; + "https://github.com/input-output-hk/Win32-network"."3825d3abf75f83f406c1f7161883c438dac7277d" = "19wahfv726fa3mqajpqdqhnl9ica3xmf68i254q45iyjcpj1psqx"; + "https://github.com/input-output-hk/hedgehog-extras"."edf6945007177a638fbeb8802397f3a6f4e47c14" = "0wc7qzkc7j4ns2rz562h6qrx2f8xyq7yjcb7zidnj7f6j0pcd0i9"; }; modules = [ { packages = { - eventful-sql-common = { - # This is needed so evenful-sql-common will build with a newer version of persistent. - ghcOptions = [ "-XDerivingStrategies -XStandaloneDeriving -XUndecidableInstances -XDataKinds -XFlexibleInstances -XMultiParamTypeClasses" ]; - doHaddock = false; - }; - # Broken due to haddock errors. Refer to https://github.com/input-output-hk/plutus/blob/master/nix/pkgs/haskell/haskell.nix plutus-ledger.doHaddock = false; plutus-use-cases.doHaddock = false; + + # See https://github.com/input-output-hk/iohk-nix/pull/488 + cardano-crypto-praos.components.library.pkgconfig = lib.mkForce [ [ libsodium-vrf ] ]; + cardano-crypto-class.components.library.pkgconfig = lib.mkForce [ [ libsodium-vrf ] ]; }; } ]; diff --git a/MetaLamp/lending-pool/nix/sources.json b/MetaLamp/lending-pool/nix/sources.json index 94979120f..3f326f62d 100644 --- a/MetaLamp/lending-pool/nix/sources.json +++ b/MetaLamp/lending-pool/nix/sources.json @@ -5,10 +5,10 @@ "homepage": "", "owner": "input-output-hk", "repo": "plutus", - "rev": "plutus-starter-devcontainer/v1.0.6", - "sha256": "1jzbcsdrv0b43dj7bwbd1fbk71f7gph6zzb8y29n9cn3j8illnyc", + "rev": "plutus-starter-devcontainer/v1.0.8", + "sha256": "0fas8kv57lyrsn3larvbfgif48d506w73y7g3g0mxfilfsl5nyfz", "type": "tarball", - "url": "https://github.com/input-output-hk/plutus/archive/plutus-starter-devcontainer/v1.0.6.tar.gz", + "url": "https://github.com/input-output-hk/plutus/archive/plutus-starter-devcontainer/v1.0.8.tar.gz", "url_template": "https://github.com///archive/.tar.gz" } } diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 919955258..4b036fca9 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -30,6 +30,7 @@ library bytestring, containers, text, + data-default, freer-simple, freer-extras, prettyprinter, diff --git a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs index 6a699ec23..ed0a79878 100644 --- a/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs +++ b/MetaLamp/lending-pool/src/Ext/Plutus/Ledger/Contexts.hs @@ -38,8 +38,8 @@ findValueByDatumHash dh outs = mconcat $ mapMaybe f outs {-# INLINABLE parseDatum #-} -- | Find datum inside pending transaction and parse it from data -parseDatum :: PlutusTx.IsData a => TxInfo -> DatumHash -> Maybe a -parseDatum txInfo dh = findDatum dh txInfo >>= (PlutusTx.fromData . getDatum) +parseDatum :: (PlutusTx.FromData a, PlutusTx.ToData a) => TxInfo -> DatumHash -> Maybe a +parseDatum txInfo dh = findDatum dh txInfo >>= (PlutusTx.fromBuiltinData . getDatum) {-# INLINABLE valueSpentFrom #-} -- | Concat value of the inputs belonging to the provided public key inside the pending transaction's inputs diff --git a/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs index 28b87b51e..68965e8eb 100644 --- a/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs @@ -9,6 +9,7 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE LambdaCase #-} module Plutus.Abstract.ContractResponse where @@ -70,16 +71,18 @@ withContractResponse :: forall l a p r s. => Proxy l -> (a -> r) -> (p -> Contract (ContractResponse Text r) s Text a) - -> Contract (ContractResponse Text r) s Void () + -> Promise (ContractResponse Text r) s Void () withContractResponse _ g c = do - e <- runError $ do - p <- endpoint @l - _ <- tell ContractPending - errorHandler `handleError` c p - tell $ case e of - Left err -> ContractError err - Right a -> ContractSuccess $ g a - where - errorHandler e = do - logInfo @Text ("Error submiting the transaction: " <> e) - throwError e + handleEndpoint @l $ \case + Left err -> tell $ ContractError err + Right p -> do + _ <- tell ContractPending + e <- runError $ errorHandler `handleError` c p + tell $ case e of + Left err -> ContractError err + Right a -> ContractSuccess $ g a + +errorHandler :: Text -> Contract w s Text b +errorHandler e = do + logInfo @Text ("Error submiting the transaction: " <> e) + throwError e diff --git a/MetaLamp/lending-pool/src/Plutus/Abstract/State/Select.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/State/Select.hs index e85c29670..a1fa57e44 100644 --- a/MetaLamp/lending-pool/src/Plutus/Abstract/State/Select.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/State/Select.hs @@ -31,16 +31,16 @@ import PlutusTx.Prelude hiding (Semigroup (..), import Prelude (Semigroup (..)) import qualified Prelude -getDatum :: PlutusTx.IsData a => TxOutTx -> Contract w s Text a +getDatum :: (PlutusTx.FromData a, PlutusTx.ToData a) => TxOutTx -> Contract w s Text a getDatum o = case txOutDatumHash $ txOutTxOut o of Nothing -> throwError "datumHash not found" Just h -> case Map.lookup h $ txData $ txOutTxTx o of Nothing -> throwError "datum not found" - Just (Datum e) -> case PlutusTx.fromData e of + Just (Datum e) -> case PlutusTx.fromBuiltinData e of Nothing -> throwError "datum has wrong type" Just d -> return d -getState :: (PlutusTx.IsData datum) => Address -> Contract w s Text [OutputValue datum] +getState :: (PlutusTx.FromData datum, PlutusTx.ToData datum) => Address -> Contract w s Text [OutputValue datum] getState address = do utxos <- utxoAt address traverse getDatum' . Map.toList $ utxos @@ -49,7 +49,7 @@ getState address = do d <- getDatum o pure $ OutputValue oref o d -findOutputsBy :: (PlutusTx.IsData datum) => +findOutputsBy :: (PlutusTx.FromData datum, PlutusTx.ToData datum) => Address -> AssetClass -> (datum -> Maybe a) -> @@ -61,7 +61,7 @@ findOutputsBy address stateToken mapDatum = mapMaybe checkStateToken <$> getStat then fmap (OutputValue oref outTx) (mapDatum datum) else Nothing -findOutputBy :: (PlutusTx.IsData datum) => +findOutputBy :: (PlutusTx.FromData datum, PlutusTx.ToData datum) => Address -> AssetClass -> (datum -> Maybe a) -> diff --git a/MetaLamp/lending-pool/src/Plutus/Abstract/State/Update.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/State/Update.hs index 356a047bd..167871efd 100644 --- a/MetaLamp/lending-pool/src/Plutus/Abstract/State/Update.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/State/Update.hs @@ -35,7 +35,7 @@ import Plutus.Abstract.OutputValue (OutputValue (..)) import qualified Plutus.Abstract.TxUtils as TxUtils import Plutus.Contract hiding (when) import Plutus.V1.Ledger.Value -import PlutusTx (IsData) +import PlutusTx (FromData, ToData) import qualified PlutusTx import PlutusTx.Prelude hiding (Semigroup (..), unless) @@ -46,8 +46,8 @@ type OwnerToken = AssetClass -- State token can be only be forged when there is an input and output containing an owner token belonging to a script {-# INLINABLE validateStateForging #-} -validateStateForging :: ValidatorHash -> OwnerToken -> TokenName -> ScriptContext -> Bool -validateStateForging ownerScript ownerToken tokenName ctx = traceIfFalse "State forging not authorized" $ +validateStateForging :: ValidatorHash -> OwnerToken -> TokenName -> BuiltinData -> ScriptContext -> Bool +validateStateForging ownerScript ownerToken tokenName _ ctx = traceIfFalse "State forging not authorized" $ hasOneOwnerToken outputValues && hasOneOwnerToken inputValues && hasOneStateToken forgedValue && hasOneStateToken (mconcat outputValues) where txInfo = scriptContextTxInfo ctx @@ -55,14 +55,14 @@ validateStateForging ownerScript ownerToken tokenName ctx = traceIfFalse "State outputValues = snd <$> scriptOutputsAt ownerScript txInfo inputValues = snd <$> scriptInputsAt ownerScript txInfo - forgedValue = txInfoForge txInfo + forgedValue = txInfoMint txInfo hasOneOwnerToken values = assetClassValueOf (mconcat values) ownerToken == 1 hasOneStateToken value = assetClassValueOf value stateToken == 1 -makeStatePolicy :: ValidatorHash -> OwnerToken -> TokenName -> MonetaryPolicy -makeStatePolicy ownerScript ownerToken tokenName = mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| \os ot tn -> Scripts.wrapMonetaryPolicy $ validateStateForging os ot tn||]) +makeStatePolicy :: ValidatorHash -> OwnerToken -> TokenName -> MintingPolicy +makeStatePolicy ownerScript ownerToken tokenName = mkMintingPolicyScript $ + $$(PlutusTx.compile [|| \os ot tn -> Scripts.wrapMintingPolicy $ validateStateForging os ot tn||]) `PlutusTx.applyCode` PlutusTx.liftCode ownerScript `PlutusTx.applyCode` PlutusTx.liftCode ownerToken `PlutusTx.applyCode` PlutusTx.liftCode tokenName @@ -86,7 +86,8 @@ data StateHandle scriptType a = StateHandle { } putState :: - (IsData (DatumType scriptType), IsData (RedeemerType scriptType)) => + (FromData (DatumType scriptType), ToData (DatumType scriptType), + FromData (RedeemerType scriptType), ToData (RedeemerType scriptType)) => PutStateHandle scriptType -> StateHandle scriptType a -> a -> @@ -105,7 +106,8 @@ putState PutStateHandle {..} StateHandle{..} newState = do (assetClassValue ownerToken 1) updateState :: - (IsData (DatumType scriptType), IsData (RedeemerType scriptType)) => + (FromData (DatumType scriptType), ToData (DatumType scriptType), + FromData (RedeemerType scriptType), ToData (RedeemerType scriptType)) => Scripts.TypedValidator scriptType -> StateHandle scriptType a -> OutputValue a -> diff --git a/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs index 05f55d187..353ff5aae 100644 --- a/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs @@ -20,15 +20,13 @@ import qualified Ledger.Constraints as Constraints import qualified Ledger.Constraints.OnChain as Constraints import qualified Ledger.Constraints.TxConstraints as Constraints import Ledger.Typed.Scripts (DatumType, - MonetaryPolicy, + MintingPolicy, RedeemerType, TypedValidator) import qualified Ledger.Typed.Scripts as Scripts import Plutus.Abstract.OutputValue (OutputValue (..)) import Plutus.Contract import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken -import Plutus.V1.Ledger.Contexts (ScriptContext, - scriptCurrencySymbol) import qualified Plutus.V1.Ledger.Scripts as Scripts import Plutus.V1.Ledger.Value (AssetClass (unAssetClass), TokenName (..), @@ -42,7 +40,9 @@ import qualified Prelude type TxPair a = (Constraints.ScriptLookups a, Constraints.TxConstraints (RedeemerType a) (DatumType a)) -type IsScriptData a = (PlutusTx.IsData (RedeemerType a), PlutusTx.IsData (DatumType a)) +type IsScriptData a = ( + PlutusTx.FromData (RedeemerType a), PlutusTx.ToData (RedeemerType a), + PlutusTx.FromData (DatumType a), PlutusTx.ToData (DatumType a)) submitTxPair :: (AsContractError e, IsScriptData a) => TxPair a @@ -50,13 +50,13 @@ submitTxPair :: (AsContractError e, IsScriptData a) => submitTxPair = Prelude.uncurry submitTxConstraintsWith mustForgeValue :: (IsScriptData a) => - MonetaryPolicy + MintingPolicy -> Value -> TxPair a mustForgeValue policy value = (lookups, tx) where - lookups = Constraints.monetaryPolicy policy - tx = Constraints.mustForgeValue value + lookups = Constraints.mintingPolicy policy + tx = Constraints.mustMintValue value mustPayToScript :: (IsScriptData a) => TypedValidator a @@ -78,7 +78,7 @@ mustSpendScriptOutputs script inputs = (lookups, tx) unspent = Map.fromList $ fmap (\(OutputValue ref tx _) -> (ref, tx)) inputs lookups = Constraints.otherScript (Scripts.validatorScript script) <> Constraints.unspentOutputs unspent tx = Prelude.mconcat $ - fmap (\(OutputValue ref _ redeemer) -> Constraints.mustSpendScriptOutput ref (Redeemer $ PlutusTx.toData redeemer)) inputs + fmap (\(OutputValue ref _ redeemer) -> Constraints.mustSpendScriptOutput ref (Redeemer $ PlutusTx.toBuiltinData redeemer)) inputs mustSpendFromScript :: (IsScriptData a) => TypedValidator a diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs index ac1c5c356..7b7a848ab 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs @@ -20,7 +20,7 @@ import Ledger hiding (singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints import Ledger.Constraints.TxConstraints as Constraints -import Ledger.Typed.Scripts (MonetaryPolicy) +import Ledger.Typed.Scripts (MintingPolicy) import qualified Ledger.Typed.Scripts as Scripts import Plutus.Abstract.OutputValue (OutputValue (..)) import qualified Plutus.Abstract.TxUtils as TxUtils @@ -30,8 +30,9 @@ import Plutus.Contracts.LendingPool.OnChain.Core (Aave, AaveScript, Reserve (..)) import qualified Plutus.Contracts.LendingPool.OnChain.Core as Core import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken -import Plutus.V1.Ledger.Contexts (ScriptContext, - scriptCurrencySymbol) +import Plutus.V1.Ledger.Contexts (ScriptContext) +import Ledger.Contexts (scriptCurrencySymbol) + import qualified Plutus.V1.Ledger.Scripts as Scripts import Plutus.V1.Ledger.Value (AssetClass (..), TokenName (..), diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs index 7171142fb..2d1b01232 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs @@ -89,9 +89,9 @@ data InfoContractState = | Users (AssocMap.Map (AssetClass, PubKeyHash) UserConfig) deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) -infoEndpoints :: Aave -> Contract (ContractResponse Text InfoContractState) AaveInfoSchema Void () -infoEndpoints aave = forever $ - withContractResponse (Proxy @"fundsAt") FundsAt fundsAt +infoEndpoints :: Aave -> Promise (ContractResponse Text InfoContractState) AaveInfoSchema Void () +infoEndpoints aave = + (withContractResponse (Proxy @"fundsAt") FundsAt fundsAt `select` withContractResponse (Proxy @"poolFunds") PoolFunds (const $ poolFunds aave) `select` withContractResponse (Proxy @"reserves") Reserves (const $ reserves aave) - `select` withContractResponse (Proxy @"users") Users (const $ users aave) + `select` withContractResponse (Proxy @"users") Users (const $ users aave)) <> infoEndpoints aave diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Owner.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Owner.hs index 7a8dc406d..deccc0a37 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Owner.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Owner.hs @@ -93,7 +93,7 @@ start = start' $ do pkh <- pubKeyHash <$> ownPubKey fmap Currency.currencySymbol $ mapError (pack . show @Currency.CurrencyError) $ - Currency.forgeContract pkh [(Core.aaveProtocolName, 1)] + Currency.mintContract pkh [(Core.aaveProtocolName, 1)] start' :: Contract w s Text CurrencySymbol -> [CreateParams] -> Contract w s Text Aave start' getAaveToken params = do @@ -123,5 +123,5 @@ type AaveOwnerSchema = data OwnerContractState = Started Aave deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) -ownerEndpoints :: Contract (ContractResponse Text OwnerContractState) AaveOwnerSchema Void () -ownerEndpoints = forever $ withContractResponse (Proxy @"start") Started start +ownerEndpoints :: Promise (ContractResponse Text OwnerContractState) AaveOwnerSchema Void () +ownerEndpoints = withContractResponse (Proxy @"start") Started start <> ownerEndpoints diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs index 7bd81b162..7845efda2 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs @@ -332,7 +332,7 @@ revokeCollateral aave RevokeCollateralParams {..} = do userDatum = Core.UserCollateralFundsDatum rcpOnBehalfOf getUsersCollateral :: AssetClass -> TxOutTx -> Bool getUsersCollateral asset tx = ((> 0) . flip assetClassValueOf asset . txOutValue . txOutTxOut $ tx) && - (txOutDatumHash . txOutTxOut $ tx) == Just (datumHash . Datum . PlutusTx.toData $ userDatum asset) + (txOutDatumHash . txOutTxOut $ tx) == Just (datumHash . Datum . PlutusTx.toBuiltinData $ userDatum asset) getOwnPubKey :: Contract w s Text PubKeyHash getOwnPubKey = pubKeyHash <$> ownPubKey @@ -364,13 +364,13 @@ data UserContractState = Lens.makeClassyPrisms ''UserContractState -- TODO ? add repayWithCollateral -userEndpoints :: Aave -> Contract (ContractResponse Text UserContractState) AaveUserSchema Void () -userEndpoints aave = forever $ - withContractResponse (Proxy @"deposit") (const Deposited) (deposit aave) +userEndpoints :: Aave -> Promise (ContractResponse Text UserContractState) AaveUserSchema Void () +userEndpoints aave = + (withContractResponse (Proxy @"deposit") (const Deposited) (deposit aave) `select` withContractResponse (Proxy @"withdraw") (const Withdrawn) (withdraw aave) `select` withContractResponse (Proxy @"borrow") (const Borrowed) (borrow aave) `select` withContractResponse (Proxy @"repay") (const Repaid) (repay aave) `select` withContractResponse (Proxy @"provideCollateral") (const CollateralProvided) (provideCollateral aave) `select` withContractResponse (Proxy @"revokeCollateral") (const CollateralRevoked) (revokeCollateral aave) `select` withContractResponse (Proxy @"ownPubKey") GetPubKey (const getOwnPubKey) - `select` withContractResponse (Proxy @"ownPubKeyBalance") GetPubKeyBalance (const ownPubKeyBalance) + `select` withContractResponse (Proxy @"ownPubKeyBalance") GetPubKeyBalance (const ownPubKeyBalance)) <> userEndpoints aave diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/AToken.hs index 16f883817..0482bf4d2 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/AToken.hs @@ -28,7 +28,7 @@ import Ledger hiding (singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints import Ledger.Constraints.TxConstraints as Constraints -import Ledger.Typed.Scripts (MonetaryPolicy) +import Ledger.Typed.Scripts (MintingPolicy) import qualified Ledger.Typed.Scripts as Scripts import Plutus.Abstract.OutputValue (OutputValue (..)) import qualified Plutus.Abstract.TxUtils as TxUtils @@ -37,8 +37,8 @@ import Plutus.Contracts.LendingPool.OnChain.Core (Aave, AaveScript, Reserve (..)) import qualified Plutus.Contracts.LendingPool.OnChain.Core as Core import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken -import Plutus.V1.Ledger.Contexts (ScriptContext, - scriptCurrencySymbol) +import Plutus.V1.Ledger.Contexts (ScriptContext) +import Ledger.Contexts (scriptCurrencySymbol) import qualified Plutus.V1.Ledger.Scripts as Scripts import Plutus.V1.Ledger.Value (AssetClass (..), TokenName (..), @@ -53,8 +53,8 @@ import Prelude (Semigroup (..)) import qualified Prelude {-# INLINABLE validator #-} -validator :: ValidatorHash -> AssetClass -> TokenName -> ScriptContext -> Bool -validator aaveScript underlyingAsset aTokenName ctx = +validator :: ValidatorHash -> AssetClass -> TokenName -> BuiltinData -> ScriptContext -> Bool +validator aaveScript underlyingAsset aTokenName _ ctx = traceIfFalse "Aave tokens mint forbidden" $ amountMinted /= 0 && amountScriptAsset == amountMinted where txInfo :: TxInfo @@ -65,7 +65,7 @@ validator aaveScript underlyingAsset aTokenName ctx = amountAsset = flip assetClassValueOf underlyingAsset amountMinted :: Integer - amountMinted = assetClassValueOf (txInfoForge txInfo) aTokenCurrency + amountMinted = assetClassValueOf (txInfoMint txInfo) aTokenCurrency amountScriptAsset :: Integer amountScriptAsset = @@ -73,9 +73,9 @@ validator aaveScript underlyingAsset aTokenName ctx = inputValue = foldMap snd $ scriptInputsAt aaveScript txInfo in amountAsset outputValue - amountAsset inputValue -makeLiquidityPolicy :: ValidatorHash -> AssetClass -> MonetaryPolicy -makeLiquidityPolicy aaveScript asset = Scripts.mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| \s a t -> Scripts.wrapMonetaryPolicy $ validator s a t||]) +makeLiquidityPolicy :: ValidatorHash -> AssetClass -> MintingPolicy +makeLiquidityPolicy aaveScript asset = Scripts.mkMintingPolicyScript $ + $$(PlutusTx.compile [|| \s a t -> Scripts.wrapMintingPolicy $ validator s a t||]) `PlutusTx.applyCode` PlutusTx.liftCode aaveScript `PlutusTx.applyCode` diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs index 895c5e09c..5c9df5ec1 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/Core/Logic.hs @@ -147,7 +147,7 @@ checkNegativeReservesTransformation stateToken reserves ctx (reserveId, _) = reservesOutputDatum = reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves - remainderDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo + remainderDatumHash = findDatumHash (Datum $ PlutusTx.toBuiltinData ReserveFundsDatum) txInfo remainderValue = (`findValueByDatumHash` scriptOutputs) <$> remainderDatumHash checkreserves :: (AssetClass, AssocMap.Map AssetClass Reserve) -> Bool @@ -181,7 +181,7 @@ checkPositiveReservesTransformation stateToken reserves ctx (reserveId, _) = may reservesOutputDatum = reservesOutputDatumHash >>= parseDatum txInfo >>= pickReserves - investmentDatumHash = findDatumHash (Datum $ PlutusTx.toData ReserveFundsDatum) txInfo + investmentDatumHash = findDatumHash (Datum $ PlutusTx.toBuiltinData ReserveFundsDatum) txInfo investmentValue = (`findValueByDatumHash` scriptOutputs) <$> investmentDatumHash checkreserves :: (AssetClass, AssocMap.Map AssetClass Reserve) -> Bool diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Service/FungibleToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/FungibleToken.hs index 4acdc6663..8f3071f4c 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Service/FungibleToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/FungibleToken.hs @@ -4,7 +4,7 @@ module Plutus.Contracts.Service.FungibleToken where -import Ledger.Typed.Scripts (MonetaryPolicy) +import Ledger.Typed.Scripts (MintingPolicy) import qualified Ledger.Typed.Scripts as Scripts import Plutus.V1.Ledger.Contexts (ScriptContext) import qualified Plutus.V1.Ledger.Scripts as Scripts @@ -13,11 +13,11 @@ import qualified PlutusTx import PlutusTx.Prelude {-# INLINABLE validator #-} -validator :: TokenName -> ScriptContext -> Bool -validator _ _ = True +validator :: TokenName -> BuiltinData -> ScriptContext -> Bool +validator _ _ _ = True -makeLiquidityPolicy :: TokenName -> MonetaryPolicy -makeLiquidityPolicy tokenName = Scripts.mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| Scripts.wrapMonetaryPolicy . validator ||]) +makeLiquidityPolicy :: TokenName -> MintingPolicy +makeLiquidityPolicy tokenName = Scripts.mkMintingPolicyScript $ + $$(PlutusTx.compile [|| Scripts.wrapMintingPolicy . validator ||]) `PlutusTx.applyCode` PlutusTx.liftCode tokenName diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs index 35026434f..96558c385 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs @@ -100,7 +100,7 @@ oracleValue :: TxOut -> (DatumHash -> Maybe Datum) -> Maybe Integer oracleValue o f = do dh <- txOutDatum o Datum d <- f dh - PlutusTx.fromData d + PlutusTx.fromBuiltinData d {-# INLINABLE findOracleValueInTxInputs #-} findOracleValueInTxInputs :: TxInfo -> (CurrencySymbol, PubKeyHash, Integer, AssetClass) -> Maybe Integer @@ -184,7 +184,7 @@ data OracleParams = OracleParams startOracle :: forall w s. OracleParams -> Contract w s Text Oracle startOracle op = do pkh <- pubKeyHash <$> Contract.ownPubKey - osc <- mapError (pack . Prelude.show) (forgeContract pkh [(oracleTokenName, 1)] :: Contract w s CurrencyError OneShotCurrency) + osc <- mapError (pack . Prelude.show) (mintContract pkh [(oracleTokenName, 1)] :: Contract w s CurrencyError OneShotCurrency) let cs = Currency.currencySymbol osc oracle = Oracle { oSymbol = cs @@ -208,7 +208,7 @@ updateOracle oracle x = do let lookups = Constraints.unspentOutputs (Map.singleton oref o) <> Constraints.typedValidatorLookups (oracleInst oracle) <> Constraints.otherScript (oracleValidator oracle) - tx = c <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toData Update) + tx = c <> Constraints.mustSpendScriptOutput oref (Redeemer $ PlutusTx.toBuiltinData Update) ledgerTx <- submitTxConstraintsWith @Oracling lookups tx awaitTxConfirmed $ txId ledgerTx logInfo @Prelude.String $ "updated oracle value to " ++ Prelude.show x @@ -238,8 +238,8 @@ useOracle (fromTuple -> oracle) = do Constraints.otherScript (oracleValidator oracle) <> Constraints.unspentOutputs unspent let val = (assetClassValue oracleCoin 1) <> lovelaceValueOf (oFee oracle) - let tx = Constraints.mustSpendScriptOutput oracleRef (Redeemer $ PlutusTx.toData Use) <> - Constraints.mustPayToOtherScript (validatorHash $ oracleValidator oracle) (Datum $ PlutusTx.toData oracleDatum) val + let tx = Constraints.mustSpendScriptOutput oracleRef (Redeemer $ PlutusTx.toBuiltinData Use) <> + Constraints.mustPayToOtherScript (validatorHash $ oracleValidator oracle) (Datum $ PlutusTx.toBuiltinData oracleDatum) val pure $ (lookups, tx) where oracleCoin = oracleAsset oracle @@ -253,7 +253,8 @@ runOracle op = do go oracle where go :: Oracle -> Contract (Last Oracle) OracleSchema Text a - go oracle = do - x <- endpoint @"update" - updateOracle oracle x - go oracle + go oracle = + awaitPromise $ endpoint @"update" $ \x -> do + updateOracle oracle x + go oracle + \ No newline at end of file diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 868619e75..60ade2678 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -62,13 +62,13 @@ import Plutus.PAB.Simulator (Simulation, import qualified Plutus.PAB.Simulator as Simulator import Plutus.PAB.Types (PABError (..)) import qualified Plutus.PAB.Webserver.Server as PAB.Server -import Plutus.V1.Ledger.Crypto (getPubKeyHash, - pubKeyHash) +import Plutus.V1.Ledger.Crypto (getPubKeyHash) +import Ledger.Crypto (pubKeyHash) import Prelude hiding (init) import Wallet.Emulator.Types (Wallet (..), walletPubKey) import Wallet.Types (ContractInstanceId) - +import Data.Default (Default (def)) ownerWallet :: Wallet ownerWallet = Wallet 1 @@ -90,12 +90,12 @@ distributeFunds wallets assets = do ownPK <- pubKeyHash <$> ownPubKey let testCurrenciesValue = mconcat $ fmap (`assetClassValue` 1000) assets policyLookups = mconcat $ - fmap (Constraints.monetaryPolicy . FungibleToken.makeLiquidityPolicy . Prelude.snd . unAssetClass) assets + fmap (Constraints.mintingPolicy . FungibleToken.makeLiquidityPolicy . Prelude.snd . unAssetClass) assets adaValue = lovelaceValueOf amount forM_ wallets $ \w -> do let pkh = pubKeyHash $ walletPubKey w lookups = policyLookups - tx = mustForgeValue testCurrenciesValue <> mustPayToPubKey pkh (adaValue <> testCurrenciesValue) + tx = mustMintValue testCurrenciesValue <> mustPayToPubKey pkh (adaValue <> testCurrenciesValue) when (pkh /= ownPK) $ do ledgerTx <- submitTxConstraintsWith @Scripts.Any lookups tx void $ awaitTxConfirmed $ txId ledgerTx @@ -265,30 +265,25 @@ data AaveContracts = instance Pretty AaveContracts where pretty = viaShow -handleAaveContract :: - ( Member (Error PABError) effs - , Member (LogMsg (PABMultiAgentMsg (Builtin AaveContracts))) effs - ) - => ContractEffect (Builtin AaveContracts) - ~> Eff effs -handleAaveContract = Builtin.handleBuiltin getSchema getContract where - getSchema = \case - AaveUser _ -> Builtin.endpointsToSchemas @Aave.AaveUserSchema - AaveInfo _ -> Builtin.endpointsToSchemas @Aave.AaveInfoSchema - AaveStart -> Builtin.endpointsToSchemas @Aave.AaveOwnerSchema - DistributeFunds _ _ -> Builtin.endpointsToSchemas @Empty - CreateOracles _ -> Builtin.endpointsToSchemas @Empty - getContract = \case - AaveInfo aave -> SomeBuiltin $ Aave.infoEndpoints aave - AaveUser aave -> SomeBuiltin $ Aave.userEndpoints aave - AaveStart -> SomeBuiltin Aave.ownerEndpoints - DistributeFunds wallets assets -> SomeBuiltin $ distributeFunds wallets assets - CreateOracles assets -> SomeBuiltin $ createOracles assets +instance Builtin.HasDefinitions AaveContracts where + getDefinitions = [AaveStart] -- TODO: not sure about contract definitions + getSchema = \case + AaveUser _ -> Builtin.endpointsToSchemas @Aave.AaveUserSchema + AaveInfo _ -> Builtin.endpointsToSchemas @Aave.AaveInfoSchema + AaveStart -> Builtin.endpointsToSchemas @Aave.AaveOwnerSchema + DistributeFunds _ _ -> Builtin.endpointsToSchemas @Empty + CreateOracles _ -> Builtin.endpointsToSchemas @Empty + getContract = \case + AaveInfo aave -> SomeBuiltin $ Aave.infoEndpoints aave + AaveUser aave -> SomeBuiltin $ Aave.userEndpoints aave + AaveStart -> SomeBuiltin Aave.ownerEndpoints + DistributeFunds wallets assets -> SomeBuiltin $ distributeFunds wallets assets + CreateOracles assets -> SomeBuiltin $ createOracles assets handlers :: SimulatorEffectHandlers (Builtin AaveContracts) handlers = - Simulator.mkSimulatorHandlers @(Builtin AaveContracts) [] - $ interpret handleAaveContract + Simulator.mkSimulatorHandlers def def + $ interpret (Builtin.contractHandler (Builtin.handleBuiltin @AaveContracts)) oneAdaInLovelace :: Integer oneAdaInLovelace = 1000000 diff --git a/MetaLamp/lending-pool/test/Fixtures/Init.hs b/MetaLamp/lending-pool/test/Fixtures/Init.hs index 7b66213a1..68f0a0bc8 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Init.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Init.hs @@ -56,7 +56,7 @@ startContract :: Contract () Aave.AaveOwnerSchema Text () startContract = void $ AaveMock.start startParams userContract :: Contract (ContractResponse Text Aave.UserContractState) Aave.AaveUserSchema Void () -userContract = void $ Aave.userEndpoints AaveMock.aave +userContract = void $ awaitPromise $ Aave.userEndpoints AaveMock.aave distributeTrace :: Trace.EmulatorTrace () distributeTrace = do diff --git a/MetaLamp/lending-pool/test/Fixtures/Symbol.hs b/MetaLamp/lending-pool/test/Fixtures/Symbol.hs index f6737d7fc..246ba5fac 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Symbol.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Symbol.hs @@ -11,7 +11,7 @@ import Data.Text (Text) import Data.Void (Void) import qualified Ledger import qualified Ledger.Constraints as Constraints -import Ledger.Typed.Scripts (MonetaryPolicy) +import Ledger.Typed.Scripts (MintingPolicy) import qualified Ledger.Typed.Scripts as Scripts import qualified Plutus.Abstract.TxUtils as TxUtils import Plutus.Contract @@ -22,12 +22,12 @@ import Plutus.V1.Ledger.Value (CurrencySymbol, TokenName, import qualified PlutusTx {-# INLINABLE validator #-} -validator :: TokenName -> ScriptContext -> Bool -validator _ _ = True +validator :: TokenName -> PlutusTx.BuiltinData -> ScriptContext -> Bool +validator _ _ _ = True -makePolicy :: TokenName -> MonetaryPolicy -makePolicy tokenName = Scripts.mkMonetaryPolicyScript $ - $$(PlutusTx.compile [|| Scripts.wrapMonetaryPolicy . validator ||]) +makePolicy :: TokenName -> MintingPolicy +makePolicy tokenName = Scripts.mkMintingPolicyScript $ + $$(PlutusTx.compile [|| Scripts.wrapMintingPolicy . validator ||]) `PlutusTx.applyCode` PlutusTx.liftCode tokenName diff --git a/MetaLamp/lending-pool/test/Spec/Shared.hs b/MetaLamp/lending-pool/test/Spec/Shared.hs index 5de4c67ec..2b12a3c09 100644 --- a/MetaLamp/lending-pool/test/Spec/Shared.hs +++ b/MetaLamp/lending-pool/test/Spec/Shared.hs @@ -5,7 +5,6 @@ module Spec.Shared where import qualified Fixtures import Plutus.Contract.Test (TracePredicate) import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave -import Plutus.V1.Ledger.Crypto (PubKeyHash) import Plutus.V1.Ledger.Value (AssetClass) import qualified PlutusTx.AssocMap as AssocMap import qualified Utils.Data as Utils diff --git a/MetaLamp/lending-pool/test/Utils/Data.hs b/MetaLamp/lending-pool/test/Utils/Data.hs index 71c620c55..d174c7187 100644 --- a/MetaLamp/lending-pool/test/Utils/Data.hs +++ b/MetaLamp/lending-pool/test/Utils/Data.hs @@ -2,7 +2,8 @@ module Utils.Data where import Data.Function ((&)) import Plutus.Abstract.ContractResponse (ContractResponse (..)) -import Plutus.V1.Ledger.Crypto (PubKeyHash, pubKeyHash) +import Plutus.V1.Ledger.Crypto (PubKeyHash) +import Ledger.Crypto (pubKeyHash) import qualified PlutusTx.AssocMap as AssocMap import qualified PlutusTx.Prelude as PlutusTx import Wallet.Emulator.Wallet (Wallet, walletPubKey) diff --git a/MetaLamp/lending-pool/test/Utils/Trace.hs b/MetaLamp/lending-pool/test/Utils/Trace.hs index e7de24026..3efc68edb 100644 --- a/MetaLamp/lending-pool/test/Utils/Trace.hs +++ b/MetaLamp/lending-pool/test/Utils/Trace.hs @@ -23,7 +23,7 @@ import Plutus.Abstract.ContractResponse (ContractResponse (..)) import Plutus.Contract.Test (TracePredicate) import qualified Plutus.Trace.Emulator as Trace import Plutus.Trace.Emulator.Types (EmulatorRuntimeError (..)) -import PlutusTx (IsData, fromData) +import PlutusTx (FromData, fromBuiltinData) import qualified Wallet.Emulator.Folds as Folds import Wallet.Emulator.MultiAgent (EmulatorEvent) @@ -50,18 +50,18 @@ getState pick userHandle = do utxoAtAddress :: Monad m => Address -> (UtxoMap -> m c)-> L.FoldM m EmulatorEvent c utxoAtAddress address check = Folds.postMapM check (L.generalize $ Folds.utxoAtAddress address) -datumsAtAddress :: (IsData a, Show a) => Address -> ([a] -> Bool) -> TracePredicate +datumsAtAddress :: (FromData a, Show a) => Address -> ([a] -> Bool) -> TracePredicate datumsAtAddress address check = utxoAtAddress address $ \utxo -> do let datums = getDatums utxo result = check datums unless result $ tell @(Doc Void) (fromString $ "Datum check failed: " <> show datums) pure result -getDatums :: IsData a => UtxoMap -> [a] +getDatums :: (FromData a) => UtxoMap -> [a] getDatums = mapMaybe findDatum . Map.elems -findDatum :: PlutusTx.IsData a => Ledger.TxOutTx -> Maybe a +findDatum :: (PlutusTx.FromData a) => Ledger.TxOutTx -> Maybe a findDatum o = do hash <- Ledger.txOutDatumHash $ Ledger.txOutTxOut o (Ledger.Datum e) <- Map.lookup hash $ Ledger.txData $ Ledger.txOutTxTx o - PlutusTx.fromData e + PlutusTx.fromBuiltinData e From f5f99f4067ae977b75ecba35e19c1216d1d077c7 Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Wed, 15 Sep 2021 11:02:01 +0700 Subject: [PATCH 165/169] update client --- MetaLamp/lending-pool/README.md | 2 +- MetaLamp/lending-pool/client/README.md | 5 -- .../client/scripts/start-chrome.sh | 1 - MetaLamp/lending-pool/client/spago.dhall | 4 ++ MetaLamp/lending-pool/client/src/AppAff.purs | 6 +- .../client/src/Business/Aave.purs | 2 +- MetaLamp/lending-pool/client/src/Main.purs | 2 +- .../lending-pool/generate-purs/AaveTypes.hs | 2 - MetaLamp/lending-pool/generate-purs/Main.hs | 33 +--------- MetaLamp/lending-pool/plutus-starter.cabal | 39 +++++++++--- .../src/Ext/Plutus/PAB/Webserver/Server.hs | 60 +++++++++++++++++++ .../lending-pool/src/Plutus/PAB/Simulation.hs | 8 ++- 12 files changed, 108 insertions(+), 56 deletions(-) delete mode 100755 MetaLamp/lending-pool/client/scripts/start-chrome.sh create mode 100644 MetaLamp/lending-pool/src/Ext/Plutus/PAB/Webserver/Server.hs diff --git a/MetaLamp/lending-pool/README.md b/MetaLamp/lending-pool/README.md index 3d3d6db7e..34c6fe6b3 100644 --- a/MetaLamp/lending-pool/README.md +++ b/MetaLamp/lending-pool/README.md @@ -32,7 +32,7 @@ cabal build all cabal run pab ``` -This will then start up the server on port 8080. +This will then start up the server on port 9080. 4. To run test simulation do: diff --git a/MetaLamp/lending-pool/client/README.md b/MetaLamp/lending-pool/client/README.md index 4a9bbdb90..aff6ecbef 100644 --- a/MetaLamp/lending-pool/client/README.md +++ b/MetaLamp/lending-pool/client/README.md @@ -33,11 +33,6 @@ npm start ``` 5. Open browser to interact with the app at https://localhost:8009/. -CORS protection needs to be disabled. You can use this script to launch chromium (note that first you need to close chromium completely, otherwise security won't be disabled): - -``` -npm run start-chrome -``` ## Troubleshooting diff --git a/MetaLamp/lending-pool/client/scripts/start-chrome.sh b/MetaLamp/lending-pool/client/scripts/start-chrome.sh deleted file mode 100755 index 776df5378..000000000 --- a/MetaLamp/lending-pool/client/scripts/start-chrome.sh +++ /dev/null @@ -1 +0,0 @@ -chromium --disable-web-security --user-data-dir=/chrome-temp \ No newline at end of file diff --git a/MetaLamp/lending-pool/client/spago.dhall b/MetaLamp/lending-pool/client/spago.dhall index e7b989c66..aedb337cc 100644 --- a/MetaLamp/lending-pool/client/spago.dhall +++ b/MetaLamp/lending-pool/client/spago.dhall @@ -6,6 +6,7 @@ You can edit this file as you like. , dependencies = [ "aff" , "affjax" + , "aff-promise" , "argonaut-codecs" , "avar" , "bigints" @@ -27,6 +28,9 @@ You can edit this file as you like. , "undefinable" , "uuid" , "web-socket" + , "routing" + , "routing-duplex" + , "halogen-formless" ] , packages = ./packages.dhall , sources = diff --git a/MetaLamp/lending-pool/client/src/AppAff.purs b/MetaLamp/lending-pool/client/src/AppAff.purs index ed0fba455..5267ffe16 100644 --- a/MetaLamp/lending-pool/client/src/AppAff.purs +++ b/MetaLamp/lending-pool/client/src/AppAff.purs @@ -81,9 +81,9 @@ post path body = do runAjax $ ajax decode affReq instance contractAppM :: Contract AppM where - getContracts = get "/api/new/contract/instances" - getContractStatus (ContractId cid) = get $ "/api/new/contract/instance/" <> cid <> "/status" - callEndpoint (Endpoint endpoint) (ContractId cid) params = post ("/api/new/contract/instance/" <> cid <> "/endpoint/" <> endpoint) (string <<< encodeJSON $ params) + getContracts = get "/api/contract/instances" + getContractStatus (ContractId cid) = get $ "/api/contract/instance/" <> cid <> "/status" + callEndpoint (Endpoint endpoint) (ContractId cid) params = post ("/api/contract/instance/" <> cid <> "/endpoint/" <> endpoint) (string <<< encodeJSON $ params) instance pollContractAppM :: PollContract AppM where pollDelay = liftAff <<< delay <<< Milliseconds $ 1000.0 diff --git a/MetaLamp/lending-pool/client/src/Business/Aave.purs b/MetaLamp/lending-pool/client/src/Business/Aave.purs index 8b4c56cec..838052c90 100644 --- a/MetaLamp/lending-pool/client/src/Business/Aave.purs +++ b/MetaLamp/lending-pool/client/src/Business/Aave.purs @@ -48,7 +48,7 @@ getAaveResponseWith endpoint pick cid param = pollEndpoint getNext endpoint para (preview pick state) getAaveContractId :: forall a. Prism' AaveContracts a -> ContractInstanceClientState AaveContracts -> Maybe ContractId -getAaveContractId pick (ContractInstanceClientState { cicContract, cicDefintion }) = (const $ toContractIdParam cicContract) <$> (preview pick cicDefintion) +getAaveContractId pick (ContractInstanceClientState st) = (const $ toContractIdParam st.cicContract) <$> (preview pick st.cicDefinition) toContractIdParam :: ContractInstanceId -> ContractId toContractIdParam (ContractInstanceId { unContractInstanceId: JsonUUID uuid }) = ContractId <<< UUID.toString $ uuid diff --git a/MetaLamp/lending-pool/client/src/Main.purs b/MetaLamp/lending-pool/client/src/Main.purs index 1b3ce2ac2..4f6ce16ff 100644 --- a/MetaLamp/lending-pool/client/src/Main.purs +++ b/MetaLamp/lending-pool/client/src/Main.purs @@ -13,7 +13,7 @@ main :: Effect Unit main = runHalogenAff do let - rootComponent = H.hoist (runAppM { host: "localhost", port: 8080 }) App.component + rootComponent = H.hoist (runAppM { host: "localhost", port: 9080 }) App.component body <- awaitBody runUI rootComponent unit body diff --git a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs index 47cc56afd..140384ec9 100644 --- a/MetaLamp/lending-pool/generate-purs/AaveTypes.hs +++ b/MetaLamp/lending-pool/generate-purs/AaveTypes.hs @@ -37,7 +37,6 @@ import qualified Plutus.Contracts.LendingPool.OffChain.User as Aave import qualified Plutus.Contracts.LendingPool.OnChain.Core as Aave import qualified Plutus.Contracts.Service.Oracle as Oracle import Plutus.PAB.Simulation (AaveContracts (..)) -import Plutus.V1.Ledger.Value (AssetClass) ratioBridge :: BridgePart ratioBridge = do @@ -56,7 +55,6 @@ aaveTypes = [ (equal <*> (genericShow <*> mkSumType)) (Proxy @AaveContracts) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Oracle.Oracle) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractResponse E A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.CreateParams) - , (order <*> (equal <*> (genericShow <*> mkSumType))) (Proxy @AssetClass) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.UserContractState) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.InfoContractState) , (equal <*> (genericShow <*> mkSumType)) (Proxy @Aave.Reserve) diff --git a/MetaLamp/lending-pool/generate-purs/Main.hs b/MetaLamp/lending-pool/generate-purs/Main.hs index 276c0e45f..cbe20e2be 100644 --- a/MetaLamp/lending-pool/generate-purs/Main.hs +++ b/MetaLamp/lending-pool/generate-purs/Main.hs @@ -13,12 +13,6 @@ module Main where import AaveTypes (aaveTypes, ratioBridge) -import Cardano.Metadata.Types (AnnotatedSignature, - HashFunction, - Property, - PropertyKey, - Subject, - SubjectProperties) import Cardano.Wallet.Types (WalletInfo) import Control.Applicative ((<|>)) import Control.Lens (set, view, (&)) @@ -47,9 +41,7 @@ import qualified PSGenerator.Common import Plutus.Contract.Checkpoint (CheckpointKey, CheckpointStore, CheckpointStoreItem) -import Plutus.Contract.Effects (TxConfirmed) import Plutus.Contract.Resumable (Responses) -import Plutus.PAB.Effects.Contract.ContractExe (ContractExe) import Plutus.PAB.Events.ContractInstanceState (PartiallyDecodedResponse) import qualified Plutus.PAB.Webserver.API as API import Plutus.PAB.Webserver.Types (ChainReport, @@ -85,21 +77,8 @@ myBridge = PSGenerator.Common.servantBridge <|> PSGenerator.Common.miscBridge <|> ratioBridge <|> - metadataBridge <|> defaultBridge --- Some of the metadata types have a datakind type parameter that --- PureScript won't support, so we must drop it. -metadataBridge :: BridgePart -metadataBridge = do - (typeName ^== "Property") - <|> (typeName ^== "SubjectProperties") - <|> (typeName ^== "AnnotatedSignature") - typeModule ^== "Cardano.Metadata.Types" - moduleName <- view (haskType . typeModule) - name <- view (haskType . typeName) - pure $ TypeInfo "plutus-pab" moduleName name [] - data MyBridge myBridgeProxy :: Proxy MyBridge @@ -114,8 +93,7 @@ myTypes = PSGenerator.Common.ledgerTypes <> PSGenerator.Common.playgroundTypes <> PSGenerator.Common.walletTypes <> - [ (equal <*> (genericShow <*> mkSumType)) (Proxy @ContractExe) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @(FullReport A)) + [ (equal <*> (genericShow <*> mkSumType)) (Proxy @(FullReport A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @ChainReport) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractReport A)) , (equal <*> (genericShow <*> mkSumType)) @@ -123,7 +101,6 @@ myTypes = , (equal <*> (genericShow <*> mkSumType)) (Proxy @(PartiallyDecodedResponse A)) -- Contract request / response types - , (equal <*> (genericShow <*> mkSumType)) (Proxy @TxConfirmed) , (equal <*> (genericShow <*> mkSumType)) (Proxy @CheckpointStore) , (order <*> (genericShow <*> mkSumType)) (Proxy @CheckpointKey) , (equal <*> (genericShow <*> mkSumType)) (Proxy @(CheckpointStoreItem A)) @@ -133,14 +110,6 @@ myTypes = , (equal <*> (genericShow <*> mkSumType)) (Proxy @(LogMessage A)) , (equal <*> (genericShow <*> mkSumType)) (Proxy @LogLevel) - -- Metadata types - , (order <*> (genericShow <*> mkSumType)) (Proxy @Subject) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @(SubjectProperties A)) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @(Property A)) - , (order <*> (genericShow <*> mkSumType)) (Proxy @PropertyKey) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @HashFunction) - , (equal <*> (genericShow <*> mkSumType)) (Proxy @(AnnotatedSignature A)) - -- * Web API types , (equal <*> (genericShow <*> mkSumType)) (Proxy @(ContractActivationArgs A)) , (genericShow <*> mkSumType) (Proxy @(ContractInstanceClientState A)) diff --git a/MetaLamp/lending-pool/plutus-starter.cabal b/MetaLamp/lending-pool/plutus-starter.cabal index 4b036fca9..9abedda0c 100644 --- a/MetaLamp/lending-pool/plutus-starter.cabal +++ b/MetaLamp/lending-pool/plutus-starter.cabal @@ -21,9 +21,27 @@ maintainer: Your email -- category: -- extra-source-files: CHANGELOG.md +flag defer-plugin-errors + description: + Defer errors from the plugin, useful for things like Haddock that can't handle it. + default: False + manual: True + +common lang + default-language: Haskell2010 + ghc-options: + -Wall -Wnoncanonical-monad-instances + -Wincomplete-uni-patterns -Wincomplete-record-updates + -Wredundant-constraints -Widentities -rtsopts + -- See Plutus Tx readme + -fobject-code -fno-ignore-interface-pragmas -fno-omit-interface-pragmas + if flag(defer-plugin-errors) + ghc-options: -fplugin-opt PlutusTx.Plugin:defer-errors + library + import: lang exposed-modules: - Plutus.Abstract.State Plutus.Abstract.State.Select Plutus.Abstract.State.Update Plutus.Abstract.ContractResponse Plutus.Abstract.OutputValue Plutus.Abstract.TxUtils Plutus.Contracts.Service.FungibleToken Plutus.Contracts.Service.Oracle Plutus.Contracts.LendingPool.OnChain.Core Plutus.Contracts.LendingPool.OnChain.Core.Script Plutus.Contracts.LendingPool.OnChain.Core.Validator Plutus.Contracts.LendingPool.OnChain.Core.Logic Plutus.Contracts.LendingPool.OnChain.AToken Plutus.Contracts.LendingPool.OffChain.AToken Plutus.Contracts.LendingPool.OffChain.Info Plutus.Contracts.LendingPool.OffChain.Owner Plutus.Contracts.LendingPool.OffChain.State Plutus.Contracts.LendingPool.OffChain.User Plutus.PAB.Simulation Ext.Plutus.Ledger.Value Ext.Plutus.Ledger.Contexts + Plutus.Abstract.State Plutus.Abstract.State.Select Plutus.Abstract.State.Update Plutus.Abstract.ContractResponse Plutus.Abstract.OutputValue Plutus.Abstract.TxUtils Plutus.Contracts.Service.FungibleToken Plutus.Contracts.Service.Oracle Plutus.Contracts.LendingPool.OnChain.Core Plutus.Contracts.LendingPool.OnChain.Core.Script Plutus.Contracts.LendingPool.OnChain.Core.Validator Plutus.Contracts.LendingPool.OnChain.Core.Logic Plutus.Contracts.LendingPool.OnChain.AToken Plutus.Contracts.LendingPool.OffChain.AToken Plutus.Contracts.LendingPool.OffChain.Info Plutus.Contracts.LendingPool.OffChain.Owner Plutus.Contracts.LendingPool.OffChain.State Plutus.Contracts.LendingPool.OffChain.User Ext.Plutus.PAB.Webserver.Server Plutus.PAB.Simulation Ext.Plutus.Ledger.Value Ext.Plutus.Ledger.Contexts build-depends: base >= 4.9 && < 5, aeson, @@ -35,6 +53,13 @@ library freer-extras, prettyprinter, lens, + semigroups, + cryptonite, + memory, + data-default, + servant-server, + wai-cors, + servant-options, -- Plutus: playground-common, plutus-contract, @@ -45,12 +70,9 @@ library plutus-use-cases, plutus-pab hs-source-dirs: src - default-language: Haskell2010 - ghc-options: - -- See Plutus Tx readme - -fobject-code -fno-ignore-interface-pragmas -fno-omit-interface-pragmas executable pab + import: lang main-is: Main.hs hs-source-dirs: pab ghc-options: @@ -60,6 +82,7 @@ executable pab plutus-starter executable pab-simulation + import: lang main-is: Main.hs hs-source-dirs: pab-simulation ghc-options: @@ -69,6 +92,7 @@ executable pab-simulation plutus-starter executable generate-purs + import: lang main-is: Main.hs hs-source-dirs: generate-purs other-modules: AaveTypes @@ -78,7 +102,7 @@ executable generate-purs base >= 4.9 && < 5, aeson, directory, - servant-purescript, + servant-purescript -any, filepath, servant-server, bytestring, @@ -96,9 +120,10 @@ executable generate-purs plutus-contract, plutus-use-cases, plutus-ledger, - plutus-tx + plutus-tx -any test-suite test + import: lang type: exitcode-stdio-1.0 main-is: Main.hs hs-source-dirs: test diff --git a/MetaLamp/lending-pool/src/Ext/Plutus/PAB/Webserver/Server.hs b/MetaLamp/lending-pool/src/Ext/Plutus/PAB/Webserver/Server.hs new file mode 100644 index 000000000..01717b020 --- /dev/null +++ b/MetaLamp/lending-pool/src/Ext/Plutus/PAB/Webserver/Server.hs @@ -0,0 +1,60 @@ +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE NamedFieldPuns #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PartialTypeSignatures #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE TypeOperators #-} + +module Ext.Plutus.PAB.Webserver.Server where + +import Cardano.Wallet.Types (WalletInfo (..)) +import Control.Concurrent.Availability (Availability, + available, newToken) +import Data.Aeson (FromJSON, ToJSON) +import Data.Proxy +import Ledger.Crypto (pubKeyHash) +import qualified Network.Wai.Middleware.Cors as Cors +import qualified Network.Wai.Middleware.Servant.Options as Cors +import qualified Plutus.PAB.Effects.Contract as Contract +import Plutus.PAB.Simulator (Simulation) +import qualified Plutus.PAB.Simulator as Simulator +import Plutus.PAB.Webserver.API (API, WSAPI, + WalletProxy) +import qualified Plutus.PAB.Webserver.Server as PAB +import Servant (Application, + Handler (Handler), Raw, + ServerT, err500, + errBody, hoistServer, + serve, + serveDirectoryFileServer, + (:<|>) ((:<|>))) +import qualified Servant + +-- Note: this definition is only to provide options responses +-- WSAPI is websocket api which does not support options requests +type CombinedAPI t = + API (Contract.ContractDef t) Integer + +startServer :: forall t. + ( FromJSON (Contract.ContractDef t) + , ToJSON (Contract.ContractDef t) + , Contract.PABContract t + , Servant.MimeUnrender Servant.JSON (Contract.ContractDef t) + ) + => Simulation t (Simulation t ()) +startServer = do + availability <- newToken + let mkWalletInfo = do + (wllt, pk) <- Simulator.addWallet + pure $ WalletInfo{wiWallet = wllt, wiPubKey = pk, wiPubKeyHash = pubKeyHash pk} + snd <$> PAB.startServer' [Cors.cors (const $ Just policy), provideOptions] 9080 (Right mkWalletInfo) Nothing availability 30 + where + provideOptions = Cors.provideOptions (Proxy @(CombinedAPI t)) + policy = Cors.simpleCorsResourcePolicy + { Cors.corsRequestHeaders = [ "content-type" ] } diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 60ade2678..97af461d5 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -69,6 +69,8 @@ import Wallet.Emulator.Types (Wallet (..), walletPubKey) import Wallet.Types (ContractInstanceId) import Data.Default (Default (def)) +import qualified Ext.Plutus.PAB.Webserver.Server as Ext.Plutus.PAB + ownerWallet :: Wallet ownerWallet = Wallet 1 @@ -148,10 +150,10 @@ activateContracts = do runLendingPool :: IO () runLendingPool = void $ Simulator.runSimulationWith handlers $ do - Simulator.logString @(Builtin AaveContracts) "Starting Aave PAB webserver on port 8080. Press enter to exit." - shutdown <- PAB.Server.startServerDebug + Simulator.logString @(Builtin AaveContracts) "Starting Aave PAB webserver on port 9080. Press enter to exit." + shutdown <- Ext.Plutus.PAB.startServer _ <- activateContracts - Simulator.logString @(Builtin AaveContracts) "Aave PAB webserver started on port 8080. Initialization complete. Press enter to exit." + Simulator.logString @(Builtin AaveContracts) "Aave PAB webserver started on port 9080. Initialization complete. Press enter to exit." _ <- liftIO getLine shutdown From e08682babd9be28736c4d35f50d91b6dabc27a6f Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Wed, 15 Sep 2021 11:03:19 +0700 Subject: [PATCH 166/169] make fmt --- .../lending-pool/src/Plutus/Abstract/ContractResponse.hs | 2 +- MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs | 2 +- .../src/Plutus/Contracts/LendingPool/OffChain/AToken.hs | 2 +- .../src/Plutus/Contracts/LendingPool/OffChain/Info.hs | 2 +- .../src/Plutus/Contracts/LendingPool/OffChain/User.hs | 2 +- .../src/Plutus/Contracts/LendingPool/OnChain/AToken.hs | 2 +- .../lending-pool/src/Plutus/Contracts/Service/Oracle.hs | 2 +- MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs | 6 +++--- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs index 68965e8eb..f2034134e 100644 --- a/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/ContractResponse.hs @@ -3,13 +3,13 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} -{-# LANGUAGE LambdaCase #-} module Plutus.Abstract.ContractResponse where diff --git a/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs b/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs index 353ff5aae..f15481655 100644 --- a/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs +++ b/MetaLamp/lending-pool/src/Plutus/Abstract/TxUtils.hs @@ -41,7 +41,7 @@ import qualified Prelude type TxPair a = (Constraints.ScriptLookups a, Constraints.TxConstraints (RedeemerType a) (DatumType a)) type IsScriptData a = ( - PlutusTx.FromData (RedeemerType a), PlutusTx.ToData (RedeemerType a), + PlutusTx.FromData (RedeemerType a), PlutusTx.ToData (RedeemerType a), PlutusTx.FromData (DatumType a), PlutusTx.ToData (DatumType a)) submitTxPair :: (AsContractError e, IsScriptData a) => diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs index 7b7a848ab..3de6e87a5 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/AToken.hs @@ -20,6 +20,7 @@ import Ledger hiding (singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints import Ledger.Constraints.TxConstraints as Constraints +import Ledger.Contexts (scriptCurrencySymbol) import Ledger.Typed.Scripts (MintingPolicy) import qualified Ledger.Typed.Scripts as Scripts import Plutus.Abstract.OutputValue (OutputValue (..)) @@ -31,7 +32,6 @@ import Plutus.Contracts.LendingPool.OnChain.Core (Aave, AaveScript, import qualified Plutus.Contracts.LendingPool.OnChain.Core as Core import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken import Plutus.V1.Ledger.Contexts (ScriptContext) -import Ledger.Contexts (scriptCurrencySymbol) import qualified Plutus.V1.Ledger.Scripts as Scripts import Plutus.V1.Ledger.Value (AssetClass (..), diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs index 2d1b01232..4fdc07c3d 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/Info.hs @@ -90,7 +90,7 @@ data InfoContractState = deriving (Prelude.Eq, Show, Generic, FromJSON, ToJSON) infoEndpoints :: Aave -> Promise (ContractResponse Text InfoContractState) AaveInfoSchema Void () -infoEndpoints aave = +infoEndpoints aave = (withContractResponse (Proxy @"fundsAt") FundsAt fundsAt `select` withContractResponse (Proxy @"poolFunds") PoolFunds (const $ poolFunds aave) `select` withContractResponse (Proxy @"reserves") Reserves (const $ reserves aave) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs index 7845efda2..fbc5e60dd 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OffChain/User.hs @@ -365,7 +365,7 @@ Lens.makeClassyPrisms ''UserContractState -- TODO ? add repayWithCollateral userEndpoints :: Aave -> Promise (ContractResponse Text UserContractState) AaveUserSchema Void () -userEndpoints aave = +userEndpoints aave = (withContractResponse (Proxy @"deposit") (const Deposited) (deposit aave) `select` withContractResponse (Proxy @"withdraw") (const Withdrawn) (withdraw aave) `select` withContractResponse (Proxy @"borrow") (const Borrowed) (borrow aave) diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/AToken.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/AToken.hs index 0482bf4d2..d199da77e 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/AToken.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/LendingPool/OnChain/AToken.hs @@ -28,6 +28,7 @@ import Ledger hiding (singleton) import Ledger.Constraints as Constraints import Ledger.Constraints.OnChain as Constraints import Ledger.Constraints.TxConstraints as Constraints +import Ledger.Contexts (scriptCurrencySymbol) import Ledger.Typed.Scripts (MintingPolicy) import qualified Ledger.Typed.Scripts as Scripts import Plutus.Abstract.OutputValue (OutputValue (..)) @@ -38,7 +39,6 @@ import Plutus.Contracts.LendingPool.OnChain.Core (Aave, AaveScript, import qualified Plutus.Contracts.LendingPool.OnChain.Core as Core import qualified Plutus.Contracts.Service.FungibleToken as FungibleToken import Plutus.V1.Ledger.Contexts (ScriptContext) -import Ledger.Contexts (scriptCurrencySymbol) import qualified Plutus.V1.Ledger.Scripts as Scripts import Plutus.V1.Ledger.Value (AssetClass (..), TokenName (..), diff --git a/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs index 96558c385..e40331979 100644 --- a/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs +++ b/MetaLamp/lending-pool/src/Plutus/Contracts/Service/Oracle.hs @@ -257,4 +257,4 @@ runOracle op = do awaitPromise $ endpoint @"update" $ \x -> do updateOracle oracle x go oracle - \ No newline at end of file + diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 97af461d5..1625e64d8 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -26,12 +26,14 @@ import Data.Aeson (FromJSON, ToJSON, encode, fromJSON) import qualified Data.ByteString as BS +import Data.Default (Default (def)) import qualified Data.Map.Strict as Map import qualified Data.Monoid as Monoid import qualified Data.Semigroup as Semigroup import Data.Text (Text) import Data.Text.Prettyprint.Doc (Pretty (..), viaShow) +import qualified Ext.Plutus.PAB.Webserver.Server as Ext.Plutus.PAB import GHC.Generics (Generic) import Ledger import Ledger.Ada (adaSymbol, @@ -40,6 +42,7 @@ import Ledger.Ada (adaSymbol, lovelaceValueOf) import Ledger.Constraints import qualified Ledger.Constraints.OffChain as Constraints +import Ledger.Crypto (pubKeyHash) import qualified Ledger.Typed.Scripts as Scripts import Ledger.Value as Value import Plutus.Abstract.ContractResponse (ContractResponse (..)) @@ -63,13 +66,10 @@ import qualified Plutus.PAB.Simulator as Simulator import Plutus.PAB.Types (PABError (..)) import qualified Plutus.PAB.Webserver.Server as PAB.Server import Plutus.V1.Ledger.Crypto (getPubKeyHash) -import Ledger.Crypto (pubKeyHash) import Prelude hiding (init) import Wallet.Emulator.Types (Wallet (..), walletPubKey) import Wallet.Types (ContractInstanceId) -import Data.Default (Default (def)) -import qualified Ext.Plutus.PAB.Webserver.Server as Ext.Plutus.PAB ownerWallet :: Wallet ownerWallet = Wallet 1 From a1c067e4f3c36578aec5e0b7eb770d10edbaedbe Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Wed, 15 Sep 2021 15:32:32 +0700 Subject: [PATCH 167/169] remove mogus mock currency --- .../lending-pool/src/Plutus/PAB/Simulation.hs | 2 +- MetaLamp/lending-pool/test/Fixtures/Asset.hs | 10 +++++----- MetaLamp/lending-pool/test/Spec/Borrow.hs | 10 +++++----- MetaLamp/lending-pool/test/Spec/Deposit.hs | 10 +++++----- .../test/Spec/ProvideCollateral.hs | 12 +++++------ MetaLamp/lending-pool/test/Spec/Repay.hs | 10 +++++----- .../test/Spec/RevokeCollateral.hs | 14 ++++++------- MetaLamp/lending-pool/test/Spec/Withdraw.hs | 20 +++++++++---------- 8 files changed, 44 insertions(+), 44 deletions(-) diff --git a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs index 1625e64d8..a5316067b 100644 --- a/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs +++ b/MetaLamp/lending-pool/src/Plutus/PAB/Simulation.hs @@ -78,7 +78,7 @@ userWallets :: [Wallet] userWallets = [Wallet i | i <- [2 .. 4]] testAssets :: [AssetClass] -testAssets = fmap toAsset ["MOGUS", "USD"] +testAssets = fmap toAsset ["EURO", "USD"] toAsset :: TokenName -> AssetClass toAsset tokenName = diff --git a/MetaLamp/lending-pool/test/Fixtures/Asset.hs b/MetaLamp/lending-pool/test/Fixtures/Asset.hs index 032e909cd..b7b37c369 100644 --- a/MetaLamp/lending-pool/test/Fixtures/Asset.hs +++ b/MetaLamp/lending-pool/test/Fixtures/Asset.hs @@ -7,17 +7,17 @@ import qualified Plutus.Contracts.LendingPool.OnChain.AToken as AToken import Plutus.PAB.Simulation (toAsset) import Plutus.V1.Ledger.Value (AssetClass) -mogus :: AssetClass -mogus = toAsset "MOGUS" +euro :: AssetClass +euro = toAsset "EURO" usd :: AssetClass usd = toAsset "USD" defaultAssets :: [AssetClass] -defaultAssets = [mogus, usd] +defaultAssets = [euro, usd] -amogus :: AssetClass -amogus = AToken.makeAToken AaveMock.aaveHash mogus +aeuro :: AssetClass +aeuro = AToken.makeAToken AaveMock.aaveHash euro ausd :: AssetClass ausd = AToken.makeAToken AaveMock.aaveHash usd diff --git a/MetaLamp/lending-pool/test/Spec/Borrow.hs b/MetaLamp/lending-pool/test/Spec/Borrow.hs index 9f5cea74b..5e2d46f6b 100644 --- a/MetaLamp/lending-pool/test/Spec/Borrow.hs +++ b/MetaLamp/lending-pool/test/Spec/Borrow.hs @@ -33,9 +33,9 @@ tests = testGroup "borrow" [ walletFundsChange Fixtures.borrowerWallet (Fixtures.initialFunds <> - assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.usd 50) + assetClassValue Fixtures.euro (negate 100) <> assetClassValue Fixtures.usd 50) .&&. Shared.reservesChange ( - Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus + Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.euro . Utils.modifyAt (over Aave._rAmount (subtract 50 . (+100))) Fixtures.usd $ Fixtures.initialReserves) .&&. Shared.userConfigsChange ( @@ -44,7 +44,7 @@ tests = testGroup "borrow" [ (Aave.UserConfig { Aave.ucDebt = 50, Aave.ucCollateralizedInvestment = 0 }) . AssocMap.insert - (Fixtures.mogus, Utils.getPubKey Fixtures.borrowerWallet) + (Fixtures.euro, Utils.getPubKey Fixtures.borrowerWallet) (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 100 }) . AssocMap.insert @@ -57,8 +57,8 @@ tests = testGroup "borrow" [ handles <- Fixtures.defaultTrace deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.usd 100 - deposit (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.mogus 100 - provideCollateral (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.mogus 100 + deposit (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.euro 100 + provideCollateral (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.euro 100 borrow (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.usd 50, checkPredicate "Should fail if user's collateral is insufficient" diff --git a/MetaLamp/lending-pool/test/Spec/Deposit.hs b/MetaLamp/lending-pool/test/Spec/Deposit.hs index d6bce9936..7069e18c5 100644 --- a/MetaLamp/lending-pool/test/Spec/Deposit.hs +++ b/MetaLamp/lending-pool/test/Spec/Deposit.hs @@ -26,19 +26,19 @@ tests = testGroup "deposit" [ (walletFundsChange Fixtures.lenderWallet (Fixtures.initialFunds <> - assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.amogus 100) - .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus Fixtures.initialReserves) + assetClassValue Fixtures.euro (negate 100) <> assetClassValue Fixtures.aeuro 100) + .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.euro Fixtures.initialReserves) .&&. Shared.userConfigsChange ( AssocMap.insert - (Fixtures.mogus, Utils.getPubKey Fixtures.lenderWallet) + (Fixtures.euro, Utils.getPubKey Fixtures.lenderWallet) (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 0 }) $ Fixtures.initialUsers ) ) $ do handles <- Fixtures.defaultTrace - deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100, + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.euro 100, checkPredicate "Should fail if user's wallet balance is insufficient" (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds @@ -48,7 +48,7 @@ tests = testGroup "deposit" [ ) $ do handles <- Fixtures.defaultTrace - deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 10000 + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.euro 10000 ] deposit :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () diff --git a/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs b/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs index d19aaf695..444963c59 100644 --- a/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs +++ b/MetaLamp/lending-pool/test/Spec/ProvideCollateral.hs @@ -27,18 +27,18 @@ tests = testGroup "provideCollateral" [ (walletFundsChange Fixtures.lenderWallet (Fixtures.initialFunds <> - assetClassValue Fixtures.mogus (negate 100)) - .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus Fixtures.initialReserves) + assetClassValue Fixtures.euro (negate 100)) + .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.euro Fixtures.initialReserves) .&&. Shared.userConfigsChange (AssocMap.insert - (Fixtures.mogus, Utils.getPubKey Fixtures.lenderWallet) + (Fixtures.euro, Utils.getPubKey Fixtures.lenderWallet) (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 100 }) Fixtures.initialUsers) ) $ do handles <- Fixtures.defaultTrace - deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 - provideCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100, + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.euro 100 + provideCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.euro 100, checkPredicate "Should fail if user's aToken balance is insufficient" (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds @@ -48,7 +48,7 @@ tests = testGroup "provideCollateral" [ ) $ do handles <- Fixtures.defaultTrace - provideCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 + provideCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.euro 100 ] provideCollateral :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () diff --git a/MetaLamp/lending-pool/test/Spec/Repay.hs b/MetaLamp/lending-pool/test/Spec/Repay.hs index 8a43d8804..995e7766d 100644 --- a/MetaLamp/lending-pool/test/Spec/Repay.hs +++ b/MetaLamp/lending-pool/test/Spec/Repay.hs @@ -34,9 +34,9 @@ tests = testGroup "repay" [ walletFundsChange Fixtures.borrowerWallet (Fixtures.initialFunds <> - assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.usd (50 - 25)) + assetClassValue Fixtures.euro (negate 100) <> assetClassValue Fixtures.usd (50 - 25)) .&&. Shared.reservesChange ( - Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus + Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.euro . Utils.modifyAt (over Aave._rAmount ((+25) . subtract 50 . (+100))) Fixtures.usd $ Fixtures.initialReserves) .&&. Shared.userConfigsChange ( @@ -45,7 +45,7 @@ tests = testGroup "repay" [ (Aave.UserConfig { Aave.ucDebt = 50 - 25, Aave.ucCollateralizedInvestment = 0 }) . AssocMap.insert - (Fixtures.mogus, Utils.getPubKey Fixtures.borrowerWallet) + (Fixtures.euro, Utils.getPubKey Fixtures.borrowerWallet) (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 100 }) . AssocMap.insert @@ -58,8 +58,8 @@ tests = testGroup "repay" [ handles <- Fixtures.defaultTrace deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.usd 100 - deposit (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.mogus 100 - provideCollateral (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.mogus 100 + deposit (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.euro 100 + provideCollateral (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.euro 100 borrow (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.usd 50 repay (handles Map.! Fixtures.borrowerWallet) Fixtures.borrowerWallet Fixtures.usd 25 , diff --git a/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs b/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs index fd73eabb5..0b810d792 100644 --- a/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs +++ b/MetaLamp/lending-pool/test/Spec/RevokeCollateral.hs @@ -28,19 +28,19 @@ tests = testGroup "revokeCollateral" [ (walletFundsChange Fixtures.lenderWallet (Fixtures.initialFunds <> - assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.amogus (100 - 100 + 50)) - .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus Fixtures.initialReserves) + assetClassValue Fixtures.euro (negate 100) <> assetClassValue Fixtures.aeuro (100 - 100 + 50)) + .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.euro Fixtures.initialReserves) .&&. Shared.userConfigsChange (AssocMap.insert - (Fixtures.mogus, Utils.getPubKey Fixtures.lenderWallet) + (Fixtures.euro, Utils.getPubKey Fixtures.lenderWallet) (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 50 }) Fixtures.initialUsers) ) $ do handles <- Fixtures.defaultTrace - deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 - provideCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 - revokeCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 50, + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.euro 100 + provideCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.euro 100 + revokeCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.euro 50, checkPredicate "Should fail if user's investment is insufficient" (walletFundsChange Fixtures.lenderWallet Fixtures.initialFunds @@ -50,7 +50,7 @@ tests = testGroup "revokeCollateral" [ ) $ do handles <- Fixtures.defaultTrace - revokeCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 + revokeCollateral (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.euro 100 ] revokeCollateral :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () diff --git a/MetaLamp/lending-pool/test/Spec/Withdraw.hs b/MetaLamp/lending-pool/test/Spec/Withdraw.hs index acfbd225a..042e2f171 100644 --- a/MetaLamp/lending-pool/test/Spec/Withdraw.hs +++ b/MetaLamp/lending-pool/test/Spec/Withdraw.hs @@ -27,29 +27,29 @@ tests = testGroup "withdraw" [ (walletFundsChange Fixtures.lenderWallet (Fixtures.initialFunds <> - assetClassValue Fixtures.mogus (negate 100 + 50) <> assetClassValue Fixtures.amogus (100 - 50)) - .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (subtract 50 . (+100))) Fixtures.mogus Fixtures.initialReserves) + assetClassValue Fixtures.euro (negate 100 + 50) <> assetClassValue Fixtures.aeuro (100 - 50)) + .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (subtract 50 . (+100))) Fixtures.euro Fixtures.initialReserves) .&&. Shared.userConfigsChange ( AssocMap.insert - (Fixtures.mogus, Utils.getPubKey Fixtures.lenderWallet) + (Fixtures.euro, Utils.getPubKey Fixtures.lenderWallet) (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 0 }) $ Fixtures.initialUsers ) ) $ do handles <- Fixtures.defaultTrace - deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 - withdraw (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 50, + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.euro 100 + withdraw (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.euro 50, checkPredicate "Should fail if user's protocol balance is insufficient" (walletFundsChange Fixtures.lenderWallet (Fixtures.initialFunds <> - assetClassValue Fixtures.mogus (negate 100) <> assetClassValue Fixtures.amogus 100) - .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.mogus Fixtures.initialReserves) + assetClassValue Fixtures.euro (negate 100) <> assetClassValue Fixtures.aeuro 100) + .&&. Shared.reservesChange (Utils.modifyAt (over Aave._rAmount (+100)) Fixtures.euro Fixtures.initialReserves) .&&. Shared.userConfigsChange ( AssocMap.insert - (Fixtures.mogus, Utils.getPubKey Fixtures.lenderWallet) + (Fixtures.euro, Utils.getPubKey Fixtures.lenderWallet) (Aave.UserConfig { Aave.ucDebt = 0, Aave.ucCollateralizedInvestment = 0 }) $ Fixtures.initialUsers ) @@ -57,8 +57,8 @@ tests = testGroup "withdraw" [ ) $ do handles <- Fixtures.defaultTrace - deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 100 - withdraw (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.mogus 200 + deposit (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.euro 100 + withdraw (handles Map.! Fixtures.lenderWallet) Fixtures.lenderWallet Fixtures.euro 200 ] withdraw :: Fixtures.UserHandle -> Wallet -> AssetClass -> Integer -> Trace.EmulatorTrace () From 8243253a7a41b94223cf843e8c55a01f23746f47 Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Sat, 18 Sep 2021 10:17:55 +0700 Subject: [PATCH 168/169] remove unused packages --- MetaLamp/lending-pool/client/spago.dhall | 3 --- 1 file changed, 3 deletions(-) diff --git a/MetaLamp/lending-pool/client/spago.dhall b/MetaLamp/lending-pool/client/spago.dhall index aedb337cc..9df6e9667 100644 --- a/MetaLamp/lending-pool/client/spago.dhall +++ b/MetaLamp/lending-pool/client/spago.dhall @@ -28,9 +28,6 @@ You can edit this file as you like. , "undefinable" , "uuid" , "web-socket" - , "routing" - , "routing-duplex" - , "halogen-formless" ] , packages = ./packages.dhall , sources = From a5ad83c300964242769f87c96338a94218090df0 Mon Sep 17 00:00:00 2001 From: olgaklimenko Date: Sat, 18 Sep 2021 10:22:19 +0700 Subject: [PATCH 169/169] make fmt and update Makefile --- MetaLamp/lending-pool/Makefile | 5 ++-- .../client/src/Component/Contract.purs | 25 ++++++++++--------- MetaLamp/lending-pool/test/Utils/Data.hs | 2 +- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/MetaLamp/lending-pool/Makefile b/MetaLamp/lending-pool/Makefile index 78eafd665..5f9b3b414 100644 --- a/MetaLamp/lending-pool/Makefile +++ b/MetaLamp/lending-pool/Makefile @@ -1,3 +1,4 @@ fmt: - find pab src -type f -name \*.hs -exec \ - stylish-haskell --inplace '{}' + + fix-stylish-haskell + fix-purty + diff --git a/MetaLamp/lending-pool/client/src/Component/Contract.purs b/MetaLamp/lending-pool/client/src/Component/Contract.purs index 9d2c778f6..cccb55445 100644 --- a/MetaLamp/lending-pool/client/src/Component/Contract.purs +++ b/MetaLamp/lending-pool/client/src/Component/Contract.purs @@ -217,7 +217,7 @@ component = (const <<< pure $ unit) revokeCollateral Nothing -> throwError "Asset name not found" - + render :: State -> H.ComponentHTML Action Slots m render state = HH.div_ @@ -227,17 +227,18 @@ component = Loading -> HH.div_ [] Failure e -> HH.h4_ [ HH.text e ] Success _ -> HH.div_ [] - , case state.submit of - Loading -> HH.div_ [ HH.text "Loading..." ] - _ -> HH.div_ - $ mapWithIndex - ( \index (Tuple title operation) -> - HH.h2_ - [ HH.text title - , HH.slot _amountForm index AmountForm.component (reservesToAmounts state.reserves) (Just <<< (OnSubmitAmount operation)) - ] - ) - [ Tuple "Deposit" SubmitDeposit, Tuple "Withdraw" SubmitWithdraw, Tuple "Borrow" SubmitBorrow, Tuple "Repay" SubmitRepay, Tuple "ProvideCollateral" SubmitProvideCollateral, Tuple "RevokeCollateral" SubmitRevokeCollateral ] + , case state.submit of + Loading -> HH.div_ [ HH.text "Loading..." ] + _ -> + HH.div_ + $ mapWithIndex + ( \index (Tuple title operation) -> + HH.h2_ + [ HH.text title + , HH.slot _amountForm index AmountForm.component (reservesToAmounts state.reserves) (Just <<< (OnSubmitAmount operation)) + ] + ) + [ Tuple "Deposit" SubmitDeposit, Tuple "Withdraw" SubmitWithdraw, Tuple "Borrow" SubmitBorrow, Tuple "Repay" SubmitRepay, Tuple "ProvideCollateral" SubmitProvideCollateral, Tuple "RevokeCollateral" SubmitRevokeCollateral ] ] reservesToAmounts :: Array { amount :: BigInteger, asset :: AssetClass } -> Array AmountForm.AmountInfo diff --git a/MetaLamp/lending-pool/test/Utils/Data.hs b/MetaLamp/lending-pool/test/Utils/Data.hs index d174c7187..60e33497d 100644 --- a/MetaLamp/lending-pool/test/Utils/Data.hs +++ b/MetaLamp/lending-pool/test/Utils/Data.hs @@ -1,9 +1,9 @@ module Utils.Data where import Data.Function ((&)) +import Ledger.Crypto (pubKeyHash) import Plutus.Abstract.ContractResponse (ContractResponse (..)) import Plutus.V1.Ledger.Crypto (PubKeyHash) -import Ledger.Crypto (pubKeyHash) import qualified PlutusTx.AssocMap as AssocMap import qualified PlutusTx.Prelude as PlutusTx import Wallet.Emulator.Wallet (Wallet, walletPubKey)