diff --git a/CHANGELOG.md b/CHANGELOG.md index fb7fb90ba3..275cdd1521 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,48 +7,49 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) -- [[Unreleased]](#unreleased) - - [Added](#added) - - [Changed](#changed) - - [Fixed](#fixed) - - [Removed](#removed) -- [[v5.0.0]](#v500) - - [Added](#added-1) - - [Changed](#changed-1) - - [Removed](#removed-1) - - [Fixed](#fixed-1) - - [Runtime Dependencies](#runtime-dependencies) -- [[v4.0.2] - 2023-01-17](#v402---2023-01-17) - - [Fixed](#fixed-2) -- [[v4.0.1] - 2022-12-20](#v401---2022-12-20) - - [Added](#added-2) -- [[v4.0.0] - 2022-12-15](#v400---2022-12-15) - - [Added](#added-3) - - [Changed](#changed-2) - - [Removed](#removed-2) - - [Fixed](#fixed-3) - - [Runtime Dependencies](#runtime-dependencies-1) -- [[3.0.0] - 2022-11-21](#300---2022-11-21) - - [Added](#added-4) - - [Changed](#changed-3) - - [Removed](#removed-3) - - [Fixed](#fixed-4) - - [Runtime Dependencies](#runtime-dependencies-2) -- [[2.0.0] - 2022-09-12](#200---2022-09-12) - - [Added](#added-5) - - [Changed](#changed-4) - - [Removed](#removed-4) - - [Fixed](#fixed-5) -- [[2.0.0-alpha] - 2022-07-05](#200-alpha---2022-07-05) - - [Added](#added-6) - - [Removed](#removed-5) - - [Changed](#changed-5) - - [Fixed](#fixed-6) -- [[1.1.0] - 2022-06-30](#110---2022-06-30) - - [Fixed](#fixed-7) -- [[1.0.1] - 2022-06-17](#101---2022-06-17) - - [Fixed](#fixed-8) -- [[1.0.0] - 2022-06-10](#100---2022-06-10) +- [Changelog](#changelog) + - [\[Unreleased\]](#unreleased) + - [Added](#added) + - [Changed](#changed) + - [Fixed](#fixed) + - [Removed](#removed) + - [\[v5.0.0\]](#v500) + - [Added](#added-1) + - [Changed](#changed-1) + - [Removed](#removed-1) + - [Fixed](#fixed-1) + - [Runtime Dependencies](#runtime-dependencies) + - [\[v4.0.2\] - 2023-01-17](#v402---2023-01-17) + - [Fixed](#fixed-2) + - [\[v4.0.1\] - 2022-12-20](#v401---2022-12-20) + - [Added](#added-2) + - [\[v4.0.0\] - 2022-12-15](#v400---2022-12-15) + - [Added](#added-3) + - [Changed](#changed-2) + - [Removed](#removed-2) + - [Fixed](#fixed-3) + - [Runtime Dependencies](#runtime-dependencies-1) + - [\[3.0.0\] - 2022-11-21](#300---2022-11-21) + - [Added](#added-4) + - [Changed](#changed-3) + - [Removed](#removed-3) + - [Fixed](#fixed-4) + - [Runtime Dependencies](#runtime-dependencies-2) + - [\[2.0.0\] - 2022-09-12](#200---2022-09-12) + - [Added](#added-5) + - [Changed](#changed-4) + - [Removed](#removed-4) + - [Fixed](#fixed-5) + - [\[2.0.0-alpha\] - 2022-07-05](#200-alpha---2022-07-05) + - [Added](#added-6) + - [Removed](#removed-5) + - [Changed](#changed-5) + - [Fixed](#fixed-6) + - [\[1.1.0\] - 2022-06-30](#110---2022-06-30) + - [Fixed](#fixed-7) + - [\[1.0.1\] - 2022-06-17](#101---2022-06-17) + - [Fixed](#fixed-8) + - [\[1.0.0\] - 2022-06-10](#100---2022-06-10) @@ -66,6 +67,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - `Contract.JsSdk` module containing helper functions for developers who want to use CTL from JS. See also: [this new guide](./doc/using-from-js.md) ([#1453](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1453)) - New [docs for contract environment](./doc/contract-environment.md) ([#1453](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1453)) - Cluster configuration options to `PlutipConfig`: `epochSize`, `maxTxSize` and `raiseExUnitsToMax` - see [Plutip docs](./doc/plutip-testing.md) ([#1494](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1494)) +- [HD wallet support](./doc/key-management.md) with mnemonic seed phrases ([#1498](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1498)) +- Ogmios-specific functions for Local TX Monitor Ouroboros Mini-Protocol in `Contract.Backend.Ogmios` ([#1508](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1508/)) +- New `mustSendChangeWithDatum` balancer constraint that adds datum to all change outputs ([#1510](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1510/)) +- Allow providing a custom set of UTxOs for collateral selection, overriding the wallet (`mustUseCollateralUtxos` balancer constraint) ([#1513](https://github.com/Plutonomicon/cardano-transaction-lib/pull/1513)) ### Changed diff --git a/README.md b/README.md index 82dd94eacf..654c565be6 100644 --- a/README.md +++ b/README.md @@ -1,115 +1,10 @@ # cardano-transaction-lib -[![Hercules-ci][herc badge]][herc link] -[![Cachix Cache][cachix badge]][cachix link] -[![PureScript code documentation][docs badge]][docs link] +This repository is a fork from https://github.com/Plutonomicon/cardano-transaction-lib and contains any necessary changes that provide either improvements that are currently not present in CTL or patches that are specific to Indigo which will most likely not be implemented in the upstream repository. -[herc badge]: https://img.shields.io/badge/ci--by--hercules-green.svg -[herc link]: https://hercules-ci.com/github/Plutonomicon/cardano-transaction-lib -[cachix badge]: https://img.shields.io/badge/cachix-public_plutonomicon-blue.svg -[cachix link]: https://public-plutonomicon.cachix.org -[docs badge]: https://img.shields.io/badge/docs-PureScript%20code%20documentation-%2377F -[docs link]: https://plutonomicon.github.io/cardano-transaction-lib/ +### Improvements (Potential PRs): +* Sharing wallets between Plutip tests: https://github.com/IndigoProtocol/cardano-transaction-lib/pull/1 -**cardano-transaction-lib** (CTL) is a Purescript library for building smart contract transactions on Cardano. It aims to port the functionality and interface of Plutus off-chain code to the browser environment and NodeJS. - -**Table of Contents** - - - - -- [Documentation](#documentation) - - [Light wallet support](#light-wallet-support) -- [Roadmap](#roadmap) -- [Architecture](#architecture) -- [Additional resources/tools:](#additional-resourcestools) -- [Available support channels info](#available-support-channels-info) - - - -## Documentation - -Please explore our documentation to discover how to use CTL, how to set up its runtime, and how it compares to Plutus/PAB: - -- [Super quick start](./doc/getting-started.md#setting-up-a-new-project) -- [Adding CTL as a dependency](./doc/ctl-as-dependency.md) -- [CTL's runtime dependencies](./doc/runtime.md) -- [Blockfrost support](./doc/blockfrost.md) -- [Getting started writing CTL contracts](./doc/getting-started.md) -- [Managing contract environment](./doc/contract-environment.md) -- [Using CTL from JS](./doc/using-from-js.md) -- [Importing Plutus Scripts](./doc/importing-scripts.md) -- [Migrating from Plutus to CTL](./doc/plutus-comparison.md) -- [Overview of testing approaches](./doc/testing.md) - - [Testing contracts with Plutip](./doc/plutip-testing.md) - - [End-to-end testing with headless browsers](./doc/e2e-testing.md) - - [Utilities for testing](./doc/test-utils.md) -- [CIP-25 NFT standard support](./doc/cip-25-nfts.md) -- [Transaction balancing](./doc/balancing.md) -- [Transaction chaining](./doc/tx-chaining.md) -- [Ada staking support](./doc/staking.md) -- [SECP256k1 support (CIP-49)](./doc/secp256k1-support.md) -- [Custom query layers](./doc/custom-query-layers.md) -- [FAQs](./doc/faq.md) -- [Feature overview video](./doc/video-intro.md) -- [Development workflows for CTL](./doc/development.md) - -You can also access [PureScript documentation for CTL and its dependencies](https://plutonomicon.github.io/cardano-transaction-lib/) for the most recent `develop` version, or [generate it yourself](./doc/development.md#generating-ps-documentation). - -### Light wallet support - -Support is planned for the following light wallets: - -- [x] [Nami](https://namiwallet.io/) -- [x] [Gero](https://gerowallet.io/) -- [x] [Flint](https://flint-wallet.com/) -- [x] [Lode](https://lodewallet.io/) -- [x] [Eternl (formerly CCvault)](https://eternl.io/) -- [x] [NuFi](https://nu.fi/) -- [ ] [Lace](https://www.lace.io/) -- [ ] [Typhon](https://typhonwallet.io/) -- [ ] [Yoroi](https://yoroi-wallet.com/) - -## Roadmap - -- [x] **Stage 1** Build a simple transaction in the browser that works with at least one light wallet (Nami) -- [x] **Stage 2** Once we can construct a simple user-to-user transaction, we will try to use the library to submit the tx with nami -- [x] **Stage 3** Once we have a simple working transaction, we will seek to build a Plutus smart contract transaction with datum from scratch -- [x] **Stage 4** Once we can construct Plutus smart contract transactions, we will seek to build a library/DSL/interface such that transactions can be built using constraints and lookups - as close as possible to a cut-and-paste solution from Plutus' `Contract` monad code in Haskell (but with no guarantee that code changes are not necessary) - - [x] **Stage 4.1** Investigate supporting compatibility with the Vasil hardfork and improvements to our initial `Contract` API -- [ ] **Stage 5** Once we have a basic `Contract`-style API, we will further refine its public interface, expand wallet support (see [below](#light-wallet-support)), expose a test interface (**DONE** - see [here](doc/plutip-testing.md)), provide a more ergonomic JS/TS API, support stake validators (**DONE**), and support CIP workflows on the public testnet (**In progress**) -- [ ] **Stage 6** Once CTL's `Contract` interface has been stabilized, we will add support for even more wallets and attempt to deprecate CTL's currently required Haskell server (**DONE**) - -## Architecture - -CTL is directly inspired by the Plutus Application Backend (PAB). Unlike PAB, however, CTL is a library and not a standalone process. Over the course of CTL's development, several questions have been raised as to how best create PAB-as-a-library: - -1. How do we get the transaction in the right format? - - This is handled by `cardano-serialization-lib`, a Rust library available as WASM -2. How do we query the chain? - - This has been solved using Ogmios & Kupo - - We [will support](https://cardano.ideascale.com/c/idea/420791) an alternative [BlockFrost](https://blockfrost.io/) backend as well in the future -3. How do we query for datums (i.e. the datums themselves and not just their hashes)? - - `Kupo` solves this problem -4. How do we get wallet data? - - This is done via browser-based light wallet integration in the browser based on CIP-30 -5. How closely should we follow Plutus' `Contract` API? - - CTL's `Contract` model is **significantly** less restrictive than Plutus' and allows for arbitrary effects within the `Contract` monad - - Certain features cannot be directly translated into Purescript from Haskell due to differences between the two languages - - Some of the Plutus conventions do not make sense for us, due to differences between on-chain and off-chain - -## Additional resources/tools: - -- [`cardano-serialization-lib`](https://github.com/Emurgo/cardano-serialization-lib/) -- [Ogmios](https://ogmios.dev) for chain queries -- [Kupo](https://cardanosolutions.github.io/kupo/) for chain queries -- [CIP-30](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0030) (wallet interface - Nami partially implements this) -- [Nami docs](https://github.com/Berry-Pool/nami-wallet) -- [Alonzo CDDL spec](https://github.com/input-output-hk/cardano-ledger/blob/0738804155245062f05e2f355fadd1d16f04cd56/alonzo/impl/cddl-files/alonzo.cddl) - -## Available support channels info - -You can find help, more information and ongoing discusion about the project here: - -- [Plutonomicon Discord](https://discord.gg/JhbexnV9Pc) -- #ctl channel at MLabs' Slack +### Patches (Breaking Changes): +* Using a CSL fork to serialize/deserialize unsorted maps: https://github.com/IndigoProtocol/cardano-transaction-lib/pull/2 +* Having `epochSize` in `PlutipConfig` to prevent `CannotFindTimeInEraSummaries` error: https://github.com/Plutonomicon/cardano-transaction-lib/issues/1057 diff --git a/doc/balancing.md b/doc/balancing.md index fc5a919d42..f8d642f390 100644 --- a/doc/balancing.md +++ b/doc/balancing.md @@ -18,10 +18,12 @@ Transaction balancing in Cardano is the process of finding a set of inputs and o CTL allows tweaking the default balancer behavior by letting the user impose constraints on the UTxO set that is used in the process (`balanceTxWithConstraints`): -- providing additional UTxOs to use: `mustUseUtxosAtAddresses` / `mustUseUtxosAtAddress` / `mustUseAdditionalUtxos` -- overriding change address: `mustSendChangeToAddress` -- prevent certain UTxOs from being spent: `mustNotSpendUtxosWithOutRefs` / `mustNotSpendUtxoWithOutRef` -- distribute token outputs equally between change UTxOs: `mustGenChangeOutsWithMaxTokenQuantity` +- Using arbitrary address as user's own (for transaction balancing): `mustUseUtxosAtAddresses` / `mustUseUtxosAtAddress` +- Providing additional UTxOs to use: `mustUseAdditionalUtxos` +- Bypassing wallet's collateral selection and select collateral UTxOs from a given set: `mustUseCollateralUtxos` +- Overriding change address: `mustSendChangeToAddress` +- Preventing certain UTxOs from being spent: `mustNotSpendUtxosWithOutRefs` / `mustNotSpendUtxoWithOutRef` +- Distributing token outputs equally between change UTxOs: `mustGenChangeOutsWithMaxTokenQuantity` ## Concurrent spending @@ -31,11 +33,11 @@ Obviously, the number of available UTxOs must be greater than the number of tran ## Balancing a Tx for other wallet -Setting `mustUseUtxosAtAddress` and `mustSendChangeToAddress` at the same time allows to build a transaction without any connection to the current wallet. For example, it's possible to balance it on server-side and send to the user to sign, or balance a Tx on one user's side while leaving fees at the expense of some other user. +Setting `mustUseUtxosAtAddress`, `mustSendChangeToAddress` and `mustUseCollateralUtxos` at the same time allows to build a transaction without any connection to the current wallet. For example, it's possible to balance it on server-side and send to the user to sign, or balance a Tx on one user's side while leaving fees at the expense of some other user. ## Synchronization -Before balancing, CTL synchronizes the wallet with the query layer, i.e. waits until all UTxOs that the wallet returns are visible in the query layer. Thus the situation when the query layer refuses to validate a Tx (either during ex-units evaluation or on Tx submission) is only possible due to a rollback. Please see [our docs for query layer synchronization](./query-layers.md). +Before balancing, CTL tries to synchronize the wallet state with the query layer, i.e. waits until all UTxOs that the wallet returns are visible in the query layer. Thus the situation when the query layer refuses to validate a Tx (either during ex-units evaluation or on Tx submission) is only possible due to a rollback or a synchronization timeout. Please see [our docs for query layer synchronization](./query-layers.md). ## Balancing process limitations diff --git a/examples/BalanceTxConstraints.purs b/examples/BalanceTxConstraints.purs index e8532c83b1..3aae0e54e1 100644 --- a/examples/BalanceTxConstraints.purs +++ b/examples/BalanceTxConstraints.purs @@ -5,14 +5,13 @@ module Ctl.Examples.BalanceTxConstraints import Contract.Prelude -import Contract.Address - ( Address - ) +import Contract.Address (Address) import Contract.BalanceTxConstraints ( BalanceTxConstraintsBuilder , mustGenChangeOutsWithMaxTokenQuantity , mustNotSpendUtxoWithOutRef , mustSendChangeToAddress + , mustUseCollateralUtxos , mustUseUtxosAtAddress ) as BalanceTxConstraints import Contract.Log (logInfo') @@ -42,6 +41,7 @@ import Contract.Value (singleton, valueOf) as Value import Contract.Wallet ( KeyWallet , getWalletAddressesWithNetworkTag + , getWalletCollateral , ownPaymentPubKeyHashes , withKeyWallet ) @@ -51,7 +51,7 @@ import Ctl.Examples.Helpers (mkCurrencySymbol, mkTokenName) as Helpers import Data.Array (head) import Data.Array (sort) as Array import Data.BigInt (BigInt, fromInt) -import Data.Map (keys, member) as Map +import Data.Map (fromFoldable, keys, member) as Map import Data.Set (findMin) as Set newtype ContractParams = ContractParams @@ -62,6 +62,7 @@ newtype ContractParams = ContractParams type ContractResult = { txHash :: TransactionHash , changeAddress :: Address + , nonSpendableAddress :: Address , mintedToken :: CurrencySymbol /\ TokenName , nonSpendableOref :: TransactionInput } @@ -99,8 +100,8 @@ assertSelectedUtxoIsNotSpent :: ContractCheck ContractResult assertSelectedUtxoIsNotSpent = assertionToCheck "Non-spendable UTxO hasn't been spent" - \{ changeAddress, nonSpendableOref } -> do - utxos <- lift $ utxosAt changeAddress + \{ nonSpendableAddress, nonSpendableOref } -> do + utxos <- lift $ utxosAt nonSpendableAddress let assertionFailure :: ContractAssertionFailure assertionFailure = @@ -119,6 +120,11 @@ contract :: ContractParams -> Contract Unit contract (ContractParams p) = do logInfo' "Examples.BalanceTxConstraints" + aliceAddress <- + liftedM "Failed to get Alice's address" + $ head + <$> (withKeyWallet p.aliceKeyWallet getWalletAddressesWithNetworkTag) + alicePubKeyHash <- liftedM "Failed to get own PKH" $ head <$> ownPaymentPubKeyHashes @@ -132,9 +138,16 @@ contract (ContractParams p) = do $ head <$> (withKeyWallet p.bobKeyWallet getWalletAddressesWithNetworkTag) + bobsCollateralArray <- withKeyWallet p.bobKeyWallet do + fold <$> getWalletCollateral + let + bobsCollateral = + Map.fromFoldable $ bobsCollateralArray <#> unwrap >>> + \{ input, output } -> Tuple input output + nonSpendableOref <- liftedM "Failed to get utxos at Bob's address" - (Set.findMin <<< Map.keys <$> utxosAt bobAddress) + (Set.findMin <<< Map.keys <$> utxosAt aliceAddress) mp /\ cs <- Helpers.mkCurrencySymbol alwaysMintsPolicy tn <- Helpers.mkTokenName "The Token" @@ -153,6 +166,7 @@ contract (ContractParams p) = do <> BalanceTxConstraints.mustUseUtxosAtAddress bobAddress <> BalanceTxConstraints.mustSendChangeToAddress bobAddress <> BalanceTxConstraints.mustNotSpendUtxoWithOutRef nonSpendableOref + <> BalanceTxConstraints.mustUseCollateralUtxos bobsCollateral void $ runChecks checks $ lift do unbalancedTx <- @@ -172,4 +186,10 @@ contract (ContractParams p) = do logInfo' "Tx submitted successfully!" let changeAddress = (unwrap bobAddress).address - pure { txHash, changeAddress, mintedToken: cs /\ tn, nonSpendableOref } + pure + { txHash + , changeAddress + , nonSpendableAddress: (unwrap aliceAddress).address + , mintedToken: cs /\ tn + , nonSpendableOref + } diff --git a/flake.lock b/flake.lock index 69679295fd..a44c14f6a0 100644 --- a/flake.lock +++ b/flake.lock @@ -980,17 +980,17 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1678285155, - "narHash": "sha256-GcaiQRZhPYysINnAFPN+IyQu9S/CZA8eb5sTGZ4qfxw=", + "lastModified": 1684253604, + "narHash": "sha256-8MvK2AxG3bGWkxWutsCWRk9MYxf/FdQu/DkAvemjqHM=", "owner": "blockfrost", "repo": "blockfrost-backend-ryo", - "rev": "49269a9adb27b370209a61de2f5407945112860a", + "rev": "587aa6800f4c0dfaf285c1313fed3043848c4a84", "type": "github" }, "original": { "owner": "blockfrost", "repo": "blockfrost-backend-ryo", - "rev": "49269a9adb27b370209a61de2f5407945112860a", + "rev": "587aa6800f4c0dfaf285c1313fed3043848c4a84", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 4004c7bf60..34af0eec3c 100644 --- a/flake.nix +++ b/flake.nix @@ -40,7 +40,7 @@ }; # TODO use a tag for blockfrost as soon as they tag a recent commit (we need it as a flake) - blockfrost.url = "github:blockfrost/blockfrost-backend-ryo/49269a9adb27b370209a61de2f5407945112860a"; + blockfrost.url = "github:blockfrost/blockfrost-backend-ryo/587aa6800f4c0dfaf285c1313fed3043848c4a84"; db-sync.url = "github:input-output-hk/cardano-db-sync/13.1.0.0"; # Plutip server related inputs @@ -138,6 +138,7 @@ packageLock = ./package-lock.json; shell = { withRuntime = true; + withChromium = false; shellHook = exportOgmiosFixtures; packageLockOnly = true; packages = with pkgs; [ diff --git a/package-lock.json b/package-lock.json index 857dce0c6c..a314bfab95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,16 +20,6 @@ "resolved": "https://registry.npmjs.org/@emurgo/cardano-message-signing-nodejs/-/cardano-message-signing-nodejs-1.0.1.tgz", "integrity": "sha512-PoKh1tQnJX18f8iEr8Jk1KXxKCn9eqaSslMI1pyOJvYRJhQVDLCh0+9YReufjp0oFJIY1ShcrR+4/WnECVZUKQ==" }, - "@emurgo/cardano-serialization-lib-browser": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-browser/-/cardano-serialization-lib-browser-11.2.1.tgz", - "integrity": "sha512-J9Pmeta7y1GYnMCxtb3GnGCRw6zk1wiQ8EdCYQRn/Yqa/ss1zoBjd41euVi02Eb58aLuOJS81nNU+BcMLGXvUg==" - }, - "@emurgo/cardano-serialization-lib-nodejs": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-11.2.1.tgz", - "integrity": "sha512-+Rw35NW4Qv/9uFaPxhKtxiIPmoBEIFMAgdqQxZTw6hNT/wvBp2TvwTBPnOW8ODs7GUAA8nrO1rJJAaxF+mAG2w==" - }, "@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -79,6 +69,16 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@mitchycola/cardano-serialization-lib-browser": { + "version": "11.2.5", + "resolved": "https://registry.npmjs.org/@mitchycola/cardano-serialization-lib-browser/-/cardano-serialization-lib-browser-11.2.5.tgz", + "integrity": "sha512-J20EsRT5JDjel3E9gP17avhWCMWIA5UFwm3ZnUfpfqFjIKJU2Acq9rXQ+kSu0azW98pWQX8K08LmS8oMR+4wCA==" + }, + "@mitchycola/cardano-serialization-lib-nodejs": { + "version": "11.2.5", + "resolved": "https://registry.npmjs.org/@mitchycola/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-11.2.5.tgz", + "integrity": "sha512-VMuSYobAtaO+YAWePabXg+1+LgcpGF6kBz0LKmKwOI9KQWQuOYXstzp73k0YVkCnI/yekEDuHcnNqm1KFLk+Hw==" + }, "@mlabs-haskell/csl-gc-wrapper": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@mlabs-haskell/csl-gc-wrapper/-/csl-gc-wrapper-1.0.1.tgz", @@ -1404,9 +1404,9 @@ "dev": true }, "devtools-protocol": { - "version": "0.0.1011705", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1011705.tgz", - "integrity": "sha512-OKvTvu9n3swmgYshvsyVHYX0+aPzCoYUnyXUacfQMmFtBtBKewV/gT4I9jkAbpTqtTi2E4S9MXLlvzBDUlqg0Q==" + "version": "0.0.1019158", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1019158.tgz", + "integrity": "sha512-wvq+KscQ7/6spEV7czhnZc9RM/woz1AY+/Vpd8/h2HFMwJSdTliu7f/yr1A6vDdJfKICZsShqsYpEQbdhg8AFQ==" }, "diffie-hellman": { "version": "5.0.3", @@ -1629,52 +1629,12 @@ "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", "dev": true }, - "es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.4.3", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - } - }, "es-module-lexer": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", "dev": true }, - "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" - } - }, "es6-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", @@ -2025,21 +1985,11 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, "functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true }, "get-intrinsic": { "version": "1.1.1", @@ -2057,15 +2007,6 @@ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -2108,6 +2049,26 @@ "slash": "^3.0.0" } }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + }, + "dependencies": { + "get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + } + } + }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -2128,11 +2089,6 @@ "function-bind": "^1.1.1" } }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2419,16 +2375,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, "interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", @@ -2472,14 +2418,6 @@ "has-tostringtag": "^1.0.0" } }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "requires": { - "has-bigints": "^1.0.1" - } - }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -2505,9 +2443,9 @@ "dev": true }, "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" }, "is-core-module": { "version": "2.9.0", @@ -2522,6 +2460,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -2576,25 +2515,12 @@ "define-properties": "^1.1.3" } }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" - }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, "is-path-cwd": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", @@ -2626,61 +2552,30 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" } }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "requires": { - "call-bind": "^1.0.2" - } - }, "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "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-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.9.tgz", - "integrity": "sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==", + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", "for-each": "^0.3.3", + "gopd": "^1.0.1", "has-tostringtag": "^1.0.0" } }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "requires": { - "call-bind": "^1.0.2" - } - }, "is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -3192,27 +3087,6 @@ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "requires": { "whatwg-url": "^5.0.0" - }, - "dependencies": { - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } } }, "node-forge": { @@ -3222,9 +3096,9 @@ "dev": true }, "node-gyp-build": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", - "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==" + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", + "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==" }, "node-polyfill-webpack-plugin": { "version": "1.1.4", @@ -3290,7 +3164,8 @@ "object-inspect": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.1.tgz", - "integrity": "sha512-Y/jF6vnvEtOPGiKD1+q+X0CiUYRQtEHp89MLLUJ7TUivtH8Ugn2+3A7Rynqk7BRsAoqeOQWnFnjpDrKSxDgIGA==" + "integrity": "sha512-Y/jF6vnvEtOPGiKD1+q+X0CiUYRQtEHp89MLLUJ7TUivtH8Ugn2+3A7Rynqk7BRsAoqeOQWnFnjpDrKSxDgIGA==", + "dev": true }, "object-is": { "version": "1.1.5", @@ -3306,17 +3181,6 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, - "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" - } - }, "obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", @@ -3656,13 +3520,13 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "puppeteer-core": { - "version": "15.3.2", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-15.3.2.tgz", - "integrity": "sha512-Fmca9UzXmJkRrvGBgUmrffGD2BlulUTfsVefV1+vqfNm4PnlZ/U1bfD6X8XQ0nftyyg520tmSKd81yH3Z2tszg==", + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-15.5.0.tgz", + "integrity": "sha512-5Q8EmF++MARczJD1JcRehVePlctxGG2TFHSxdCV8NqPOk44/cMySmZw2nETn+lwUOyp0L9afosMFTnT4KgmWgw==", "requires": { "cross-fetch": "3.1.5", "debug": "4.3.4", - "devtools-protocol": "0.0.1011705", + "devtools-protocol": "0.0.1019158", "extract-zip": "2.0.1", "https-proxy-agent": "5.0.1", "pkg-dir": "4.2.0", @@ -3799,6 +3663,7 @@ "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -4132,6 +3997,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -4264,26 +4130,6 @@ "xtend": "^4.0.2" } }, - "string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4418,6 +4264,11 @@ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "traverse": { "version": "0.6.7", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", @@ -4451,17 +4302,6 @@ "mime-types": "~2.1.24" } }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, "unbzip2-stream": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", @@ -4588,15 +4428,14 @@ } }, "util": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.4.tgz", - "integrity": "sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==", + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", "requires": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", - "safe-buffer": "^5.1.2", "which-typed-array": "^1.1.2" } }, @@ -4675,6 +4514,11 @@ "minimalistic-assert": "^1.0.0" } }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, "webpack": { "version": "5.67.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.67.0.tgz", @@ -4922,6 +4766,15 @@ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4931,29 +4784,17 @@ "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-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.8.tgz", - "integrity": "sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", - "es-abstract": "^1.20.0", "for-each": "^0.3.3", + "gopd": "^1.0.1", "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.9" + "is-typed-array": "^1.1.10" } }, "wildcard": { diff --git a/package.json b/package.json index fdc0085b55..d0142eeed0 100755 --- a/package.json +++ b/package.json @@ -33,8 +33,8 @@ "dependencies": { "@emurgo/cardano-message-signing-browser": "1.0.1", "@emurgo/cardano-message-signing-nodejs": "1.0.1", - "@emurgo/cardano-serialization-lib-browser": "11.2.1", - "@emurgo/cardano-serialization-lib-nodejs": "11.2.1", + "@mitchycola/cardano-serialization-lib-browser": "^11.2.5", + "@mitchycola/cardano-serialization-lib-nodejs": "11.2.5", "@mlabs-haskell/csl-gc-wrapper": "^1.0.1", "@mlabs-haskell/json-bigint": " 1.0.0", "@noble/secp256k1": "^1.7.0", diff --git a/server/dist-newstyle/cache/compiler b/server/dist-newstyle/cache/compiler new file mode 100644 index 0000000000..a27777f54c Binary files /dev/null and b/server/dist-newstyle/cache/compiler differ diff --git a/server/dist-newstyle/cache/config b/server/dist-newstyle/cache/config new file mode 100644 index 0000000000..1d66c52ec6 Binary files /dev/null and b/server/dist-newstyle/cache/config differ diff --git a/src/Contract/AssocMap.purs b/src/Contract/AssocMap.purs index 419361f046..755fdc2c8b 100644 --- a/src/Contract/AssocMap.purs +++ b/src/Contract/AssocMap.purs @@ -1,6 +1,16 @@ -- | A module for a Plutus-style `AssocMap` -module Contract.AssocMap (module AssocMap) where +module Contract.AssocMap + ( DatumMap(DatumMap) + , module AssocMap + ) where +import Contract.Prelude + +import Aeson (class DecodeAeson, class EncodeAeson) +import Ctl.Internal.FromData + ( class FromData + , fromData + ) import Ctl.Internal.Plutus.Types.AssocMap ( Map(Map) , delete @@ -20,3 +30,51 @@ import Ctl.Internal.Plutus.Types.AssocMap , unionWith , values ) as AssocMap +import Ctl.Internal.ToData + ( class ToData + , toData + ) +import Ctl.Internal.Types.PlutusData + ( PlutusData(DatumMap, Map) + ) as PlutusData +import Data.Bifunctor (bimap) + +newtype DatumMap (k :: Type) (v :: Type) = DatumMap (AssocMap.Map k v) + +derive instance Generic (DatumMap k v) _ +derive instance Newtype (DatumMap k v) _ +derive newtype instance (Eq k, Eq v) => Eq (DatumMap k v) +derive newtype instance (Ord k, Ord v) => Ord (DatumMap k v) +derive newtype instance + ( EncodeAeson k + , EncodeAeson v + ) => + EncodeAeson (DatumMap k v) + +derive newtype instance + ( DecodeAeson k + , DecodeAeson v + ) => + DecodeAeson (DatumMap k v) + +instance (Show k, Show v) => Show (DatumMap k v) where + show = genericShow + +instance (ToData k, ToData v) => ToData (DatumMap k v) where + toData (DatumMap (AssocMap.Map xs)) = PlutusData.DatumMap + (bimap toData toData <$> xs) + +instance (FromData k, FromData v) => FromData (DatumMap k v) where + fromData (PlutusData.DatumMap mp) = do + (DatumMap <<< AssocMap.Map) <$> + ( for mp \(k /\ v) -> + Tuple <$> fromData k <*> fromData v + ) + -- Since deserialization will utilize `Map` instead of the ad hoc `DatumMap`, + -- a case for `Map` is needed. + fromData (PlutusData.Map mp) = do + (DatumMap <<< AssocMap.Map) <$> + ( for mp \(k /\ v) -> + Tuple <$> fromData k <*> fromData v + ) + fromData _ = Nothing diff --git a/src/Contract/BalanceTxConstraints.purs b/src/Contract/BalanceTxConstraints.purs index ca6afa0075..d7e4ef8eec 100644 --- a/src/Contract/BalanceTxConstraints.purs +++ b/src/Contract/BalanceTxConstraints.purs @@ -10,6 +10,7 @@ import Ctl.Internal.BalanceTx.Constraints , mustSendChangeToAddress , mustUseAdditionalUtxos , mustUseCoinSelectionStrategy + , mustUseCollateralUtxos , mustUseUtxosAtAddress , mustUseUtxosAtAddresses ) as BalanceTxConstraints diff --git a/src/Contract/PlutusData.purs b/src/Contract/PlutusData.purs index 1d5334ea04..960c7fb121 100644 --- a/src/Contract/PlutusData.purs +++ b/src/Contract/PlutusData.purs @@ -89,7 +89,7 @@ import Ctl.Internal.Types.OutputDatum ( OutputDatum(NoOutputDatum, OutputDatumHash, OutputDatum) ) as OutputDatum import Ctl.Internal.Types.PlutusData - ( PlutusData(Constr, Map, List, Integer, Bytes) + ( PlutusData(Constr, DatumMap, Map, List, Integer, Bytes) ) as PlutusData import Ctl.Internal.Types.Redeemer ( Redeemer(Redeemer) diff --git a/src/Internal/ApplyArgs.js b/src/Internal/ApplyArgs.js index 1afe7de8d3..aa924225a8 100644 --- a/src/Internal/ApplyArgs.js +++ b/src/Internal/ApplyArgs.js @@ -3,10 +3,10 @@ let lib; let apply_args; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); apply_args = require("apply-args-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); apply_args = require("apply-args-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/BalanceTx/BalanceTx.purs b/src/Internal/BalanceTx/BalanceTx.purs index e4239ac9e5..22f57cf171 100644 --- a/src/Internal/BalanceTx/BalanceTx.purs +++ b/src/Internal/BalanceTx/BalanceTx.purs @@ -6,6 +6,7 @@ module Ctl.Internal.BalanceTx import Prelude +import Contract.Address (getNetworkId) import Contract.Log (logTrace') import Control.Monad.Error.Class (catchError, liftMaybe, throwError) import Control.Monad.Except.Trans (ExceptT(ExceptT), except, runExceptT) @@ -23,7 +24,12 @@ import Ctl.Internal.BalanceTx.Collateral ( addTxCollateral , addTxCollateralReturn ) -import Ctl.Internal.BalanceTx.Constraints (BalanceTxConstraintsBuilder) +import Ctl.Internal.BalanceTx.Collateral.Select (selectCollateral) +import Ctl.Internal.BalanceTx.Constraints + ( BalanceTxConstraintsBuilder + , _collateralUtxos + , _nonSpendableInputs + ) import Ctl.Internal.BalanceTx.Constraints ( _changeAddress , _maxChangeOutputTokenQuantity @@ -128,9 +134,12 @@ import Ctl.Internal.Contract.Wallet ) as Wallet import Ctl.Internal.Helpers (liftEither, (??)) import Ctl.Internal.Partition (equipartition, partition) -import Ctl.Internal.Plutus.Conversion (toPlutusValue) +import Ctl.Internal.Plutus.Conversion (fromPlutusUtxoMap, toPlutusValue) import Ctl.Internal.Serialization.Address (Address) import Ctl.Internal.Types.OutputDatum (OutputDatum(NoOutputDatum, OutputDatum)) +import Ctl.Internal.Types.ProtocolParameters + ( ProtocolParameters(ProtocolParameters) + ) import Ctl.Internal.Types.Scripts ( Language(PlutusV1) , PlutusScript(PlutusScript) @@ -160,13 +169,14 @@ import Data.Lens.Setter ((%~), (.~), (?~)) import Data.Log.Tag (TagSet) import Data.Log.Tag (fromArray, tag) as TagSet import Data.Map (Map) -import Data.Map (empty, insert, lookup, toUnfoldable, union) as Map +import Data.Map (empty, filterKeys, insert, lookup, toUnfoldable, union) as Map import Data.Maybe (Maybe(Just, Nothing), fromMaybe, isJust, maybe) import Data.Newtype (class Newtype, unwrap, wrap) import Data.Set as Set import Data.Traversable (for, traverse) import Data.Tuple (fst) import Data.Tuple.Nested (type (/\), (/\)) +import Data.UInt (toInt) as UInt import Effect.Aff.Class (liftAff) import Effect.Class (liftEffect) @@ -267,9 +277,29 @@ balanceTxWithConstraints transaction extraUtxos constraintsBuilder = do setTransactionCollateral :: Address -> Transaction -> BalanceTxM Transaction setTransactionCollateral changeAddr transaction = do - collateral <- - liftEitherContract $ note CouldNotGetCollateral <$> - Wallet.getWalletCollateral + nonSpendableSet <- asksConstraints _nonSpendableInputs + mbCollateralUtxos <- asksConstraints _collateralUtxos + -- We must filter out UTxOs that are set as non-spendable in the balancer + -- constraints + let + isSpendable = not <<< flip Set.member nonSpendableSet + collateral <- case mbCollateralUtxos of + -- if no collateral utxos are specified, use the wallet + Nothing -> Array.filter (isSpendable <<< _.input <<< unwrap) <$> do + liftEitherContract $ note CouldNotGetCollateral <$> + Wallet.getWalletCollateral + -- otherwise, get all the utxos, filter out unspendable, and select + -- collateral using internal algo, that is also used in KeyWallet + Just utxoMap -> do + ProtocolParameters params <- liftContract getProtocolParameters + networkId <- liftContract getNetworkId + let + coinsPerUtxoUnit = params.coinsPerUtxoUnit + maxCollateralInputs = UInt.toInt $ params.maxCollateralInputs + utxoMap' = fromPlutusUtxoMap networkId $ Map.filterKeys isSpendable + utxoMap + liftEffect $ Array.fromFoldable <<< fold <$> + selectCollateral coinsPerUtxoUnit maxCollateralInputs utxoMap' addTxCollateralReturn collateral (addTxCollateral collateral transaction) changeAddr diff --git a/src/Internal/BalanceTx/Constraints.purs b/src/Internal/BalanceTx/Constraints.purs index 32b33ec493..35cae944e4 100644 --- a/src/Internal/BalanceTx/Constraints.purs +++ b/src/Internal/BalanceTx/Constraints.purs @@ -8,9 +8,11 @@ module Ctl.Internal.BalanceTx.Constraints , mustSendChangeToAddress , mustUseAdditionalUtxos , mustUseCoinSelectionStrategy + , mustUseCollateralUtxos , mustUseUtxosAtAddress , mustUseUtxosAtAddresses , _additionalUtxos + , _collateralUtxos , _changeAddress , _maxChangeOutputTokenQuantity , _nonSpendableInputs @@ -31,7 +33,7 @@ import Ctl.Internal.Plutus.Types.Address ( Address , AddressWithNetworkTag(AddressWithNetworkTag) ) as Plutus -import Ctl.Internal.Plutus.Types.Transaction (UtxoMap) as Plutus +import Ctl.Internal.Plutus.Types.Transaction (UtxoMap) import Ctl.Internal.Serialization.Address (Address, NetworkId) import Ctl.Internal.Types.Transaction (TransactionInput) import Data.Array (singleton) as Array @@ -42,14 +44,15 @@ import Data.Lens.Iso.Newtype (_Newtype) import Data.Lens.Record (prop) import Data.Lens.Setter (appendOver, set, setJust) import Data.Map (empty) as Map -import Data.Maybe (Maybe(Nothing)) +import Data.Maybe (Maybe(Just, Nothing)) import Data.Newtype (class Newtype, over2, unwrap, wrap) import Data.Set (Set) import Data.Set (singleton) as Set import Type.Proxy (Proxy(Proxy)) newtype BalanceTxConstraints = BalanceTxConstraints - { additionalUtxos :: Plutus.UtxoMap + { additionalUtxos :: UtxoMap + , collateralUtxos :: Maybe UtxoMap , maxChangeOutputTokenQuantity :: Maybe BigInt , nonSpendableInputs :: Set TransactionInput , srcAddresses :: Maybe (Array Address) @@ -59,9 +62,12 @@ newtype BalanceTxConstraints = BalanceTxConstraints derive instance Newtype BalanceTxConstraints _ -_additionalUtxos :: Lens' BalanceTxConstraints Plutus.UtxoMap +_additionalUtxos :: Lens' BalanceTxConstraints UtxoMap _additionalUtxos = _Newtype <<< prop (Proxy :: Proxy "additionalUtxos") +_collateralUtxos :: Lens' BalanceTxConstraints (Maybe UtxoMap) +_collateralUtxos = _Newtype <<< prop (Proxy :: Proxy "collateralUtxos") + _maxChangeOutputTokenQuantity :: Lens' BalanceTxConstraints (Maybe BigInt) _maxChangeOutputTokenQuantity = _Newtype <<< prop (Proxy :: Proxy "maxChangeOutputTokenQuantity") @@ -95,6 +101,7 @@ buildBalanceTxConstraints = applyFlipped defaultConstraints <<< unwrap defaultConstraints :: BalanceTxConstraints defaultConstraints = wrap { additionalUtxos: Map.empty + , collateralUtxos: Nothing , maxChangeOutputTokenQuantity: Nothing , nonSpendableInputs: mempty , srcAddresses: Nothing @@ -156,10 +163,14 @@ mustNotSpendUtxoWithOutRef = mustNotSpendUtxosWithOutRefs <<< Set.singleton -- | execution units (sets `additionalUtxoSet` of Ogmios `EvaluateTx`). -- | Note that you need to use `unspentOutputs` lookup to make these UTxO's -- | spendable by the transaction (see `Examples.TxChaining` for reference). -mustUseAdditionalUtxos :: Plutus.UtxoMap -> BalanceTxConstraintsBuilder +mustUseAdditionalUtxos :: UtxoMap -> BalanceTxConstraintsBuilder mustUseAdditionalUtxos = wrap <<< set _additionalUtxos +-- | Tells the balancer to select from the provided UTxO set when choosing +-- | collateral UTxOs. Disables wallet's collateral selection. +mustUseCollateralUtxos :: UtxoMap -> BalanceTxConstraintsBuilder +mustUseCollateralUtxos = wrap <<< set _collateralUtxos <<< Just + -- | Tells the balancer to use the given strategy for coin selection. mustUseCoinSelectionStrategy :: SelectionStrategy -> BalanceTxConstraintsBuilder mustUseCoinSelectionStrategy = wrap <<< set _selectionStrategy - diff --git a/src/Internal/BalanceTx/ExUnitsAndMinFee.purs b/src/Internal/BalanceTx/ExUnitsAndMinFee.purs index ade5c9ac3c..fb732c4579 100644 --- a/src/Internal/BalanceTx/ExUnitsAndMinFee.purs +++ b/src/Internal/BalanceTx/ExUnitsAndMinFee.purs @@ -8,7 +8,10 @@ import Prelude import Contract.Numeric.Natural (fromInt') as Natural import Control.Monad.Error.Class (throwError) import Control.Monad.Except.Trans (except) -import Ctl.Internal.BalanceTx.Constraints (_additionalUtxos) as Constraints +import Ctl.Internal.BalanceTx.Constraints + ( _additionalUtxos + , _collateralUtxos + ) as Constraints import Ctl.Internal.BalanceTx.Error ( BalanceTxError(UtxoLookupFailedFor, ExUnitsEvaluationFailed) ) @@ -65,7 +68,7 @@ import Data.Either (Either(Left, Right), note) import Data.Foldable (foldMap) import Data.Lens.Getter ((^.)) import Data.Lens.Setter ((?~)) -import Data.Map (empty, fromFoldable, lookup, toUnfoldable) as Map +import Data.Map (empty, fromFoldable, lookup, toUnfoldable, union) as Map import Data.Maybe (Maybe(Just, Nothing), fromMaybe) import Data.Newtype (unwrap, wrap) import Data.Set (Set) @@ -133,8 +136,11 @@ evalExUnitsAndMinFee unattachedTx allUtxos = do additionalUtxos <- fromPlutusUtxoMap networkId <$> asksConstraints Constraints._additionalUtxos + collateralUtxos <- + fromPlutusUtxoMap networkId <<< fromMaybe Map.empty + <$> asksConstraints Constraints._collateralUtxos minFee <- liftContract $ Contract.MinFee.calculateMinFee finalizedTx - additionalUtxos + (Map.union additionalUtxos collateralUtxos) pure $ txWithExUnits /\ unwrap minFee -- | Attaches datums and redeemers, sets the script integrity hash, diff --git a/src/Internal/BalanceTx/UtxoMinAda.js b/src/Internal/BalanceTx/UtxoMinAda.js index 626faddd42..4551b2f876 100644 --- a/src/Internal/BalanceTx/UtxoMinAda.js +++ b/src/Internal/BalanceTx/UtxoMinAda.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Contract/MinFee.purs b/src/Internal/Contract/MinFee.purs index f71ece87a1..7e0f9da5ce 100644 --- a/src/Internal/Contract/MinFee.purs +++ b/src/Internal/Contract/MinFee.purs @@ -9,13 +9,10 @@ import Ctl.Internal.Cardano.Types.Transaction , _collateral , _inputs ) -import Ctl.Internal.Cardano.Types.TransactionUnspentOutput - ( TransactionUnspentOutput - ) import Ctl.Internal.Cardano.Types.Value (Coin) import Ctl.Internal.Contract (getProtocolParameters) import Ctl.Internal.Contract.Monad (Contract, getQueryHandle) -import Ctl.Internal.Contract.Wallet (getWalletAddresses, getWalletCollateral) +import Ctl.Internal.Contract.Wallet (getWalletAddresses) import Ctl.Internal.Helpers (liftM, liftedM) import Ctl.Internal.Serialization.Address ( Address @@ -29,14 +26,14 @@ import Ctl.Internal.Types.Transaction (TransactionInput) import Data.Array (fromFoldable, mapMaybe) import Data.Array as Array import Data.Either (hush) +import Data.Lens (non) import Data.Lens.Getter ((^.)) -import Data.Map (empty, fromFoldable, keys, lookup, values) as Map -import Data.Maybe (fromMaybe, maybe) +import Data.Map (keys, lookup, values) as Map +import Data.Maybe (Maybe(Just, Nothing)) import Data.Newtype (unwrap) import Data.Set (Set) import Data.Set (difference, fromFoldable, intersection, mapMaybe, union) as Set import Data.Traversable (for) -import Data.Tuple.Nested ((/\)) import Effect.Aff (error) import Effect.Aff.Class (liftAff) @@ -47,6 +44,8 @@ calculateMinFee tx additionalUtxos = do pparams <- getProtocolParameters calculateMinFeeCsl pparams selfSigners tx +-- | This function estimates the set of keys that must be used +-- | for signing to make the transaction valid for the network. getSelfSigners :: Transaction -> UtxoMap -> Contract (Set Ed25519KeyHash) getSelfSigners tx additionalUtxos = do queryHandle <- getQueryHandle @@ -64,31 +63,33 @@ getSelfSigners tx additionalUtxos = do (_.address <<< unwrap) <$> Map.values additionalUtxos (inUtxosAddrs :: Set Address) <- setFor txInputs $ \txInput -> - liftedM (error $ "Couldn't get tx output for " <> show txInput) $ - (map <<< map) (_.address <<< unwrap) - (liftAff $ queryHandle.getUtxoByOref txInput <#> hush >>> join) + liftedM (error $ "Couldn't get tx output for " <> show txInput) + $ (map <<< map) (_.address <<< unwrap) + $ case Map.lookup txInput additionalUtxos of + Nothing -> + liftAff (queryHandle.getUtxoByOref txInput <#> hush >>> join) + Just utxo -> pure $ Just utxo - -- Get all tx output addressses let - txCollats :: Set TransactionInput - txCollats = Set.fromFoldable <<< fromMaybe [] $ tx ^. _body <<< _collateral - - walletCollats <- maybe Map.empty toUtxoMap <$> getWalletCollateral + collateralInputs = tx ^. _body <<< _collateral <<< non [] - (inCollatAddrs :: Set Address) <- setFor txCollats - ( \txCollat -> - liftM (error $ "Couldn't get tx output for " <> show txCollat) - $ (map (_.address <<< unwrap) <<< Map.lookup txCollat) - $ walletCollats - ) + (collateralAddresses :: Set Address) <- + setFor (Set.fromFoldable collateralInputs) $ \txInput -> + liftedM (error $ "Couldn't get tx output for " <> show txInput) + $ (map <<< map) (_.address <<< unwrap) + $ case Map.lookup txInput additionalUtxos of + Nothing -> + liftAff (queryHandle.getUtxoByOref txInput <#> hush >>> join) + Just utxo -> pure $ Just utxo -- Get own addressses (ownAddrs :: Set Address) <- Set.fromFoldable <$> getWalletAddresses -- Combine to get all self tx input addresses let - txOwnAddrs = ownAddrs `Set.intersection` - (additionalUtxosAddrs `Set.union` inUtxosAddrs `Set.union` inCollatAddrs) + txOwnAddrs = + (additionalUtxosAddrs `Set.union` ownAddrs) `Set.intersection` + (inUtxosAddrs `Set.union` collateralAddresses) -- Extract payment pub key hashes from addresses. paymentPkhs <- map (Set.mapMaybe identity) $ setFor txOwnAddrs $ \addr -> do @@ -116,7 +117,3 @@ getSelfSigners tx additionalUtxos = do -> (a -> m b) -> m (Set b) setFor txIns f = Set.fromFoldable <$> for (fromFoldable txIns) f - - toUtxoMap :: Array TransactionUnspentOutput -> UtxoMap - toUtxoMap = Map.fromFoldable <<< map - (unwrap >>> \({ input, output }) -> input /\ output) diff --git a/src/Internal/Deserialization/FromBytes.js b/src/Internal/Deserialization/FromBytes.js index 802458ed31..6130154525 100644 --- a/src/Internal/Deserialization/FromBytes.js +++ b/src/Internal/Deserialization/FromBytes.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Deserialization/FromBytes.purs b/src/Internal/Deserialization/FromBytes.purs index 5406e8d564..45af0f6eb9 100644 --- a/src/Internal/Deserialization/FromBytes.purs +++ b/src/Internal/Deserialization/FromBytes.purs @@ -26,6 +26,7 @@ import Ctl.Internal.Serialization.Types , Mint , NativeScript , PlutusData + , PlutusDatumMap , PoolMetadataHash , PublicKey , Redeemers @@ -93,6 +94,9 @@ instance FromBytes NativeScript where instance FromBytes PlutusData where fromBytes' = fromBytesImpl "PlutusData" +instance FromBytes PlutusDatumMap where + fromBytes' = fromBytesImpl "PlutusDatumMap" + instance FromBytes PoolMetadataHash where fromBytes' = fromBytesImpl "PoolMetadataHash" @@ -165,4 +169,4 @@ foreign import _fromBytes . ErrorFfiHelper r -> String -> ByteArray - -> E r a + -> E r a \ No newline at end of file diff --git a/src/Internal/Deserialization/Keys.js b/src/Internal/Deserialization/Keys.js index 51a83714d3..dd163b3933 100644 --- a/src/Internal/Deserialization/Keys.js +++ b/src/Internal/Deserialization/Keys.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Deserialization/Language.js b/src/Internal/Deserialization/Language.js index b2d596da37..5d32f78298 100644 --- a/src/Internal/Deserialization/Language.js +++ b/src/Internal/Deserialization/Language.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Deserialization/NativeScript.js b/src/Internal/Deserialization/NativeScript.js index 567e648715..34703265f2 100644 --- a/src/Internal/Deserialization/NativeScript.js +++ b/src/Internal/Deserialization/NativeScript.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Deserialization/PlutusData.js b/src/Internal/Deserialization/PlutusData.js index 5542bdd10c..aa85f6e8d7 100644 --- a/src/Internal/Deserialization/PlutusData.js +++ b/src/Internal/Deserialization/PlutusData.js @@ -2,18 +2,23 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); +const plutusDataAs = what => helper => data => { + const res = data["as_" + what](); + return res == null ? helper.nothing : helper.just(res); +}; + exports._convertPlutusData = handle => pd => { switch (pd.kind()) { case lib.PlutusDataKind.ConstrPlutusData: return handle.constr(pd.as_constr_plutus_data()); case lib.PlutusDataKind.Map: - return handle.map(pd.as_map()); + return handle.map(pd); case lib.PlutusDataKind.List: return handle.list(pd.as_list()); case lib.PlutusDataKind.Integer: @@ -25,6 +30,8 @@ exports._convertPlutusData = handle => pd => { } }; +exports._PlutusData_originalBytes = plutusDataAs("original_bytes"); +exports._PlutusData_map = plutusDataAs("map"); exports._unpackPlutusList = containerHelper => containerHelper.unpack; exports._ConstrPlutusData_alternative = x => x.alternative(); exports._ConstrPlutusData_data = x => x.data(); @@ -39,3 +46,14 @@ exports._unpackPlutusMap = containerHelper => tuple => plutusMap => { } return res; }; + +exports._unpackPlutusDatumMap = containerHelper => tuple => plutusDatumMap => { + const keys = containerHelper.unpack(plutusDatumMap.keys()); + const res = []; + for (let key of keys) { + // Assuming that `PlutusMap.get()` never fails on elements from result of + // its `.keys()` call. + res.push(tuple(key)(plutusDatumMap.get(key))); + } + return res; +}; diff --git a/src/Internal/Deserialization/PlutusData.purs b/src/Internal/Deserialization/PlutusData.purs index 7a87147968..c7ad251f29 100644 --- a/src/Internal/Deserialization/PlutusData.purs +++ b/src/Internal/Deserialization/PlutusData.purs @@ -9,30 +9,33 @@ import Ctl.Internal.Deserialization.BigInt (convertBigInt) import Ctl.Internal.Deserialization.FromBytes (fromBytes) import Ctl.Internal.FfiHelpers ( ContainerHelper + , MaybeFfiHelper , containerHelper + , maybeFfiHelper ) import Ctl.Internal.FromData (class FromData, fromData) import Ctl.Internal.Serialization.Types ( BigInt , ConstrPlutusData , PlutusData + , PlutusDatumMap , PlutusList , PlutusMap ) import Ctl.Internal.Types.BigNum (BigNum) import Ctl.Internal.Types.ByteArray (ByteArray) -import Ctl.Internal.Types.CborBytes (CborBytes) +import Ctl.Internal.Types.CborBytes (CborBytes(CborBytes)) import Ctl.Internal.Types.PlutusData ( PlutusData(Constr, Map, List, Integer, Bytes) ) as T -import Data.Maybe (Maybe, fromJust) +import Data.Maybe (Maybe(Just, Nothing), fromJust) import Data.Tuple (Tuple(Tuple)) import Data.Tuple.Nested (type (/\), (/\)) import Partial.Unsafe (unsafePartial) type ConvertPlutusData = { constr :: ConstrPlutusData -> T.PlutusData - , map :: PlutusMap -> T.PlutusData + , map :: PlutusData -> T.PlutusData , list :: PlutusList -> T.PlutusData , integer :: BigInt -> T.PlutusData , bytes :: ByteArray -> T.PlutusData @@ -41,7 +44,7 @@ type ConvertPlutusData = convertPlutusData :: PlutusData -> T.PlutusData convertPlutusData pd = _convertPlutusData { constr: convertPlutusConstr - , map: convertPlutusMap + , map: convertMap , list: convertPlutusList , integer: convertPlutusInteger , bytes: convertPlutusBytes @@ -56,12 +59,33 @@ convertPlutusConstr constr = do alt = _ConstrPlutusData_alternative constr T.Constr alt data' -convertPlutusMap :: PlutusMap -> T.PlutusData -convertPlutusMap = - _unpackPlutusMap containerHelper Tuple - >>> map - (\(k /\ v) -> (convertPlutusData k /\ convertPlutusData v)) - >>> T.Map +-- With no good way of knowing the data types that are contained in a map defore +-- deserialization, we can assume that CSL's default map deserialization should +-- be used, unless the original bytes of the `PlutusData` is provided to CSL. +-- The key-value pairs should be returned unsorted by defalut, since CSL should +-- always be storing the original bytes while deserializing `PlutusData`. The +-- output of `convertMap` should be `Map` instead of the ad hoc `DatumMap`, +-- since a CBOR map is not limited to a datum. +convertMap :: PlutusData -> T.PlutusData +convertMap pd = do + case getOriginalBytes pd of + Just (bytes) -> unsafePartial $ fromJust $ convertDatumMap bytes + Nothing -> unsafePartial $ fromJust $ convertPlutusMap pd + +convertDatumMap :: ByteArray -> Maybe T.PlutusData +convertDatumMap bytes = do + entries <- + (fromBytes (CborBytes bytes) :: Maybe PlutusDatumMap) <#> + _unpackPlutusDatumMap containerHelper Tuple >>> map + \(k /\ v) -> (convertPlutusData k /\ convertPlutusData v) + pure $ T.Map entries + +convertPlutusMap :: PlutusData -> Maybe T.PlutusData +convertPlutusMap pd = do + entries <- _PlutusData_map maybeFfiHelper pd <#> + _unpackPlutusMap containerHelper Tuple >>> map + \(k /\ v) -> (convertPlutusData k /\ convertPlutusData v) + pure $ T.Map entries convertPlutusList :: PlutusList -> T.PlutusData convertPlutusList = @@ -78,6 +102,15 @@ convertPlutusBytes = T.Bytes deserializeData :: forall (a :: Type). FromData a => CborBytes -> Maybe a deserializeData = fromData <<< convertPlutusData <=< fromBytes +getOriginalBytes :: PlutusData -> Maybe ByteArray +getOriginalBytes = _PlutusData_originalBytes maybeFfiHelper + +foreign import _PlutusData_map + :: MaybeFfiHelper -> PlutusData -> Maybe PlutusMap + +foreign import _PlutusData_originalBytes + :: MaybeFfiHelper -> PlutusData -> Maybe ByteArray + foreign import _convertPlutusData :: ConvertPlutusData -> PlutusData -> T.PlutusData @@ -91,3 +124,9 @@ foreign import _unpackPlutusMap -> (forall a b. a -> b -> Tuple a b) -> PlutusMap -> Array (PlutusData /\ PlutusData) + +foreign import _unpackPlutusDatumMap + :: ContainerHelper + -> (forall a b. a -> b -> Tuple a b) + -> PlutusDatumMap + -> Array (PlutusData /\ PlutusData) diff --git a/src/Internal/Deserialization/Transaction.js b/src/Internal/Deserialization/Transaction.js index e0f990c2e5..75174a8ccf 100644 --- a/src/Internal/Deserialization/Transaction.js +++ b/src/Internal/Deserialization/Transaction.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Deserialization/UnspentOutput.js b/src/Internal/Deserialization/UnspentOutput.js index e87e5eb37d..d4cf3703c6 100644 --- a/src/Internal/Deserialization/UnspentOutput.js +++ b/src/Internal/Deserialization/UnspentOutput.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Deserialization/WitnessSet.js b/src/Internal/Deserialization/WitnessSet.js index 752cc47bc0..b72dac2541 100644 --- a/src/Internal/Deserialization/WitnessSet.js +++ b/src/Internal/Deserialization/WitnessSet.js @@ -1,3 +1,12 @@ +/* global BROWSER_RUNTIME */ + +let lib; +if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { + lib = require("@mitchycola/cardano-serialization-lib-browser"); +} else { + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); +} + const call = property => object => object[property](); const callMaybe = property => maybe => object => { diff --git a/src/Internal/Hashing.js b/src/Internal/Hashing.js index 0d9f2065d0..f6fddc4bfc 100644 --- a/src/Internal/Hashing.js +++ b/src/Internal/Hashing.js @@ -6,9 +6,9 @@ const SHA3 = require("jssha/dist/sha3"); let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); @@ -20,6 +20,14 @@ exports.blake2b224HashHex = bytesToHash => { return Blake2.blake2bHex(bytesToHash, null, 28); }; +exports.blake2b224Hash = bytesToHash => { + return Blake2.blake2b(bytesToHash, null, 28); +}; + +exports.blake2b224HashHex = bytesToHash => { + return Blake2.blake2bHex(bytesToHash, null, 28); +}; + exports.blake2b256Hash = bytesToHash => { return Blake2.blake2b(bytesToHash, null, 32); }; diff --git a/src/Internal/Plutip/Server.purs b/src/Internal/Plutip/Server.purs index bf41d6961c..30240b173a 100644 --- a/src/Internal/Plutip/Server.purs +++ b/src/Internal/Plutip/Server.purs @@ -7,6 +7,7 @@ module Ctl.Internal.Plutip.Server , checkPlutipServer , stopChildProcessWithPort , testPlutipContracts + , testPlutipContracts' ) where import Prelude @@ -154,7 +155,14 @@ testPlutipContracts -> TestPlanM ContractTest Unit -> TestPlanM (Aff Unit) Unit testPlutipContracts plutipCfg tp = do - ContractTestPlan runContractTestPlan <- lift $ execDistribution tp + contractTestPlan <- lift $ execDistribution tp + testPlutipContracts' plutipCfg contractTestPlan + +testPlutipContracts' + :: PlutipConfig + -> ContractTestPlan + -> TestPlanM (Aff Unit) Unit +testPlutipContracts' plutipCfg (ContractTestPlan runContractTestPlan) = do runContractTestPlan \distr tests -> do cleanupRef <- liftEffect $ Ref.new mempty bracket (startPlutipContractEnv plutipCfg distr cleanupRef) diff --git a/src/Internal/QueryM.purs b/src/Internal/QueryM.purs index 72a3e25b47..c0165cd251 100644 --- a/src/Internal/QueryM.purs +++ b/src/Internal/QueryM.purs @@ -5,15 +5,15 @@ module Ctl.Internal.QueryM ( module ExportDispatcher , module ExportServerConfig + , QueryConfig , ClusterSetup , ListenerSet , OgmiosListeners , OgmiosWebSocket - , QueryConfig - , QueryM , ParQueryM , QueryMT(QueryMT) , QueryEnv + , QueryM , QueryRuntime , SubmitTxListenerSet , WebSocket(WebSocket) @@ -35,6 +35,10 @@ module Ctl.Internal.QueryM , scriptToAeson , submitTxOgmios , underlyingWebSocket + , mempoolSnapshotSizeAndCapacityAff + , releaseMempoolAff + , mempoolSnapshotNextTxAff + , acquireMempoolSnapshotAff ) where import Prelude @@ -354,6 +358,36 @@ mempoolSnapshotHasTxAff ogmiosWs logger ms = mkOgmiosRequestAff ogmiosWs logger (Ogmios.mempoolSnapshotHasTxCall ms) _.mempoolHasTx +mempoolSnapshotSizeAndCapacityAff + :: OgmiosWebSocket + -> Logger + -> Ogmios.MempoolSnapshotAcquired + -> Aff Ogmios.MempoolSizeAndCapacity +mempoolSnapshotSizeAndCapacityAff ogmiosWs logger ms = + mkOgmiosRequestAff ogmiosWs logger (Ogmios.mempoolSnpashotSizeAndCapacityCall ms) + _.mempoolSizeAndCapcity + unit + +releaseMempoolAff + :: OgmiosWebSocket + -> Logger + -> Ogmios.MempoolSnapshotAcquired + -> Aff Ogmios.MempoolReleased +releaseMempoolAff ogmiosWs logger ms = + mkOgmiosRequestAff ogmiosWs logger (Ogmios.releaseMempoolCall ms) + _.releaseMempool + unit + +mempoolSnapshotNextTxAff + :: OgmiosWebSocket + -> Logger + -> Ogmios.MempoolSnapshotAcquired + -> Aff (Maybe Ogmios.MempoolTransaction) +mempoolSnapshotNextTxAff ogmiosWs logger ms = + mkOgmiosRequestAff ogmiosWs logger (Ogmios.mempoolSnapshotNextTxCall ms) + _.mempoolNextTx + unit + -------------------------------------------------------------------------------- -- Affjax -------------------------------------------------------------------------------- @@ -587,8 +621,14 @@ mkOgmiosWebSocketLens logger isTxConfirmed = do mkListenerSet dispatcher pendingRequests , acquireMempool: mkListenerSet dispatcher pendingRequests + , releaseMempool: + mkListenerSet dispatcher pendingRequests , mempoolHasTx: mkListenerSet dispatcher pendingRequests + , mempoolNextTx: + mkListenerSet dispatcher pendingRequests + , mempoolSizeAndCapcity: + mkListenerSet dispatcher pendingRequests , submit: mkSubmitTxListenerSet dispatcher pendingSubmitTxRequests , poolIds: @@ -630,7 +670,10 @@ type OgmiosListeners = , currentEpoch :: ListenerSet Unit Ogmios.CurrentEpoch , systemStart :: ListenerSet Unit Ogmios.OgmiosSystemStart , acquireMempool :: ListenerSet Unit Ogmios.MempoolSnapshotAcquired + , releaseMempool :: ListenerSet Unit Ogmios.MempoolReleased , mempoolHasTx :: ListenerSet TxHash Boolean + , mempoolNextTx :: ListenerSet Unit (Maybe Ogmios.MempoolTransaction) + , mempoolSizeAndCapcity :: ListenerSet Unit Ogmios.MempoolSizeAndCapacity , poolIds :: ListenerSet Unit PoolIdsR , poolParameters :: ListenerSet (Array PoolPubKeyHash) PoolParametersR , delegationsAndRewards :: ListenerSet (Array String) DelegationsAndRewardsR diff --git a/src/Internal/QueryM/Ogmios.purs b/src/Internal/QueryM/Ogmios.purs index 408b5ad26e..cd83ffc036 100644 --- a/src/Internal/QueryM/Ogmios.purs +++ b/src/Internal/QueryM/Ogmios.purs @@ -1,13 +1,18 @@ -- | Provides types and instances to create Ogmios requests and decode -- | its responses. module Ctl.Internal.QueryM.Ogmios - ( ChainOrigin(ChainOrigin) + ( AdditionalUtxoSet(..) + , ChainOrigin(..) , ChainPoint , ChainTipQR(CtChainOrigin, CtChainPoint) , CurrentEpoch(CurrentEpoch) , DelegationsAndRewardsR(DelegationsAndRewardsR) , ExecutionUnits + , MempoolReleased(..) + , MempoolSizeAndCapacity(..) , MempoolSnapshotAcquired + , MempoolTransaction(..) + , MempoolTxBody(..) , OgmiosAddress , OgmiosBlockHeaderHash(OgmiosBlockHeaderHash) , OgmiosTxOut @@ -40,19 +45,32 @@ module Ctl.Internal.QueryM.Ogmios , TxEvaluationResult(TxEvaluationResult) , TxEvaluationR(TxEvaluationR) , PoolIdsR + , PoolParameters + , PoolParametersR(..) + , RedeemerPointer + , ScriptFailure(..) + , SubmitTxR(..) + , TxEvaluationFailure(..) + , TxEvaluationR(..) + , TxEvaluationResult(..) , TxHash - , UtxoQR(UtxoQR) + , UtxoQR(..) , UtxoQueryResult , acquireMempoolSnapshotCall , aesonArray , aesonObject , evaluateTxCall - , queryPoolIdsCall , mempoolSnapshotHasTxCall + , mempoolSnapshotNextTxCall + , mempoolSnpashotSizeAndCapacityCall , mkOgmiosCallType + , parseIpv6String , queryChainTipCall , queryCurrentEpochCall + , queryDelegationsAndRewards , queryEraSummariesCall + , queryPoolIdsCall + , queryPoolParameters , queryProtocolParametersCall , querySystemStartCall , queryPoolParameters @@ -61,6 +79,7 @@ module Ctl.Internal.QueryM.Ogmios , slotLengthFactor , parseIpv6String , rationalToSubcoin + , releaseMempoolCall ) where import Prelude @@ -69,7 +88,7 @@ import Aeson ( class DecodeAeson , class EncodeAeson , Aeson - , JsonDecodeError(AtKey, TypeMismatch, MissingValue) + , JsonDecodeError(AtKey, TypeMismatch, MissingValue, UnexpectedValue) , caseAesonArray , caseAesonObject , caseAesonString @@ -103,7 +122,8 @@ import Ctl.Internal.Cardano.Types.ScriptRef ( ScriptRef(NativeScriptRef, PlutusScriptRef) ) import Ctl.Internal.Cardano.Types.Transaction - ( Costmdls(Costmdls) + ( AuxiliaryData + , Costmdls(Costmdls) , ExUnitPrices , ExUnits , Ipv4(Ipv4) @@ -113,6 +133,7 @@ import Ctl.Internal.Cardano.Types.Transaction , PoolPubKeyHash , Relay(MultiHostName, SingleHostAddr, SingleHostName) , SubCoin + , TransactionWitnessSet , URL(URL) , UnitInterval ) @@ -176,6 +197,7 @@ import Ctl.Internal.Types.SystemStart ) import Ctl.Internal.Types.TokenName (TokenName, getTokenName, mkTokenName) import Ctl.Internal.Types.VRFKeyHash (VRFKeyHash(VRFKeyHash)) +import Data.Argonaut (fromString) as JSON import Data.Array (catMaybes, index) import Data.Array (head, length, replicate) as Array import Data.Bifunctor (lmap) @@ -317,6 +339,23 @@ mempoolSnapshotHasTxCall _ = mkOgmiosCallType , args: { id: _ } } +mempoolSnapshotNextTxCall + :: MempoolSnapshotAcquired -> JsonWspCall Unit (Maybe MempoolTransaction) +mempoolSnapshotNextTxCall _ = mkOgmiosCallType + { methodname: "NextTx" + , args: const { fields: "all" } + } + +mempoolSnpashotSizeAndCapacityCall + :: MempoolSnapshotAcquired -> JsonWspCall Unit MempoolSizeAndCapacity +mempoolSnpashotSizeAndCapacityCall _ = + mkOgmiosCallTypeNoArgs "SizeAndCapacity" + +releaseMempoolCall + :: MempoolSnapshotAcquired -> JsonWspCall Unit MempoolReleased +releaseMempoolCall _ = + mkOgmiosCallTypeNoArgs "ReleaseMempool" + -------------------------------------------------------------------------------- -- Local Tx Monitor Query Response & Parsing -------------------------------------------------------------------------------- @@ -331,6 +370,116 @@ instance DecodeAeson MempoolSnapshotAcquired where map AwaitAcquired <<< aesonObject (flip getField "AwaitAcquired" >=> flip getField "slot") +-- | The acquired snapshot’s size (in bytes), number of transactions, and capacity +-- | (in bytes). +newtype MempoolSizeAndCapacity = MempoolSizeAndCapacity + { capacity :: BigInt + , currentSize :: BigInt + , numberOfTxs :: BigInt + } + +derive instance Generic MempoolSizeAndCapacity _ +derive instance Newtype MempoolSizeAndCapacity _ +instance Show MempoolSizeAndCapacity where + show = genericShow + +instance DecodeAeson MempoolSizeAndCapacity where + decodeAeson = aesonObject $ \o -> do + capacity <- getField o "capacity" + currentSize <- getField o "currentSize" + numberOfTxs <- getField o "numberOfTxs" + + pure $ wrap {capacity, currentSize, numberOfTxs} + +data MempoolReleased = Released + +-- Ogmios only has a single response for releasing the mempool +-- https://github.com/CardanoSolutions/ogmios/blob/d326d8839d50ff628f7be1b5552f7cd22b2f094e/server/src/Ogmios/Data/Protocol/StateQuery.hs#L231 +instance DecodeAeson MempoolReleased where + decodeAeson = aesonString $ \a -> case a of + "Released" -> Right Released + _ -> Left $ UnexpectedValue $ JSON.fromString a + +instance Show MempoolReleased where + show Released = "Mempool Released" + +newtype MempoolTransaction = MempoolTransaction + { id :: OgmiosTxId + -- , inputSource :: InputSource + , body :: MempoolTxBody + -- , witness :: MempoolWitnessSet + -- , metadata :: Maybe MempoolAuxiliaryData + -- , raw :: String + } + +derive instance Generic MempoolTransaction _ +derive instance Newtype MempoolTransaction _ +instance Show MempoolTransaction where + show = genericShow + +instance DecodeAeson MempoolTransaction where + decodeAeson = aesonObject $ \o -> do + id <- getField o "id" + body <- getField o "body" + pure $ MempoolTransaction { id, body } + +newtype MempoolTxBody = MempoolTxBody + { inputs :: Array OgmiosTxOutRef + -- , collaterals :: Array OgmiosTxOutRef + , outputs :: Array OgmiosTxOut + -- , certificates :: Array Certificate + -- , withdrawls :: Map OgmiosRewardAddress BigInt + -- , fee :: BigInt + -- , validityInterval :: ValidityInterval + -- , update :: Maybe Update + -- , mint :: Maybe Value + -- , network :: Maybe NetworkId + -- , scriptIntegrityHash :: Maybe String + -- , requiredExtraSignatures :: Array OgmiosRequiredSigner + } + +derive instance Generic MempoolTxBody _ +derive instance Newtype MempoolTxBody _ +instance Show MempoolTxBody where + show = genericShow + +instance DecodeAeson MempoolTxBody where + decodeAeson = aesonObject $ \o -> do + inputs <- aesonArray (traverse parseTxOutRef) =<< getField o "inputs" + outputs <- aesonArray (traverse parseTxOut) =<< getField o "outputs" + pure $ MempoolTxBody { inputs, outputs } + +data InputSource = Inputs | Collaterals +type OgmiosRewardAddress = String +type OgmiosRequiredSigner = String +newtype MempoolWitnessSet = MempoolWitnessSet TransactionWitnessSet + +type MempoolAuxiliaryData = + { hash :: String + , body :: AuxiliaryData + } + +type ValidityInterval = + { invalidBefore :: Maybe BigInt + , invalidHereafter :: Maybe BigInt + } + +-- parser for ValidityInterval +parseValidityInterval :: Aeson -> Either JsonDecodeError ValidityInterval +parseValidityInterval = aesonObject $ \o -> do + invalidBefore <- getFieldOptional o "invalidBefore" + invalidHereafter <- getFieldOptional o "invalidHereafter" + pure { invalidBefore, invalidHereafter } + +-- parser for InputSource +parseInputSource :: Aeson -> Either JsonDecodeError InputSource +parseInputSource = aesonObject $ \o -> do + inputSource <- getField o "invalidSource" + case inputSource of + "inputs" -> Right Inputs + "outputs" -> Right Collaterals + _ -> Left $ UnexpectedValue $ JSON.fromString inputSource + -------------------------------------------------------------------------------- -- Helpers -------------------------------------------------------------------------------- @@ -1117,6 +1266,14 @@ aesonArray -> Either JsonDecodeError a aesonArray = caseAesonArray (Left (TypeMismatch "Expected Array")) +-- helper for assuming we get an string +aesonString + :: forall (a :: Type) + . (String -> Either JsonDecodeError a) + -> Aeson + -> Either JsonDecodeError a +aesonString = caseAesonString (Left (TypeMismatch "Expected String")) + -- parser for txOutRef parseTxOutRef :: Aeson -> Either JsonDecodeError OgmiosTxOutRef parseTxOutRef = aesonObject $ \o -> do diff --git a/src/Internal/Serialization.js b/src/Internal/Serialization.js index d66f01e93e..3302ee47a2 100644 --- a/src/Internal/Serialization.js +++ b/src/Internal/Serialization.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Serialization/Address.js b/src/Internal/Serialization/Address.js index b9f664e970..cd1c178067 100644 --- a/src/Internal/Serialization/Address.js +++ b/src/Internal/Serialization/Address.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Serialization/AuxiliaryData.js b/src/Internal/Serialization/AuxiliaryData.js index 130262830e..8d8a566f04 100644 --- a/src/Internal/Serialization/AuxiliaryData.js +++ b/src/Internal/Serialization/AuxiliaryData.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Serialization/BigInt.js b/src/Internal/Serialization/BigInt.js index 6997bf4af6..a9dbd42a82 100644 --- a/src/Internal/Serialization/BigInt.js +++ b/src/Internal/Serialization/BigInt.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Serialization/Hash.js b/src/Internal/Serialization/Hash.js index 88a7af703b..5d03d2d764 100644 --- a/src/Internal/Serialization/Hash.js +++ b/src/Internal/Serialization/Hash.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Serialization/MinFee.js b/src/Internal/Serialization/MinFee.js index c24676a3a7..f428f84bed 100644 --- a/src/Internal/Serialization/MinFee.js +++ b/src/Internal/Serialization/MinFee.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Serialization/NativeScript.js b/src/Internal/Serialization/NativeScript.js index ea4f798a5d..73e1db20f2 100644 --- a/src/Internal/Serialization/NativeScript.js +++ b/src/Internal/Serialization/NativeScript.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Serialization/PlutusData.js b/src/Internal/Serialization/PlutusData.js index 580cdcfddc..3a68ec5b47 100644 --- a/src/Internal/Serialization/PlutusData.js +++ b/src/Internal/Serialization/PlutusData.js @@ -2,15 +2,16 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); exports._mkPlutusData_bytes = bytes => lib.PlutusData.new_bytes(bytes); exports._mkPlutusData_list = list => lib.PlutusData.new_list(list); -exports._mkPlutusData_map = list => lib.PlutusData.new_map(list); +exports._mkPlutusData_map = map => lib.PlutusData.new_map(map); +exports._mkPlutusData_datumMap = cbor => lib.PlutusData.new_datum_map(cbor); exports._mkPlutusData_integer = int => lib.PlutusData.new_integer(int); exports._mkPlutusData_constr = constr => lib.PlutusData.new_constr_plutus_data(constr); @@ -34,3 +35,11 @@ exports._packMap = first => second => kvs => { } return res; }; + +exports._packDatumMap = first => second => kvs => { + const res = lib.PlutusDatumMap.new(); + for (let kv of kvs) { + res.insert(first(kv), second(kv)); + } + return res; +}; diff --git a/src/Internal/Serialization/PlutusData.purs b/src/Internal/Serialization/PlutusData.purs index b607fc2069..61f5deb8e6 100644 --- a/src/Internal/Serialization/PlutusData.purs +++ b/src/Internal/Serialization/PlutusData.purs @@ -1,5 +1,6 @@ module Ctl.Internal.Serialization.PlutusData ( convertPlutusData + , convertPlutusDatumMap , packPlutusList ) where @@ -11,10 +12,12 @@ import Ctl.Internal.FfiHelpers , containerHelper , maybeFfiHelper ) +import Ctl.Internal.Serialization.ToBytes (toBytes') import Ctl.Internal.Serialization.Types ( BigInt , ConstrPlutusData , PlutusData + , PlutusDatumMap , PlutusList , PlutusMap ) @@ -26,10 +29,12 @@ import Data.Maybe (Maybe, fromJust) import Data.Tuple (Tuple, fst, snd) import Data.Tuple.Nested (type (/\), (/\)) import Partial.Unsafe (unsafePartial) +import Untagged.Union (asOneOf) convertPlutusData :: T.PlutusData -> PlutusData convertPlutusData x = case x of T.Constr alt list -> convertConstr alt list + T.DatumMap mp -> convertPlutusDatumMap mp T.Map mp -> convertPlutusMap mp T.List lst -> convertPlutusList lst T.Integer n -> convertPlutusInteger n @@ -54,6 +59,15 @@ convertPlutusMap mp = in _mkPlutusData_map $ _packMap fst snd entries +convertPlutusDatumMap + :: Array (T.PlutusData /\ T.PlutusData) -> PlutusData +convertPlutusDatumMap mp = + let + entries :: Array (PlutusData /\ PlutusData) + entries = mp <#> \(k /\ v) -> (convertPlutusData k /\ convertPlutusData v) + in + _mkPlutusData_datumMap $ toBytes' $ asOneOf $ _packDatumMap fst snd entries + convertPlutusInteger :: BigInt.BigInt -> PlutusData convertPlutusInteger n = _mkPlutusData_integer $ convertBigInt n @@ -72,6 +86,7 @@ packPlutusList = (_packPlutusList containerHelper) foreign import _mkPlutusData_bytes :: ByteArray -> PlutusData foreign import _mkPlutusData_list :: PlutusList -> PlutusData foreign import _mkPlutusData_map :: PlutusMap -> PlutusData +foreign import _mkPlutusData_datumMap :: ByteArray -> PlutusData foreign import _mkPlutusData_integer :: BigInt -> PlutusData foreign import _mkPlutusData_constr :: ConstrPlutusData -> PlutusData @@ -85,3 +100,9 @@ foreign import _packMap -> (forall a b. Tuple a b -> b) -> Array (PlutusData /\ PlutusData) -> PlutusMap + +foreign import _packDatumMap + :: (forall a b. Tuple a b -> a) + -> (forall a b. Tuple a b -> b) + -> Array (PlutusData /\ PlutusData) + -> PlutusDatumMap diff --git a/src/Internal/Serialization/PlutusScript.js b/src/Internal/Serialization/PlutusScript.js index af3c7ec8ca..1f2f3bed72 100644 --- a/src/Internal/Serialization/PlutusScript.js +++ b/src/Internal/Serialization/PlutusScript.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Serialization/ToBytes.purs b/src/Internal/Serialization/ToBytes.purs index f46868ccd8..bbf2cd8602 100644 --- a/src/Internal/Serialization/ToBytes.purs +++ b/src/Internal/Serialization/ToBytes.purs @@ -1,5 +1,6 @@ module Ctl.Internal.Serialization.ToBytes ( toBytes + , toBytes' ) where import Prelude @@ -19,6 +20,7 @@ import Ctl.Internal.Serialization.Types , Mint , NativeScript , PlutusData + , PlutusDatumMap , PoolMetadataHash , Redeemers , ScriptDataHash @@ -48,6 +50,7 @@ type SerializableData = Address |+| Mint |+| NativeScript |+| PlutusData + |+| PlutusDatumMap |+| PoolMetadataHash |+| Redeemers |+| ScriptDataHash @@ -76,3 +79,8 @@ toBytes => a -> CborBytes toBytes = CborBytes <<< _toBytes + +toBytes' + :: SerializableData + -> ByteArray +toBytes' = _toBytes \ No newline at end of file diff --git a/src/Internal/Serialization/Types.purs b/src/Internal/Serialization/Types.purs index 9cafb8706b..a55e257d07 100644 --- a/src/Internal/Serialization/Types.purs +++ b/src/Internal/Serialization/Types.purs @@ -38,6 +38,7 @@ module Ctl.Internal.Serialization.Types , NetworkId , Nonce , PlutusData + , PlutusDatumMap , PlutusList , PlutusMap , PlutusScript @@ -123,6 +124,7 @@ foreign import data NativeScripts :: Type foreign import data NetworkId :: Type foreign import data Nonce :: Type foreign import data PlutusData :: Type +foreign import data PlutusDatumMap :: Type foreign import data PlutusList :: Type foreign import data PlutusMap :: Type foreign import data PlutusScript :: Type diff --git a/src/Internal/Serialization/WitnessSet.js b/src/Internal/Serialization/WitnessSet.js index 8596ffc6aa..ffd6446300 100644 --- a/src/Internal/Serialization/WitnessSet.js +++ b/src/Internal/Serialization/WitnessSet.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Test/ContractTest.purs b/src/Internal/Test/ContractTest.purs index 683a2f7bde..e75f80aecd 100644 --- a/src/Internal/Test/ContractTest.purs +++ b/src/Internal/Test/ContractTest.purs @@ -5,6 +5,8 @@ module Ctl.Internal.Test.ContractTest , ContractTestHandler , ContractTestPlan(ContractTestPlan) , ContractTestPlanHandler + , sameWallets + , groupContractTestPlans ) where import Prelude @@ -12,6 +14,9 @@ import Prelude import Contract.Monad (Contract) import Ctl.Internal.Test.TestPlanM (TestPlanM) import Ctl.Internal.Test.UtxoDistribution (class UtxoDistribution) +import Data.Tuple.Nested ((/\)) +import Mote.Monad (group, mapTest) +import Data.Tuple (fst, snd) -- | Represents a `Contract` test suite that depend on *some* wallet -- | `UtxoDistribution`. @@ -50,6 +55,15 @@ newtype ContractTestPlan = ContractTestPlan -> r ) +instance Semigroup ContractTestPlan where + append (ContractTestPlan runContractTestPlan) (ContractTestPlan runContractTestPlan') = + do + runContractTestPlan \distr tests -> do + runContractTestPlan' + \distr' tests' -> ContractTestPlan \h -> h (distr /\ distr') do + mapTest (_ <<< fst) tests + mapTest (_ <<< snd) tests' + -- | Same as `ContractTestHandler`, but wrapped in a `TestPaln`. type ContractTestPlanHandler :: Type -> Type -> Type -> Type type ContractTestPlanHandler distr wallets r = @@ -57,3 +71,18 @@ type ContractTestPlanHandler distr wallets r = => distr -> TestPlanM (wallets -> Contract Unit) Unit -> r + +-- | Store a wallet `UtxoDistribution` and `Contract`s that depend on that wallet +sameWallets + :: forall (distr :: Type) (wallets :: Type) + . UtxoDistribution distr wallets + => distr + -> TestPlanM (wallets -> Contract Unit) Unit + -> ContractTestPlan +sameWallets distr tests = ContractTestPlan \h -> h distr tests + +-- | Group `ContractTestPlans` together, so that they can be ran in the same Plutip instance +groupContractTestPlans :: String -> ContractTestPlan -> ContractTestPlan +groupContractTestPlans title (ContractTestPlan runContractTestPlan) = do + runContractTestPlan \distr tests -> ContractTestPlan \h -> h distr do + group title tests \ No newline at end of file diff --git a/src/Internal/Types/BigNum.js b/src/Internal/Types/BigNum.js index 70ba1439ba..9dc4141f85 100644 --- a/src/Internal/Types/BigNum.js +++ b/src/Internal/Types/BigNum.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Types/Int.js b/src/Internal/Types/Int.js index 301a3d7724..188f084f0e 100644 --- a/src/Internal/Types/Int.js +++ b/src/Internal/Types/Int.js @@ -2,9 +2,9 @@ let lib; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { - lib = require("@emurgo/cardano-serialization-lib-browser"); + lib = require("@mitchycola/cardano-serialization-lib-browser"); } else { - lib = require("@emurgo/cardano-serialization-lib-nodejs"); + lib = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); diff --git a/src/Internal/Types/PlutusData.purs b/src/Internal/Types/PlutusData.purs index f366f470be..d381bfec32 100644 --- a/src/Internal/Types/PlutusData.purs +++ b/src/Internal/Types/PlutusData.purs @@ -1,6 +1,7 @@ module Ctl.Internal.Types.PlutusData ( PlutusData ( Constr + , DatumMap , Map , List , Integer @@ -34,6 +35,7 @@ import Data.Tuple.Nested ((/\)) -- Doesn't distinguish "BuiltinData" and "Data" like Plutus: data PlutusData = Constr BigNum (Array PlutusData) + | DatumMap (Array (Tuple PlutusData PlutusData)) | Map (Array (Tuple PlutusData PlutusData)) | List (Array PlutusData) | Integer BigInt @@ -49,6 +51,7 @@ instance Show PlutusData where -- Based off Ogmios Datum Cache Json format, although we no longer use ODC instance DecodeAeson PlutusData where decodeAeson aeson = decodeConstr + <|> decodeMap <|> decodeMap <|> decodeList <|> decodeInteger @@ -92,6 +95,15 @@ instance EncodeAeson PlutusData where { "constr": constr , "fields": fields } + encodeAeson (DatumMap elems) = encodeAeson + { "map": encodeAeson $ map + ( \(k /\ v) -> + { "key": encodeAeson k + , "value": encodeAeson v + } + ) + elems + } encodeAeson (Map elems) = encodeAeson { "map": encodeAeson $ map ( \(k /\ v) -> diff --git a/test-data/keys/.gitkeep b/test-data/keys/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test/CoinSelection/ArbitraryHelpers.purs b/test/CoinSelection/ArbitraryHelpers.purs new file mode 100644 index 0000000000..d8e78d66f2 --- /dev/null +++ b/test/CoinSelection/ArbitraryHelpers.purs @@ -0,0 +1,143 @@ +module Test.Ctl.CoinSelection.ArbitraryHelpers where + +import Prelude + +import Control.Apply (lift2) +import Ctl.Internal.BalanceTx.CoinSelection as CoinSelection +import Ctl.Internal.Cardano.Types.Transaction + ( TransactionOutput(TransactionOutput) + , UtxoMap + ) +import Data.Map.Gen (genMap) +import Data.Map (Map) +import Ctl.Internal.Cardano.Types.Value (Value) +import Ctl.Internal.CoinSelection.UtxoIndex + ( TxUnspentOutput + , UtxoIndex + ) +import Ctl.Internal.CoinSelection.UtxoIndex as UtxoIndex +import Ctl.Internal.Serialization.Address + ( Address + , NetworkId(MainnetId) + , baseAddressToAddress + , paymentKeyHashStakeKeyHashAddress + ) +import Ctl.Internal.Types.OutputDatum (OutputDatum(NoOutputDatum)) +import Ctl.Internal.Types.Transaction + ( TransactionHash + , TransactionInput(TransactionInput) + ) +import Data.Generic.Rep (class Generic) +import Data.Map.Gen (genMap) as Map +import Data.Maybe (Maybe(Nothing)) +import Data.Newtype (class Newtype, unwrap, wrap) +import Data.Show.Generic (genericShow) +import Data.Tuple (Tuple(Tuple)) +import Data.Tuple.Nested (type (/\), (/\)) +import Data.UInt (fromInt) as UInt +import Test.QuickCheck.Arbitrary (class Arbitrary, arbitrary) +import Test.QuickCheck.Gen (Gen) + +newtype ArbitraryUtxoIndex = ArbitraryUtxoIndex UtxoIndex + +derive instance Newtype ArbitraryUtxoIndex _ + +instance Arbitrary ArbitraryUtxoIndex where + arbitrary = + (arbitrary :: Gen ArbitraryUtxoMap) + <#> wrap <<< UtxoIndex.buildUtxoIndex <<< unwrap + +newtype ArbitrarySelectionState = ArbitrarySelectionState + CoinSelection.SelectionState + +derive instance Newtype ArbitrarySelectionState _ + +instance Arbitrary ArbitrarySelectionState where + arbitrary = ArbitrarySelectionState <$> + lift2 CoinSelection.fromIndexFiltered + (arbitrary :: Gen (TransactionInput -> Boolean)) + (unwrap <$> (arbitrary :: Gen ArbitraryUtxoIndex)) + +newtype ArbitraryUtxoMap = ArbitraryUtxoMap UtxoMap + +derive instance Generic ArbitraryUtxoMap _ +derive instance Newtype ArbitraryUtxoMap _ + +instance Show ArbitraryUtxoMap where + show = genericShow + +instance Arbitrary ArbitraryUtxoMap where + arbitrary = wrap <$> Map.genMap genTransactionInput genTransactionOutput + +newtype ArbitraryTxUnspentOut = + ArbitraryTxUnspentOut (TransactionInput /\ TransactionOutput) + +derive instance Newtype ArbitraryTxUnspentOut _ + +instance Arbitrary ArbitraryTxUnspentOut where + arbitrary = wrap <$> lift2 Tuple genTransactionInput genTransactionOutput + +genTransactionInput :: Gen TransactionInput +genTransactionInput = unwrap <$> (arbitrary :: Gen ArbitraryTransactionInput) + +genTransactionOutput :: Gen TransactionOutput +genTransactionOutput = unwrap <$> (arbitrary :: Gen ArbitraryTransactionOutput) + +newtype ArbitraryTransactionInput = + ArbitraryTransactionInput TransactionInput + +derive instance Newtype ArbitraryTransactionInput _ + +instance Arbitrary ArbitraryTransactionInput where + arbitrary = wrap <$> lift2 mkTxInput arbitrary arbitrary + where + mkTxInput :: TransactionHash -> Int -> TransactionInput + mkTxInput transactionId index = + TransactionInput + { transactionId + , index: UInt.fromInt index + } + +newtype ArbitraryTransactionOutput = + ArbitraryTransactionOutput TransactionOutput + +derive instance Newtype ArbitraryTransactionOutput _ + +instance Arbitrary ArbitraryTransactionOutput where + arbitrary = wrap <$> lift2 mkTxOutput arbitrary arbitrary + where + mkTxOutput :: ArbitraryAddress -> Value -> TransactionOutput + mkTxOutput address amount = + TransactionOutput + { address: unwrap address + , amount + , datum: NoOutputDatum + , scriptRef: Nothing + } + +newtype ArbitraryTxUnspentOutput = ArbitraryTxUnspentOutput TxUnspentOutput + +derive instance Newtype ArbitraryTxUnspentOutput _ + +instance Arbitrary ArbitraryTxUnspentOutput where + arbitrary = ArbitraryTxUnspentOutput <$> lift2 (/\) in_ out + where + in_ = unwrap <$> (arbitrary :: Gen ArbitraryTransactionInput) + out = unwrap <$> (arbitrary :: Gen ArbitraryTransactionOutput) + +newtype ArbitraryAddress = ArbitraryAddress Address + +derive instance Newtype ArbitraryAddress _ + +instance Arbitrary ArbitraryAddress where + arbitrary = + wrap <<< baseAddressToAddress <$> + lift2 (paymentKeyHashStakeKeyHashAddress MainnetId) arbitrary arbitrary + + +newtype ArbitraryMap k v = ArbitraryMap (Map k v) + +derive instance Newtype (ArbitraryMap k v) _ + +instance (Ord k, Arbitrary k, Arbitrary v) => Arbitrary (ArbitraryMap k v) where + arbitrary = ArbitraryMap <$> genMap arbitrary arbitrary diff --git a/test/Datum.purs b/test/Datum.purs new file mode 100644 index 0000000000..533110891a --- /dev/null +++ b/test/Datum.purs @@ -0,0 +1,44 @@ +module Test.Ctl.Datum + ( main + , suite + ) where + +import Contract.Prelude + +import Contract.AssocMap (DatumMap(DatumMap), Map(Map)) +import Ctl.Internal.Deserialization.PlutusData (deserializeData) +import Ctl.Internal.FromData (fromData) +import Ctl.Internal.Serialization (serializeData) +import Ctl.Internal.Test.TestPlanM (TestPlanM, interpret) +import Ctl.Internal.ToData (toData) +import Ctl.Internal.Types.CborBytes (CborBytes, hexToCborBytesUnsafe) +import Data.BigInt (BigInt, fromInt) +import Effect.Aff (launchAff_) +import Mote (group, test) +import Test.Spec.Assertions (shouldEqual) + +datum :: DatumMap BigInt String +datum = DatumMap $ Map $ + [ (fromInt 2 /\ "b") + , (fromInt 4 /\ "d") + , (fromInt 1 /\ "a") + , (fromInt 3 /\ "c") + ] + +datumCBOR ∷ CborBytes +datumCBOR = hexToCborBytesUnsafe "a4024162044164014161034163" + +-- Run with `spago test --main Test.Ctl.Datum` +main :: Effect Unit +main = launchAff_ do + interpret suite + +suite :: TestPlanM (Aff Unit) Unit +suite = do + group "Unsorted Datum Map" do + test "To Data <=> From Data" do + Just datum `shouldEqual` (fromData $ toData datum) + test "Serialize Datum" do + datumCBOR `shouldEqual` serializeData datum + test "Deserialize Datum CBOR" do + Just datum `shouldEqual` deserializeData datumCBOR diff --git a/test/Wallet/Cip30/SignData.js b/test/Wallet/Cip30/SignData.js index 69ce9d44be..f028acfcec 100644 --- a/test/Wallet/Cip30/SignData.js +++ b/test/Wallet/Cip30/SignData.js @@ -3,10 +3,10 @@ let lib, csl; if (typeof BROWSER_RUNTIME != "undefined" && BROWSER_RUNTIME) { lib = require("@emurgo/cardano-message-signing-browser"); - csl = require("@emurgo/cardano-serialization-lib-browser"); + csl = require("@mitchycola/cardano-serialization-lib-browser"); } else { lib = require("@emurgo/cardano-message-signing-nodejs"); - csl = require("@emurgo/cardano-serialization-lib-nodejs"); + csl = require("@mitchycola/cardano-serialization-lib-nodejs"); } lib = require("@mlabs-haskell/csl-gc-wrapper")(lib); csl = require("@mlabs-haskell/csl-gc-wrapper")(csl);