diff --git a/.gitignore b/.gitignore index 27477514..f9159ad1 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,8 @@ dist test-dist package-lock.json -yarn.lock \ No newline at end of file +yarn.lock +# nixago: ignore-linked-files +/lefthook.yml +/.editorconfig +/treefmt.toml \ No newline at end of file diff --git a/Readme.md b/Readme.md index 57379d97..4da0be4d 100644 --- a/Readme.md +++ b/Readme.md @@ -3,71 +3,79 @@ Official Links - - Website : marlowe.iohk.io - - Documentation : docs.marlowe.iohk.io - - Playground : play.marlowe.iohk.io - - Blog : marlowe.iohk.io/blog - - Support : iohk.zendesk.com -**Repository Status** : *Beta* (Warning : Work still under progress) +- Website : marlowe.iohk.io +- Documentation : docs.marlowe.iohk.io +- Playground : play.marlowe.iohk.io +- Blog : marlowe.iohk.io/blog +- Support : iohk.zendesk.com + +**Repository Status** : _Beta_ (Warning : Work still under progress) # Overview -`marlowe-ts-sdk` is a suite of **TypeScript/JavaScript** libraries for Web Cardano Dapp Development using Marlowe Technologies. +`marlowe-ts-sdk` is a suite of **TypeScript/JavaScript** libraries for Web Cardano Dapp Development using Marlowe Technologies. It is composed of the following [npm workspaces](https://docs.npmjs.com/cli/v7/using-npm/workspaces) : -- Language +- Language - [@marlowe.io/language-core-v1](./packages/language/core/v1/) - Marlowe Core V1 constructs - - JSON Codec -- Cardano Wallet + - JSON Codec +- Cardano Wallet - [@marlowe.io/wallet](./packages/runtime/core/) - - Wallet Extension Capabalities (Browser / CIP-30) - - Single Wallet Address Capabalities(NodeJS / Version used for e2e tests only) -- Runtime - - [@marlowe.io/runtime-lifecycle](./packages/runtime/lifecycle/) : Entry Point for Running remotely Marlowe Contracts over a backend instance of the runtime using a connected wallet. - - Marlowe Tx Commands - - Create - - Applying Inputs - - Withdraws - - Query capabilities for supporting these commands + - Wallet Extension Capabalities (Browser / CIP-30) + - Single Wallet Address Capabalities(NodeJS / Version used for e2e tests only) +- Runtime + - [@marlowe.io/runtime-lifecycle](./packages/runtime/lifecycle/) : Entry Point for Running remotely Marlowe Contracts over a backend instance of the runtime using a connected wallet. + - Marlowe Tx Commands + - Create + - Applying Inputs + - Withdraws + - Query capabilities for supporting these commands - [@marlowe.io/runtime-core](./packages/runtime/core/) : core concepts used throughout the runtime libraries. - [@marlowe.io/runtime-rest-client](./packages/runtime/client/rest/) : client of the runtime rest api. -- Infrastruture Supporting SubDomains +- Infrastruture Supporting SubDomains - [@marlowe.io/adapter](./packages/adapter) : supporting set of libraries for Marlowe and Runtime Core Domains. - # Get Started ## Prerequesites -- Runtime instance available : How to ? (TODO) +- Runtime instance available : How to ? (TODO) - Wallet Extension installed : (TODO) -## Wallet Extensions -### Compatible - - Nami - - Eternl +## Wallet Extensions + +### Compatible + +- Nami +- Eternl + ### Non Compatiible - - Lace + +- Lace + ### Non Tested - - TODO -## NPM +- TODO + +## NPM ```bash npm install @marlowe.io/adapter @marlowe.io/wallet @marlowe.io/language-core-v1 @marlowe.io/runtime @marlowe.io/runtime-core @marlowe.io/runtime-rest-client ``` -## Examples - - TODO +## Examples + +- TODO + +## Basic usage -## Basic usage ``` TODO ``` -# Development +# Development -see documentation [here](./doc/howToDevelop.md). +see documentation [here](./doc/howToDevelop.md). diff --git a/changelog.d/20230905_171509_hrajchert_PLT_7420_add_prettier_precommit.md b/changelog.d/20230905_171509_hrajchert_PLT_7420_add_prettier_precommit.md new file mode 100644 index 00000000..42537980 --- /dev/null +++ b/changelog.d/20230905_171509_hrajchert_PLT_7420_add_prettier_precommit.md @@ -0,0 +1,3 @@ +### Changed + +- Reformat code with [prettier](https://prettier.io/) and [alejandra](https://github.com/kamadorueda/alejandra) using the [treefmt](https://github.com/numtide/treefmt-nix) tool diff --git a/doc/howToDevelop.md b/doc/howToDevelop.md index 6e27c03f..cdf7368c 100644 --- a/doc/howToDevelop.md +++ b/doc/howToDevelop.md @@ -1,4 +1,3 @@ - # Development ## Build diff --git a/flake.lock b/flake.lock index 6a9b5c44..ea4454a2 100644 --- a/flake.lock +++ b/flake.lock @@ -80,6 +80,81 @@ "type": "github" } }, + "flake-utils": { + "locked": { + "lastModified": 1653893745, + "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "locked": { + "lastModified": 1653893745, + "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_3": { + "locked": { + "lastModified": 1653893745, + "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_4": { + "locked": { + "lastModified": 1653893745, + "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_5": { + "locked": { + "lastModified": 1653893745, + "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "haumea": { "inputs": { "nixpkgs": "nixpkgs_2" @@ -121,6 +196,128 @@ "type": "github" } }, + "nixago": { + "inputs": { + "flake-utils": "flake-utils", + "nixago-exts": "nixago-exts", + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1687381756, + "narHash": "sha256-IUMIlYfrvj7Yli4H2vvyig8HEPpfCeMaE6+kBGPzFyk=", + "owner": "nix-community", + "repo": "nixago", + "rev": "dacceb10cace103b3e66552ec9719fa0d33c0dc9", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixago", + "type": "github" + } + }, + "nixago-exts": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixago": "nixago_2", + "nixpkgs": [ + "std", + "nixago", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1676070308, + "narHash": "sha256-QaJ65oc2l8iwQIGWUJ0EKjCeSuuCM/LqR8RauxZUUkc=", + "owner": "nix-community", + "repo": "nixago-extensions", + "rev": "e5380cb0456f4ea3c86cf94e3039eb856bf07d0b", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixago-extensions", + "type": "github" + } + }, + "nixago-exts_2": { + "inputs": { + "flake-utils": "flake-utils_4", + "nixago": "nixago_3", + "nixpkgs": [ + "std", + "nixago", + "nixago-exts", + "nixago", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1655508669, + "narHash": "sha256-BDDdo5dZQMmwNH/GNacy33nPBnCpSIydWFPZs0kkj/g=", + "owner": "nix-community", + "repo": "nixago-extensions", + "rev": "3022a932ce109258482ecc6568c163e8d0b426aa", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixago-extensions", + "type": "github" + } + }, + "nixago_2": { + "inputs": { + "flake-utils": "flake-utils_3", + "nixago-exts": "nixago-exts_2", + "nixpkgs": [ + "std", + "nixago", + "nixago-exts", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1676070010, + "narHash": "sha256-iYzJIWptE1EUD8VINAg66AAMUajizg8JUYN3oBmb8no=", + "owner": "nix-community", + "repo": "nixago", + "rev": "d480ba6c0c16e2c5c0bd2122852d6a0c9ad1ed0e", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "rename-config-data", + "repo": "nixago", + "type": "github" + } + }, + "nixago_3": { + "inputs": { + "flake-utils": "flake-utils_5", + "nixpkgs": [ + "std", + "nixago", + "nixago-exts", + "nixago", + "nixago-exts", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1655405483, + "narHash": "sha256-Crd49aZWNrpczlRTOwWGfwBMsTUoG9vlHDKQC7cx264=", + "owner": "nix-community", + "repo": "nixago", + "rev": "e6a9566c18063db5b120e69e048d3627414e327d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixago", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1677383253, @@ -153,6 +350,21 @@ } }, "nixpkgs_3": { + "locked": { + "lastModified": 1654568412, + "narHash": "sha256-BZkGyX62PyB8fzFHOcjGBJTWGb+PQ28lEbZEUR2x9JM=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "d23be02c22add83d28588ac164dcbac733305b04", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_4": { "locked": { "lastModified": 1675940568, "narHash": "sha256-epG6pOT9V0kS+FUqd7R6/CWkgnZx2DMT5Veqo+y6G3c=", @@ -259,11 +471,8 @@ "std", "blank" ], - "nixago": [ - "std", - "blank" - ], - "nixpkgs": "nixpkgs_3", + "nixago": "nixago", + "nixpkgs": "nixpkgs_4", "paisano": "paisano", "paisano-tui": "paisano-tui", "terranix": [ diff --git a/flake.nix b/flake.nix index a5df7db3..a4eda802 100644 --- a/flake.nix +++ b/flake.nix @@ -6,29 +6,36 @@ std.url = "github:divnix/std"; nixpkgs.follows = "std/nixpkgs"; std.inputs.devshell.url = "github:numtide/devshell"; + std.inputs.nixago.url = "github:nix-community/nixago"; }; - outputs = { std, self, ...} @ inputs: std.growOn { - inherit inputs; - # 1. Each folder inside `cellsFrom` becomes a "Cell" - # Run for example: 'mkdir nix/mycell' - # 2. Each .nix or /default.nix within it becomes a "Cell Block" - # Run for example: '$EDITOR nix/mycell/packages.nix' - see example content below - cellsFrom = ./nix; - # 3. Only blocks with these names [here: "packages" & "shells"] are picked up by Standard - # It's a bit like the output type system of your flake project (hint: CLI & TUI!!) - cellBlocks = with std.blockTypes; [ - (installables "packages" {ci.build = true;}) - (devshells "shells" {ci.build = true;}) - ]; - } - # 4. Run 'nix run github:divnix/std' - # 'growOn' ... Soil: - # - here, compat for the Nix CLI - # - but can use anything that produces flake outputs (e.g. flake-parts or flake-utils) - # 5. Run: nix run . - { - devShells = std.harvest self ["ts-sdk" "shells"]; - packages = std.harvest self ["ts-sdk" "packages"]; - }; -} \ No newline at end of file + outputs = { + std, + self, + ... + } @ inputs: + std.growOn { + inherit inputs; + # 1. Each folder inside `cellsFrom` becomes a "Cell" + # Run for example: 'mkdir nix/mycell' + # 2. Each .nix or /default.nix within it becomes a "Cell Block" + # Run for example: '$EDITOR nix/mycell/packages.nix' - see example content below + cellsFrom = ./nix; + # 3. Only blocks with these names [here: "packages" & "shells"] are picked up by Standard + # It's a bit like the output type system of your flake project (hint: CLI & TUI!!) + cellBlocks = with std.blockTypes; [ + (installables "packages" {ci.build = true;}) + (nixago "configs") + (devshells "shells" {ci.build = true;}) + ]; + } + # 4. Run 'nix run github:divnix/std' + # 'growOn' ... Soil: + # - here, compat for the Nix CLI + # - but can use anything that produces flake outputs (e.g. flake-parts or flake-utils) + # 5. Run: nix run . + { + devShells = std.harvest self ["ts-sdk" "shells"]; + packages = std.harvest self ["ts-sdk" "packages"]; + }; +} diff --git a/nix/ts-sdk/configs.nix b/nix/ts-sdk/configs.nix new file mode 100644 index 00000000..f5e811a0 --- /dev/null +++ b/nix/ts-sdk/configs.nix @@ -0,0 +1,104 @@ +/* +Adapted from https://github.com/divnix/std/blob/3dca8edd82ff100878ff0797f67abda629ca8686/src/std/templates/minimal/nix/repo/configs.nix + +This file holds configuration data for repo dotfiles. + +Q: Why not just put the put the file there? + +A: (1) dotfile proliferation + (2) have all the things in one place / fromat + (3) potentially share / re-use configuration data - keeping it in sync +*/ +{ + inputs, + cell, +}: { + # Tool Homepage: https://editorconfig.org/ + editorconfig = { + data = { + root = true; + + "*" = { + end_of_line = "lf"; + insert_final_newline = true; + trim_trailing_whitespace = true; + charset = "utf-8"; + indent_style = "space"; + indent_size = 2; + }; + + "*.{diff,patch}" = { + end_of_line = "unset"; + insert_final_newline = "unset"; + trim_trailing_whitespace = "unset"; + indent_size = "unset"; + }; + + "*.md" = { + max_line_length = "off"; + trim_trailing_whitespace = false; + }; + + "{LICENSES/**,LICENSE}" = { + end_of_line = "unset"; + insert_final_newline = "unset"; + trim_trailing_whitespace = "unset"; + charset = "unset"; + indent_style = "unset"; + indent_size = "unset"; + }; + }; + }; + + # Tool Homepage: https://numtide.github.io/treefmt/ + treefmt = { + packages = [ + inputs.nixpkgs.alejandra + inputs.nixpkgs.nodePackages.prettier + inputs.nixpkgs.nodePackages.prettier-plugin-toml + ]; + devshell.startup.prettier-plugin-toml = inputs.nixpkgs.lib.stringsWithDeps.noDepEntry '' + export NODE_PATH=${inputs.nixpkgs.nodePackages.prettier-plugin-toml}/lib/node_modules:''${NODE_PATH-} + ''; + data = { + formatter = { + nix = { + command = "alejandra"; + includes = ["*.nix"]; + }; + prettier = { + command = "prettier"; + options = ["--plugin" "prettier-plugin-toml" "--write"]; + includes = [ + "*.css" + "*.html" + "*.js" + "*.json" + "*.jsx" + "*.md" + "*.mdx" + "*.scss" + "*.ts" + "*.yaml" + "*.toml" + ]; + }; + }; + }; + }; + + # Tool Homepage: https://github.com/evilmartians/lefthook + lefthook = { + data = { + pre-commit = { + commands = { + treefmt = { + run = "treefmt --fail-on-change {staged_files}"; + skip = ["merge" "rebase"]; + }; + }; + }; + }; + }; + +} diff --git a/nix/ts-sdk/packages.nix b/nix/ts-sdk/packages.nix index 5557b1c1..8b6827e3 100644 --- a/nix/ts-sdk/packages.nix +++ b/nix/ts-sdk/packages.nix @@ -1,4 +1,7 @@ -{inputs, cell}: { +{ + inputs, + cell, +}: { inherit (inputs.nixpkgs) hello; default = cell.packages.hello; -} \ No newline at end of file +} diff --git a/nix/ts-sdk/shells.nix b/nix/ts-sdk/shells.nix index 41d018af..4d6ce133 100644 --- a/nix/ts-sdk/shells.nix +++ b/nix/ts-sdk/shells.nix @@ -8,34 +8,39 @@ # l = nixpkgs.lib // builtins; dev = lib.dev.mkShell { + name = "ts-sdk devshell"; packages = with nixpkgs; [ pkg-config nodejs - yarn scriv + nodePackages.prettier ]; - - env = [ - + nixago = [ + ((lib.dev.mkNixago lib.cfg.treefmt) cell.configs.treefmt) + ((lib.dev.mkNixago lib.cfg.editorconfig) cell.configs.editorconfig) + ((lib.dev.mkNixago lib.cfg.lefthook) cell.configs.lefthook) ]; - commands = - [ - { - package = nixpkgs.nodejs; - category = "JavaScript"; - } - { - package = nixpkgs.yarn; - category = "JavaScript"; - } - { - package = std.cli.default; - category = "std"; - } - ]; + commands = [ + { + package = nixpkgs.nodejs; + category = "JavaScript"; + } + { + package = nixpkgs.nodePackages.prettier; + category = "JavaScript"; + } + { + package = nixpkgs.treefmt; + category = "std"; + } + { + package = std.cli.default; + category = "std"; + } + ]; }; in { inherit dev; default = dev; -} \ No newline at end of file +} diff --git a/packages/adapter/Readme.md b/packages/adapter/Readme.md index 2b3a464a..fc1321d0 100644 --- a/packages/adapter/Readme.md +++ b/packages/adapter/Readme.md @@ -1,2 +1,3 @@ # @marlowe.io/adapter -A Set of small functionalities that supports @marlowe.io libraries \ No newline at end of file + +A Set of small functionalities that supports @marlowe.io libraries diff --git a/packages/adapter/package.json b/packages/adapter/package.json index a2ad10d1..52bca795 100644 --- a/packages/adapter/package.json +++ b/packages/adapter/package.json @@ -50,4 +50,4 @@ "json-bigint": "^1.0.0", "newtype-ts": "0.3.5" } -} \ No newline at end of file +} diff --git a/packages/adapter/src/codec.ts b/packages/adapter/src/codec.ts index 72fd5c9f..b1a37dfb 100644 --- a/packages/adapter/src/codec.ts +++ b/packages/adapter/src/codec.ts @@ -1,24 +1,26 @@ -import * as C from 'io-ts/lib/Codec.js' -import * as D from 'io-ts/lib/Decoder.js' -import * as E from 'io-ts/lib/Encoder.js' -import JSONbigint from 'json-bigint'; +import * as C from "io-ts/lib/Codec.js"; +import * as D from "io-ts/lib/Decoder.js"; +import * as E from "io-ts/lib/Encoder.js"; +import JSONbigint from "json-bigint"; -export type DecodingError = string[] - -export const MarloweJSON = JSONbigint ({ - alwaysParseAsBig: true, - useNativeBigInt: true, - }); +export type DecodingError = string[]; +export const MarloweJSON = JSONbigint({ + alwaysParseAsBig: true, + useNativeBigInt: true, +}); export const MarloweJSONDecoder: D.Decoder = { - decode: (data) => (data === ''? null : MarloweJSON.parse(data)) -} + decode: (data) => (data === "" ? null : MarloweJSON.parse(data)), +}; export const MarloweJSONEncoder: E.Encoder = { - encode: (data) => MarloweJSON.stringify(data) -} + encode: (data) => MarloweJSON.stringify(data), +}; -export const MarloweJSONCodec: C.Codec = C.make(MarloweJSONDecoder, MarloweJSONEncoder) +export const MarloweJSONCodec: C.Codec = C.make( + MarloweJSONDecoder, + MarloweJSONEncoder +); -export const minify = (a:string) => a.replace(/[\n\r\s]/g, '') \ No newline at end of file +export const minify = (a: string) => a.replace(/[\n\r\s]/g, ""); diff --git a/packages/adapter/src/file.ts b/packages/adapter/src/file.ts index e888cae6..5008b5ce 100644 --- a/packages/adapter/src/file.ts +++ b/packages/adapter/src/file.ts @@ -1,10 +1,9 @@ +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as E from "fp-ts/lib/Either.js"; -import * as TE from 'fp-ts/lib/TaskEither.js' -import * as E from 'fp-ts/lib/Either.js' - -import fs from 'fs'; -import { promisify } from 'util'; - +import fs from "fs"; +import { promisify } from "util"; const readFromFile = promisify(fs.readFile); -export const getFileContents = (path: string) => TE.tryCatch(() => readFromFile(path, 'utf-8'), E.toError); +export const getFileContents = (path: string) => + TE.tryCatch(() => readFromFile(path, "utf-8"), E.toError); diff --git a/packages/adapter/src/http.ts b/packages/adapter/src/http.ts index add163f8..c6cc2b06 100644 --- a/packages/adapter/src/http.ts +++ b/packages/adapter/src/http.ts @@ -1,23 +1,27 @@ -import { AxiosInstance, AxiosResponse } from 'axios'; -import * as TE from 'fp-ts/lib/TaskEither.js' -import { flow, identity } from 'fp-ts/lib/function.js'; -import { MarloweJSON } from '@marlowe.io/adapter/codec'; - +import { AxiosInstance, AxiosResponse } from "axios"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import { flow, identity } from "fp-ts/lib/function.js"; +import { MarloweJSON } from "@marlowe.io/adapter/codec"; const getOnlyData = TE.bimap( - (e: unknown) => (e instanceof Error ? e : new Error(MarloweJSON.stringify(e))), - (v: AxiosResponse): any => v.data, + (e: unknown) => + e instanceof Error ? e : new Error(MarloweJSON.stringify(e)), + (v: AxiosResponse): any => v.data ); const getWithDataAndHeaders = TE.bimap( (e: unknown) => (e instanceof Error ? e : new Error(String(e))), - (v: AxiosResponse): any => [v.headers,v.data], + (v: AxiosResponse): any => [v.headers, v.data] ); -export const Get = (request: AxiosInstance) => flow(TE.tryCatchK(request.get, identity), getOnlyData); +export const Get = (request: AxiosInstance) => + flow(TE.tryCatchK(request.get, identity), getOnlyData); -export const GetWithDataAndHeaders = (request: AxiosInstance) => flow(TE.tryCatchK(request.get, identity), getWithDataAndHeaders); +export const GetWithDataAndHeaders = (request: AxiosInstance) => + flow(TE.tryCatchK(request.get, identity), getWithDataAndHeaders); -export const Post = (request: AxiosInstance) => flow(TE.tryCatchK(request.post, identity), getOnlyData); +export const Post = (request: AxiosInstance) => + flow(TE.tryCatchK(request.post, identity), getOnlyData); -export const Put = (request: AxiosInstance) => flow(TE.tryCatchK(request.put, identity), getOnlyData); \ No newline at end of file +export const Put = (request: AxiosInstance) => + flow(TE.tryCatchK(request.put, identity), getOnlyData); diff --git a/packages/adapter/src/index.ts b/packages/adapter/src/index.ts index 3775dcfe..5ae1d12c 100644 --- a/packages/adapter/src/index.ts +++ b/packages/adapter/src/index.ts @@ -1,2 +1,2 @@ -export * as MarloweJSON from './codec.js'; -export * as Time from './time.js' +export * as MarloweJSON from "./codec.js"; +export * as Time from "./time.js"; diff --git a/packages/adapter/src/time.ts b/packages/adapter/src/time.ts index a60223ed..78db62a4 100644 --- a/packages/adapter/src/time.ts +++ b/packages/adapter/src/time.ts @@ -2,12 +2,12 @@ import * as t from "io-ts/lib/index.js"; import { pipe } from "fp-ts/lib/function.js"; import { format, formatISO } from "date-fns"; -export type ISO8601 = t.TypeOf -export const ISO8601 = t.string +export type ISO8601 = t.TypeOf; +export const ISO8601 = t.string; -export type POSIXTime = t.TypeOf -export const POSIXTime = t.number +export type POSIXTime = t.TypeOf; +export const POSIXTime = t.number; - -export const datetoIso8601 = (date:Date):ISO8601 => pipe(date,date => format (date,"yyyy-MM-dd'T'HH:mm:ss'Z'")) -export const datetoIso8601Bis = (date:Date):ISO8601 => pipe(date,formatISO) +export const datetoIso8601 = (date: Date): ISO8601 => + pipe(date, (date) => format(date, "yyyy-MM-dd'T'HH:mm:ss'Z'")); +export const datetoIso8601Bis = (date: Date): ISO8601 => pipe(date, formatISO); diff --git a/packages/adapter/src/tsconfig.json b/packages/adapter/src/tsconfig.json index 9db6b325..883f4cd4 100644 --- a/packages/adapter/src/tsconfig.json +++ b/packages/adapter/src/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "../../../tsconfig-base.json", "compilerOptions": { - "outDir": "../dist", + "outDir": "../dist" } } diff --git a/packages/language/core/v1/Readme.md b/packages/language/core/v1/Readme.md index 7d8628c5..95664059 100644 --- a/packages/language/core/v1/Readme.md +++ b/packages/language/core/v1/Readme.md @@ -1,2 +1,3 @@ # @marlowe.io/language-core-v1 -TODO \ No newline at end of file + +TODO diff --git a/packages/language/core/v1/package.json b/packages/language/core/v1/package.json index e3f129ee..a055b058 100644 --- a/packages/language/core/v1/package.json +++ b/packages/language/core/v1/package.json @@ -68,4 +68,4 @@ "json-bigint": "^1.0.0", "jsonbigint-io-ts-reporters": "2.0.1" } -} \ No newline at end of file +} diff --git a/packages/language/core/v1/src/examples/contract-one-notify.ts b/packages/language/core/v1/src/examples/contract-one-notify.ts index 465243e5..9df58e50 100644 --- a/packages/language/core/v1/src/examples/contract-one-notify.ts +++ b/packages/language/core/v1/src/examples/contract-one-notify.ts @@ -4,16 +4,14 @@ import { Contract } from "../semantics/contract/index.js"; import { close } from "../semantics/contract/close.js"; import { Timeout } from "../semantics/contract/when/index.js"; - /** * Marlowe Example : A contract with One Step (one true notify) */ -export const oneNotifyTrue : (notifyTimeout:Timeout) => Contract - = (notifyTimeout) => - ({ when :[{ case :{ notify_if: true } - , then : close}] - , timeout : notifyTimeout - , timeout_continuation : close}) - - +export const oneNotifyTrue: (notifyTimeout: Timeout) => Contract = ( + notifyTimeout +) => ({ + when: [{ case: { notify_if: true }, then: close }], + timeout: notifyTimeout, + timeout_continuation: close, +}); diff --git a/packages/language/core/v1/src/examples/index.ts b/packages/language/core/v1/src/examples/index.ts index 7786a79d..79590ad2 100644 --- a/packages/language/core/v1/src/examples/index.ts +++ b/packages/language/core/v1/src/examples/index.ts @@ -1,5 +1,2 @@ -export * as SwapADAToken from './swaps/swap-token-token.js'; -export {oneNotifyTrue} from './contract-one-notify.js'; - - - +export * as SwapADAToken from "./swaps/swap-token-token.js"; +export { oneNotifyTrue } from "./contract-one-notify.js"; diff --git a/packages/language/core/v1/src/examples/swaps/swap-token-token.ts b/packages/language/core/v1/src/examples/swaps/swap-token-token.ts index c709aa03..bef6aa3b 100644 --- a/packages/language/core/v1/src/examples/swaps/swap-token-token.ts +++ b/packages/language/core/v1/src/examples/swaps/swap-token-token.ts @@ -1,56 +1,69 @@ - import { Contract } from "../../semantics/contract/index.js"; import { close } from "../../semantics/contract/close.js"; import { role } from "../../semantics/contract/common/payee/party.js"; import { TokenValue } from "../../semantics/contract/common/tokenValue.js"; import { Timeout } from "../../semantics/contract/when/index.js"; - /** * Marlowe Example : Swap * Description : * Takes Tokens A from one party and tokens B from another party, and it swaps them atomically. */ -export type SwapRequest - = { provider : SwapParty - , swapper : SwapParty } - -export type SwapParty - = { roleName : string - , depositTimeout : Timeout - , value: TokenValue - } - -export const mkSwapContract : ( request: SwapRequest) => Contract - = (request) => - ({ when :[{ case :{ party: role(request.provider.roleName) - , deposits: request.provider.value.amount - , of_token: request.provider.value.token - , into_account: role(request.provider.roleName) - } - , then : { when :[{ case :{ party: role(request.swapper.roleName) - , deposits: request.swapper.value.amount - , of_token: request.swapper.value.token - , into_account: role(request.swapper.roleName) - } - , then : { pay:request.provider.value.amount - , token: request.provider.value.token - , from_account: role(request.provider.roleName) - , to: {party : role(request.swapper.roleName)} - , then: ({ pay:request.swapper.value.amount - , token: request.swapper.value.token - , from_account: role(request.swapper.roleName) - , to: {party : role(request.provider.roleName) } - , then: close})} - }] - , timeout : request.swapper.depositTimeout - , timeout_continuation : { pay: request.provider.value.amount - , token: request.provider.value.token - , from_account: role(request.provider.roleName) - , to: {party : role(request.provider.roleName)} - , then: close}}}] - , timeout : request.provider.depositTimeout - , timeout_continuation : close}) +export type SwapRequest = { provider: SwapParty; swapper: SwapParty }; +export type SwapParty = { + roleName: string; + depositTimeout: Timeout; + value: TokenValue; +}; +export const mkSwapContract: (request: SwapRequest) => Contract = ( + request +) => ({ + when: [ + { + case: { + party: role(request.provider.roleName), + deposits: request.provider.value.amount, + of_token: request.provider.value.token, + into_account: role(request.provider.roleName), + }, + then: { + when: [ + { + case: { + party: role(request.swapper.roleName), + deposits: request.swapper.value.amount, + of_token: request.swapper.value.token, + into_account: role(request.swapper.roleName), + }, + then: { + pay: request.provider.value.amount, + token: request.provider.value.token, + from_account: role(request.provider.roleName), + to: { party: role(request.swapper.roleName) }, + then: { + pay: request.swapper.value.amount, + token: request.swapper.value.token, + from_account: role(request.swapper.roleName), + to: { party: role(request.provider.roleName) }, + then: close, + }, + }, + }, + ], + timeout: request.swapper.depositTimeout, + timeout_continuation: { + pay: request.provider.value.amount, + token: request.provider.value.token, + from_account: role(request.provider.roleName), + to: { party: role(request.provider.roleName) }, + then: close, + }, + }, + }, + ], + timeout: request.provider.depositTimeout, + timeout_continuation: close, +}); diff --git a/packages/language/core/v1/src/semantics/contract/assert.ts b/packages/language/core/v1/src/semantics/contract/assert.ts index ca6b8c08..c1caf724 100644 --- a/packages/language/core/v1/src/semantics/contract/assert.ts +++ b/packages/language/core/v1/src/semantics/contract/assert.ts @@ -2,11 +2,8 @@ import * as t from "io-ts/lib/index.js"; import { Contract } from "./index.js"; import { Observation } from "./common/observations.js"; -export type Assert - = { assert: Observation - , then: Contract } +export type Assert = { assert: Observation; then: Contract }; -export const Assert : t.Type - = t.recursion('Assert', () => - t.type ({ assert: Observation - , then: Contract })) \ No newline at end of file +export const Assert: t.Type = t.recursion("Assert", () => + t.type({ assert: Observation, then: Contract }) +); diff --git a/packages/language/core/v1/src/semantics/contract/close.ts b/packages/language/core/v1/src/semantics/contract/close.ts index f1a792ad..b095d68a 100644 --- a/packages/language/core/v1/src/semantics/contract/close.ts +++ b/packages/language/core/v1/src/semantics/contract/close.ts @@ -1,5 +1,5 @@ import * as t from "io-ts/lib/index.js"; -export const close = 'close' -export type Close = t.TypeOf -export const Close = t.literal('close') \ No newline at end of file +export const close = "close"; +export type Close = t.TypeOf; +export const Close = t.literal("close"); diff --git a/packages/language/core/v1/src/semantics/contract/common/address.ts b/packages/language/core/v1/src/semantics/contract/common/address.ts index 810e0011..57dc61ac 100644 --- a/packages/language/core/v1/src/semantics/contract/common/address.ts +++ b/packages/language/core/v1/src/semantics/contract/common/address.ts @@ -1,7 +1,4 @@ +import * as t from "io-ts/lib/index.js"; -import * as t from "io-ts/lib/index.js" - -export type AddressBech32 = string -export const AddressBech32 = t.string - - +export type AddressBech32 = string; +export const AddressBech32 = t.string; diff --git a/packages/language/core/v1/src/semantics/contract/common/observations.ts b/packages/language/core/v1/src/semantics/contract/common/observations.ts index a0b342e2..7e53e8af 100644 --- a/packages/language/core/v1/src/semantics/contract/common/observations.ts +++ b/packages/language/core/v1/src/semantics/contract/common/observations.ts @@ -3,52 +3,57 @@ import { iso, Newtype } from "newtype-ts"; import { fromNewtype } from "io-ts-types"; import { ChoiceId, Value } from "./value.js"; -export type And = { both: Observation, and: Observation } -export const And : t.Type = t.recursion('And', () => t.type({ both: Observation, and: Observation })) +export type And = { both: Observation; and: Observation }; +export const And: t.Type = t.recursion("And", () => + t.type({ both: Observation, and: Observation }) +); -export type Or = { either: Observation, or: Observation } -export const Or : t.Type = t.recursion('Or', () => t.type({ either: Observation, or: Observation })) +export type Or = { either: Observation; or: Observation }; +export const Or: t.Type = t.recursion("Or", () => + t.type({ either: Observation, or: Observation }) +); -export type Not = { not: Observation } -export const Not : t.Type = t.recursion('Not', () => t.type({ not: Observation })) +export type Not = { not: Observation }; +export const Not: t.Type = t.recursion("Not", () => + t.type({ not: Observation }) +); -export type Chose = { chose_something_for: ChoiceId } -export const Chose : t.Type = t.recursion('Chose', () => t.type({ chose_something_for: ChoiceId })) +export type Chose = { chose_something_for: ChoiceId }; +export const Chose: t.Type = t.recursion("Chose", () => + t.type({ chose_something_for: ChoiceId }) +); -export type Equal - = { value: Value - , equal_to: Value } +export type Equal = { value: Value; equal_to: Value }; -export const Equal : t.Type = t.recursion('Equal', () => - t.type({ value: Value, equal_to: Value })) +export const Equal: t.Type = t.recursion("Equal", () => + t.type({ value: Value, equal_to: Value }) +); -export type Greater - = { value: Value - , gt: Value } +export type Greater = { value: Value; gt: Value }; -export const Greater : t.Type = t.recursion('Greater', () => - t.type({ value: Value, gt: Value })) +export const Greater: t.Type = t.recursion("Greater", () => + t.type({ value: Value, gt: Value }) +); -export type GreaterOrEqual -= { value: Value - , ge_than: Value } +export type GreaterOrEqual = { value: Value; ge_than: Value }; -export const GreaterOrEqual : t.Type = t.recursion('GreaterOrEqual', () => - t.type({ value: Value, ge_than: Value })) +export const GreaterOrEqual: t.Type = t.recursion( + "GreaterOrEqual", + () => t.type({ value: Value, ge_than: Value }) +); -export type Lower -= { value: Value - , lt: Value } +export type Lower = { value: Value; lt: Value }; -export const Lower : t.Type = t.recursion('Lower', () => - t.type({ value: Value, lt: Value })) +export const Lower: t.Type = t.recursion("Lower", () => + t.type({ value: Value, lt: Value }) +); -export type LowerOrEqual - = { value: Value - , le_than: Value } +export type LowerOrEqual = { value: Value; le_than: Value }; -export const LowerOrEqual : t.Type = t.recursion('LowerOrEqual', () => - t.type({ value: Value, le_than: Value })) +export const LowerOrEqual: t.Type = t.recursion( + "LowerOrEqual", + () => t.type({ value: Value, le_than: Value }) +); export type Observation = | And @@ -60,16 +65,19 @@ export type Observation = | GreaterOrEqual | Lower | LowerOrEqual - | boolean - -export const Observation : t.Type = t.recursion('Observation', () => - t.union([ And - , Or - , Not - , Chose - , Equal - , Greater - , GreaterOrEqual - , Lower - , LowerOrEqual - , t.boolean])) \ No newline at end of file + | boolean; + +export const Observation: t.Type = t.recursion("Observation", () => + t.union([ + And, + Or, + Not, + Chose, + Equal, + Greater, + GreaterOrEqual, + Lower, + LowerOrEqual, + t.boolean, + ]) +); diff --git a/packages/language/core/v1/src/semantics/contract/common/payee/account.ts b/packages/language/core/v1/src/semantics/contract/common/payee/account.ts index ffd334d9..6e879052 100644 --- a/packages/language/core/v1/src/semantics/contract/common/payee/account.ts +++ b/packages/language/core/v1/src/semantics/contract/common/payee/account.ts @@ -2,11 +2,11 @@ import * as t from "io-ts/lib/index.js"; import { Party } from "./party.js"; import { Token } from "../token.js"; -export type AccountId = t.TypeOf -export const AccountId = Party +export type AccountId = t.TypeOf; +export const AccountId = Party; -export type Account = t.TypeOf -export const Account = t.tuple([t.tuple([AccountId,Token]),t.bigint]) +export type Account = t.TypeOf; +export const Account = t.tuple([t.tuple([AccountId, Token]), t.bigint]); -export type Accounts = t.TypeOf -export const Accounts = t.array(Account) \ No newline at end of file +export type Accounts = t.TypeOf; +export const Accounts = t.array(Account); diff --git a/packages/language/core/v1/src/semantics/contract/common/payee/index.ts b/packages/language/core/v1/src/semantics/contract/common/payee/index.ts index d64bbc2a..be713096 100644 --- a/packages/language/core/v1/src/semantics/contract/common/payee/index.ts +++ b/packages/language/core/v1/src/semantics/contract/common/payee/index.ts @@ -2,8 +2,8 @@ import * as t from "io-ts/lib/index.js"; import { AccountId } from "./account.js"; import { Party } from "./party.js"; - -export type Payee = t.TypeOf -export const Payee = t.union([ t.type({ account: AccountId }) - , t.type({ party: Party }) - ]) \ No newline at end of file +export type Payee = t.TypeOf; +export const Payee = t.union([ + t.type({ account: AccountId }), + t.type({ party: Party }), +]); diff --git a/packages/language/core/v1/src/semantics/contract/common/payee/party.ts b/packages/language/core/v1/src/semantics/contract/common/payee/party.ts index 77756347..dd864249 100644 --- a/packages/language/core/v1/src/semantics/contract/common/payee/party.ts +++ b/packages/language/core/v1/src/semantics/contract/common/payee/party.ts @@ -4,32 +4,29 @@ import { fromNewtype } from "io-ts-types"; import { TokenName } from "../token.js"; import { AddressBech32 } from "../address.js"; import { pipe } from "fp-ts/lib/function.js"; -import * as A from 'fp-ts/lib/Array.js' +import * as A from "fp-ts/lib/Array.js"; -export type Address = t.TypeOf -export const Address = t.type({address:AddressBech32}) +export type Address = t.TypeOf; +export const Address = t.type({ address: AddressBech32 }); +export const role = (roleToken: TokenName) => ({ role_token: roleToken }); +export type Role = t.TypeOf; +export const Role = t.type({ role_token: TokenName }); -export const role = (roleToken:TokenName) => ({ role_token: roleToken }) -export type Role = t.TypeOf -export const Role = t.type({role_token: TokenName }) +export const party = (party: Role | Address) => party; +export type Party = t.TypeOf; +export const Party = t.union([Address, Role]); -export const party = (party:Role|Address) => party -export type Party = t.TypeOf -export const Party = t.union([Address,Role]) +export const partiesToStrings: (parties: Party[]) => string[] = (parties) => + pipe(parties, A.map(partyToString)); +export const partyToString: (party: Party) => string = (party) => + isRole(party) ? party.role_token : party.address; -export const partiesToStrings : (parties :Party[]) => (string[]) = - (parties) => pipe(parties,A.map (partyToString)) - -export const partyToString : (party :Party) => string = - (party) => isRole(party) ? party.role_token : party.address - - -export function isRole (party:Party) : party is Role { - return (party as Role).role_token !== undefined +export function isRole(party: Party): party is Role { + return (party as Role).role_token !== undefined; } -export function isAddress (party:Party) : party is Address { - return (party as Address).address !== undefined -} \ No newline at end of file +export function isAddress(party: Party): party is Address { + return (party as Address).address !== undefined; +} diff --git a/packages/language/core/v1/src/semantics/contract/common/policyId.ts b/packages/language/core/v1/src/semantics/contract/common/policyId.ts index f08194e1..df314754 100644 --- a/packages/language/core/v1/src/semantics/contract/common/policyId.ts +++ b/packages/language/core/v1/src/semantics/contract/common/policyId.ts @@ -1,4 +1,4 @@ -import * as t from "io-ts/lib/index.js" +import * as t from "io-ts/lib/index.js"; -export type PolicyId = string -export const PolicyId = t.string \ No newline at end of file +export type PolicyId = string; +export const PolicyId = t.string; diff --git a/packages/language/core/v1/src/semantics/contract/common/token.ts b/packages/language/core/v1/src/semantics/contract/common/token.ts index 08fe7567..4a5e57e0 100644 --- a/packages/language/core/v1/src/semantics/contract/common/token.ts +++ b/packages/language/core/v1/src/semantics/contract/common/token.ts @@ -1,18 +1,22 @@ -import * as t from "io-ts/lib/index.js" +import * as t from "io-ts/lib/index.js"; import { PolicyId } from "./policyId.js"; +export type TokenName = t.TypeOf; +export const TokenName = t.string; -export type TokenName = t.TypeOf -export const TokenName = t.string +export type Token = t.TypeOf; +export const Token = t.type({ + currency_symbol: PolicyId, + token_name: TokenName, +}); -export type Token = t.TypeOf -export const Token = t.type({currency_symbol:PolicyId,token_name:TokenName}) +export const token = (currency_symbol: PolicyId, token_name: TokenName) => ({ + currency_symbol: currency_symbol, + token_name: token_name, +}); -export const token = (currency_symbol :PolicyId,token_name: TokenName) => ({ currency_symbol: currency_symbol, token_name: token_name }) - - -export const tokenToString : (token : Token) => string = (token) => `${token.currency_symbol}|${token.token_name}` - -export const lovelaceToken : Token = token('','') -export const adaToken: Token = lovelaceToken +export const tokenToString: (token: Token) => string = (token) => + `${token.currency_symbol}|${token.token_name}`; +export const lovelaceToken: Token = token("", ""); +export const adaToken: Token = lovelaceToken; diff --git a/packages/language/core/v1/src/semantics/contract/common/tokenValue.ts b/packages/language/core/v1/src/semantics/contract/common/tokenValue.ts index 652f305e..c181d92b 100644 --- a/packages/language/core/v1/src/semantics/contract/common/tokenValue.ts +++ b/packages/language/core/v1/src/semantics/contract/common/tokenValue.ts @@ -1,19 +1,19 @@ -import * as t from "io-ts/lib/index.js" +import * as t from "io-ts/lib/index.js"; import * as T from "./token.js"; -export const toString : (token : TokenValue) => string = (tokenValue) => `${tokenValue.amount} - ${T.tokenToString(tokenValue.token)}` +export const toString: (token: TokenValue) => string = (tokenValue) => + `${tokenValue.amount} - ${T.tokenToString(tokenValue.token)}`; +export type TokenValue = t.TypeOf; +export const TokenValue = t.type({ amount: t.bigint, token: T.Token }); +export const tokenValue: (amount: bigint) => (token: T.Token) => TokenValue = + (amount) => (token) => ({ amount: amount, token: token }); -export type TokenValue = t.TypeOf -export const TokenValue = t.type({amount:t.bigint,token:T.Token}) -export const tokenValue : (amount : bigint) => (token : T.Token) => TokenValue - = (amount) => (token) => ({amount:amount,token:token}) +export const lovelaceValue: (lovelaces: bigint) => TokenValue = ( + lovelaces +) => ({ amount: lovelaces, token: T.adaToken }); - - -export const lovelaceValue : (lovelaces : bigint) => TokenValue - = (lovelaces) => ({amount:lovelaces,token:T.adaToken}) - - -export const adaValue : (adaAmount : bigint) => TokenValue - = (adaAmount) => ({amount:adaAmount*1_000_000n,token:T.adaToken}) +export const adaValue: (adaAmount: bigint) => TokenValue = (adaAmount) => ({ + amount: adaAmount * 1_000_000n, + token: T.adaToken, +}); diff --git a/packages/language/core/v1/src/semantics/contract/common/value.ts b/packages/language/core/v1/src/semantics/contract/common/value.ts index a99ca4db..fd224ffc 100644 --- a/packages/language/core/v1/src/semantics/contract/common/value.ts +++ b/packages/language/core/v1/src/semantics/contract/common/value.ts @@ -4,65 +4,75 @@ import { fromNewtype } from "io-ts-types"; import { Party } from "../common/payee/party.js"; import { Observation } from "./observations.js"; -export const constant = (constant:bigint) => constant -export type Constant = t.TypeOf -export const Constant = t.bigint +export const constant = (constant: bigint) => constant; +export type Constant = t.TypeOf; +export const Constant = t.bigint; -export type TimeIntervalStart = t.TypeOf -export const TimeIntervalStart = t.literal('time_interval_start') +export type TimeIntervalStart = t.TypeOf; +export const TimeIntervalStart = t.literal("time_interval_start"); -export type TimeIntervalEnd = t.TypeOf -export const TimeIntervalEnd = t.literal('time_interval_end') +export type TimeIntervalEnd = t.TypeOf; +export const TimeIntervalEnd = t.literal("time_interval_end"); -export type NegValue = { negate: Value } -export const NegValue : t.Type = t.recursion('NegValue', () => t.type({ negate: Value })) +export type NegValue = { negate: Value }; +export const NegValue: t.Type = t.recursion("NegValue", () => + t.type({ negate: Value }) +); -export type AddValue - = { add: Value - , and: Value } +export type AddValue = { add: Value; and: Value }; -export const AddValue : t.Type = t.recursion('AddValue', () => t.type({ add: Value, and: Value })) +export const AddValue: t.Type = t.recursion("AddValue", () => + t.type({ add: Value, and: Value }) +); -export type SubValue - = { value: Value - , minus: Value } +export type SubValue = { value: Value; minus: Value }; -export const SubValue : t.Type = t.recursion('SubValue', () => t.type({ value: Value, minus: Value })) +export const SubValue: t.Type = t.recursion("SubValue", () => + t.type({ value: Value, minus: Value }) +); -export const mulValue = (multiply:Value,times:Value) => ({ multiply: multiply, times: times }) -export type MulValue - = { multiply: Value - , times: Value } +export const mulValue = (multiply: Value, times: Value) => ({ + multiply: multiply, + times: times, +}); +export type MulValue = { multiply: Value; times: Value }; -export const MulValue : t.Type = t.recursion('MulValue', () => t.type({ multiply: Value, times: Value })) +export const MulValue: t.Type = t.recursion("MulValue", () => + t.type({ multiply: Value, times: Value }) +); -export type DivValue - = { divide: Value - , by: Value } +export type DivValue = { divide: Value; by: Value }; -export const DivValue : t.Type = t.recursion('DivValue', () => t.type({ divide: Value, by: Value })) +export const DivValue: t.Type = t.recursion("DivValue", () => + t.type({ divide: Value, by: Value }) +); -export type ChoiceName = t.TypeOf -export const ChoiceName = t.string +export type ChoiceName = t.TypeOf; +export const ChoiceName = t.string; -export type ChoiceId = - { choice_name: ChoiceName - , choice_owner: Party } +export type ChoiceId = { choice_name: ChoiceName; choice_owner: Party }; -export const ChoiceId : t.Type = t.recursion('ChoiceId', () => t.type({ choice_name: ChoiceName, choice_owner: Party })) +export const ChoiceId: t.Type = t.recursion("ChoiceId", () => + t.type({ choice_name: ChoiceName, choice_owner: Party }) +); -export type ChoiceValue = { value_of_choice: ChoiceId } -export const ChoiceValue : t.Type = t.recursion('ChoiceValue', () => t.type({ value_of_choice: ChoiceId })) +export type ChoiceValue = { value_of_choice: ChoiceId }; +export const ChoiceValue: t.Type = t.recursion("ChoiceValue", () => + t.type({ value_of_choice: ChoiceId }) +); +export type ValueId = t.TypeOf; +export const ValueId = t.string; -export type ValueId = t.TypeOf -export const ValueId = t.string +export type UseValue = { use_value: ValueId }; +export const UseValue: t.Type = t.recursion("UseValue", () => + t.type({ use_value: ValueId }) +); -export type UseValue = { use_value: ValueId } -export const UseValue : t.Type = t.recursion('UseValue', () => t.type({ use_value: ValueId })) - -export type Cond = { if: Observation, then: Value, else: Value } -export const Cond : t.Type = t.recursion('Cond', () => t.type({ if: Observation, then: Value, else: Value })) +export type Cond = { if: Observation; then: Value; else: Value }; +export const Cond: t.Type = t.recursion("Cond", () => + t.type({ if: Observation, then: Value, else: Value }) +); export type Value = | Constant @@ -75,17 +85,20 @@ export type Value = | TimeIntervalStart | TimeIntervalEnd | UseValue - | Cond - -export const Value :t.Type = t.recursion('Value', () => - t.union([ Constant - , NegValue - , AddValue - , SubValue - , MulValue - , DivValue - , ChoiceValue - , TimeIntervalStart - , TimeIntervalEnd - , UseValue - , Cond])) \ No newline at end of file + | Cond; + +export const Value: t.Type = t.recursion("Value", () => + t.union([ + Constant, + NegValue, + AddValue, + SubValue, + MulValue, + DivValue, + ChoiceValue, + TimeIntervalStart, + TimeIntervalEnd, + UseValue, + Cond, + ]) +); diff --git a/packages/language/core/v1/src/semantics/contract/contract.ts b/packages/language/core/v1/src/semantics/contract/contract.ts index 3bd3a1b7..33e30d8e 100644 --- a/packages/language/core/v1/src/semantics/contract/contract.ts +++ b/packages/language/core/v1/src/semantics/contract/contract.ts @@ -1,4 +1,3 @@ - import * as t from "io-ts/lib/index.js"; import { Assert } from "./assert.js"; @@ -8,20 +7,8 @@ import { Let } from "./let.js"; import { Pay } from "./pay.js"; import { When } from "./when/index.js"; -export type Contract = - | Close - | Pay - | If - | When - | Let - | Assert - -export const Contract : t.Type - = t.recursion('Contract', () => - t.union ([ Close - , Pay - , If - , When - , Let - , Assert])) +export type Contract = Close | Pay | If | When | Let | Assert; +export const Contract: t.Type = t.recursion("Contract", () => + t.union([Close, Pay, If, When, Let, Assert]) +); diff --git a/packages/language/core/v1/src/semantics/contract/if.ts b/packages/language/core/v1/src/semantics/contract/if.ts index e65963c1..66991691 100644 --- a/packages/language/core/v1/src/semantics/contract/if.ts +++ b/packages/language/core/v1/src/semantics/contract/if.ts @@ -2,13 +2,8 @@ import * as t from "io-ts/lib/index.js"; import { Contract } from "./index.js"; import { Observation } from "./common/observations.js"; -export type If - = { if: Observation - , then: Contract - , else: Contract } +export type If = { if: Observation; then: Contract; else: Contract }; -export const If : t.Type - = t.recursion('If', () => - t.type ({ if: Observation - , then: Contract - , else: Contract })) \ No newline at end of file +export const If: t.Type = t.recursion("If", () => + t.type({ if: Observation, then: Contract, else: Contract }) +); diff --git a/packages/language/core/v1/src/semantics/contract/index.ts b/packages/language/core/v1/src/semantics/contract/index.ts index 25d01dcd..8fd304b7 100644 --- a/packages/language/core/v1/src/semantics/contract/index.ts +++ b/packages/language/core/v1/src/semantics/contract/index.ts @@ -1,6 +1,4 @@ - - -export { Contract } from './contract.js'; +export { Contract } from "./contract.js"; export { Assert } from "./assert.js"; export { Close, close } from "./close.js"; export { If } from "./if.js"; @@ -12,7 +10,6 @@ export { inputNotify } from "./when/input/notify.js"; export { Input, BuiltinByteString } from "./when/input/index.js"; export { Value } from "./common/value.js"; export { Accounts } from "./common/payee/account.js"; -export { Token, TokenName, tokenToString, token } from './common/token.js'; -export { TokenValue, tokenValue, adaValue } from './common/tokenValue.js'; -export { PolicyId } from './common/policyId.js'; - +export { Token, TokenName, tokenToString, token } from "./common/token.js"; +export { TokenValue, tokenValue, adaValue } from "./common/tokenValue.js"; +export { PolicyId } from "./common/policyId.js"; diff --git a/packages/language/core/v1/src/semantics/contract/let.ts b/packages/language/core/v1/src/semantics/contract/let.ts index 3e2cf8c8..26869360 100644 --- a/packages/language/core/v1/src/semantics/contract/let.ts +++ b/packages/language/core/v1/src/semantics/contract/let.ts @@ -2,13 +2,8 @@ import * as t from "io-ts/lib/index.js"; import { Contract } from "./index.js"; import { ValueId, Value } from "./common/value.js"; -export type Let - = { let: ValueId - , be: Value - , then: Contract } +export type Let = { let: ValueId; be: Value; then: Contract }; -export const Let : t.Type - = t.recursion('Let', () => - t.type ({ let: ValueId - , be: Value - , then: Contract })) \ No newline at end of file +export const Let: t.Type = t.recursion("Let", () => + t.type({ let: ValueId, be: Value, then: Contract }) +); diff --git a/packages/language/core/v1/src/semantics/contract/pay.ts b/packages/language/core/v1/src/semantics/contract/pay.ts index c0159b2d..d5606455 100644 --- a/packages/language/core/v1/src/semantics/contract/pay.ts +++ b/packages/language/core/v1/src/semantics/contract/pay.ts @@ -1,4 +1,4 @@ -import * as t from "io-ts/lib/index.js" +import * as t from "io-ts/lib/index.js"; import { AccountId } from "./common/payee/account.js"; import { Contract } from "./index.js"; import { Payee } from "./common/payee/index.js"; @@ -6,25 +6,33 @@ import { Token } from "./common/token.js"; import { Value } from "./common/value.js"; export const pay = ( - pay: Value - , token: Token - , from_account: AccountId - , to: Payee - , then: Contract) => ({pay:pay, token: token, from_account: from_account, to: to, then: then}) + pay: Value, + token: Token, + from_account: AccountId, + to: Payee, + then: Contract +) => ({ + pay: pay, + token: token, + from_account: from_account, + to: to, + then: then, +}); export type Pay = { - pay: Value; - token: Token; - from_account: AccountId; - to: Payee; - then: Contract; - } + pay: Value; + token: Token; + from_account: AccountId; + to: Payee; + then: Contract; +}; -export const Pay -= t.recursion('Pay', () => - t.type({ pay: Value - , token: Token - , from_account: AccountId - , to: Payee - , then: Contract - })) +export const Pay = t.recursion("Pay", () => + t.type({ + pay: Value, + token: Token, + from_account: AccountId, + to: Payee, + then: Contract, + }) +); diff --git a/packages/language/core/v1/src/semantics/contract/when/action/choice.ts b/packages/language/core/v1/src/semantics/contract/when/action/choice.ts index 78148e80..c013f984 100644 --- a/packages/language/core/v1/src/semantics/contract/when/action/choice.ts +++ b/packages/language/core/v1/src/semantics/contract/when/action/choice.ts @@ -1,20 +1,14 @@ import * as t from "io-ts/lib/index.js"; import { ChoiceId } from "../../common/value.js"; -export type Bound - = { from: bigint - , to: bigint } +export type Bound = { from: bigint; to: bigint }; -export const Bound : t.Type - = t.recursion('Bound', () => - t.type ({ from: t.bigint - , to: t.bigint })) +export const Bound: t.Type = t.recursion("Bound", () => + t.type({ from: t.bigint, to: t.bigint }) +); -export type Choice = - { choose_between: Bound[] - , for_choice: ChoiceId } +export type Choice = { choose_between: Bound[]; for_choice: ChoiceId }; -export const Choice : t.Type - = t.recursion('Choice', () => - t.type ({ choose_between: t.array(Bound) - , for_choice: ChoiceId })) \ No newline at end of file +export const Choice: t.Type = t.recursion("Choice", () => + t.type({ choose_between: t.array(Bound), for_choice: ChoiceId }) +); diff --git a/packages/language/core/v1/src/semantics/contract/when/action/deposit.ts b/packages/language/core/v1/src/semantics/contract/when/action/deposit.ts index fd7423a5..bfb83928 100644 --- a/packages/language/core/v1/src/semantics/contract/when/action/deposit.ts +++ b/packages/language/core/v1/src/semantics/contract/when/action/deposit.ts @@ -4,15 +4,18 @@ import { Party } from "../../common/payee/party.js"; import { Token } from "../../common/token.js"; import { Value } from "../../common/value.js"; -export type Deposit = - | { party: Party - , deposits: Value - , of_token: Token - , into_account: AccountId } +export type Deposit = { + party: Party; + deposits: Value; + of_token: Token; + into_account: AccountId; +}; -export const Deposit : t.Type - = t.recursion('Deposit', () => - t.type ({ party: Party - , deposits: Value - , of_token: Token - , into_account: AccountId })) \ No newline at end of file +export const Deposit: t.Type = t.recursion("Deposit", () => + t.type({ + party: Party, + deposits: Value, + of_token: Token, + into_account: AccountId, + }) +); diff --git a/packages/language/core/v1/src/semantics/contract/when/action/index.ts b/packages/language/core/v1/src/semantics/contract/when/action/index.ts index 318ef51b..4c36f309 100644 --- a/packages/language/core/v1/src/semantics/contract/when/action/index.ts +++ b/packages/language/core/v1/src/semantics/contract/when/action/index.ts @@ -4,19 +4,8 @@ import { Choice } from "./choice.js"; import { Deposit } from "./deposit.js"; import { Notify } from "./notify.js"; -export type Action = - | Deposit - | Choice - | Notify - -export const Action : t.Type - = t.recursion('Action', () => - t.union ([ Deposit - , Choice - , Notify])) - - - - - +export type Action = Deposit | Choice | Notify; +export const Action: t.Type = t.recursion("Action", () => + t.union([Deposit, Choice, Notify]) +); diff --git a/packages/language/core/v1/src/semantics/contract/when/action/notify.ts b/packages/language/core/v1/src/semantics/contract/when/action/notify.ts index 74213344..79442094 100644 --- a/packages/language/core/v1/src/semantics/contract/when/action/notify.ts +++ b/packages/language/core/v1/src/semantics/contract/when/action/notify.ts @@ -1,8 +1,8 @@ import * as t from "io-ts/lib/index.js"; import { Observation } from "../../common/observations.js"; -export type Notify = { notify_if: Observation } +export type Notify = { notify_if: Observation }; -export const Notify : t.Type - = t.recursion('Notify', () => - t.type ({ notify_if: Observation })) +export const Notify: t.Type = t.recursion("Notify", () => + t.type({ notify_if: Observation }) +); diff --git a/packages/language/core/v1/src/semantics/contract/when/index.ts b/packages/language/core/v1/src/semantics/contract/when/index.ts index 5312b51f..a8c0ac26 100644 --- a/packages/language/core/v1/src/semantics/contract/when/index.ts +++ b/packages/language/core/v1/src/semantics/contract/when/index.ts @@ -2,30 +2,36 @@ import * as t from "io-ts/lib/index.js"; import { Action } from "./action/index.js"; import { Contract } from "../index.js"; import { pipe } from "fp-ts/lib/function.js"; -import getUnixTime from 'date-fns/getUnixTime/index.js' +import getUnixTime from "date-fns/getUnixTime/index.js"; +export type When = { + when: Case[]; + timeout: Timeout; + timeout_continuation: Contract; +}; -export type When - = { when: Case[] - , timeout: Timeout - , timeout_continuation: Contract } +export const When: t.Type = t.recursion("When", () => + t.type({ + when: t.array(Case), + timeout: Timeout, + timeout_continuation: Contract, + }) +); -export const When : t.Type - = t.recursion('When', () => - t.type ({ when: t.array(Case) - , timeout: Timeout - , timeout_continuation: Contract })) +export type Case = { case: Action; then: Contract }; -export type Case - = { case: Action - , then: Contract } +export const Case: t.Type = t.recursion("Case", () => + t.type({ case: Action, then: Contract }) +); -export const Case : t.Type - = t.recursion('Case', () => - t.type ({ case: Action - , then: Contract })) +export type Timeout = t.TypeOf; +export const Timeout = t.bigint; -export type Timeout = t.TypeOf -export const Timeout = t.bigint - -export const datetoTimeout = (date:Date):Timeout => pipe(date,getUnixTime,(a) => a * 1_000,BigInt,(a) => a.valueOf()) \ No newline at end of file +export const datetoTimeout = (date: Date): Timeout => + pipe( + date, + getUnixTime, + (a) => a * 1_000, + BigInt, + (a) => a.valueOf() + ); diff --git a/packages/language/core/v1/src/semantics/contract/when/input/choice.ts b/packages/language/core/v1/src/semantics/contract/when/input/choice.ts index 95e6e0b3..36c6deaa 100644 --- a/packages/language/core/v1/src/semantics/contract/when/input/choice.ts +++ b/packages/language/core/v1/src/semantics/contract/when/input/choice.ts @@ -1,10 +1,11 @@ import * as t from "io-ts/lib/index.js"; import { ChoiceId } from "../../common/value.js"; -export type ChosenNum = t.TypeOf -export const ChosenNum = t.bigint +export type ChosenNum = t.TypeOf; +export const ChosenNum = t.bigint; -export type InputChoice = t.TypeOf -export const InputChoice - = t.type ({ for_choice_id: ChoiceId - , input_that_chooses_num: ChosenNum }) \ No newline at end of file +export type InputChoice = t.TypeOf; +export const InputChoice = t.type({ + for_choice_id: ChoiceId, + input_that_chooses_num: ChosenNum, +}); diff --git a/packages/language/core/v1/src/semantics/contract/when/input/deposit.ts b/packages/language/core/v1/src/semantics/contract/when/input/deposit.ts index 572f0866..79feeb31 100644 --- a/packages/language/core/v1/src/semantics/contract/when/input/deposit.ts +++ b/packages/language/core/v1/src/semantics/contract/when/input/deposit.ts @@ -3,9 +3,10 @@ import { AccountId } from "../../common/payee/account.js"; import { Party } from "../../common/payee/party.js"; import { Token } from "../../common/token.js"; -export type InputDeposit = t.TypeOf -export const InputDeposit - = t.type ({ input_from_party: Party - , that_deposits: t.bigint - , of_token: Token - , into_account: AccountId }) \ No newline at end of file +export type InputDeposit = t.TypeOf; +export const InputDeposit = t.type({ + input_from_party: Party, + that_deposits: t.bigint, + of_token: Token, + into_account: AccountId, +}); diff --git a/packages/language/core/v1/src/semantics/contract/when/input/index.ts b/packages/language/core/v1/src/semantics/contract/when/input/index.ts index 5ae7f26b..17332759 100644 --- a/packages/language/core/v1/src/semantics/contract/when/input/index.ts +++ b/packages/language/core/v1/src/semantics/contract/when/input/index.ts @@ -1,30 +1,27 @@ -import * as t from "io-ts/lib/index.js" +import * as t from "io-ts/lib/index.js"; import { Contract } from "../../index.js"; import { InputChoice } from "./choice.js"; import { InputDeposit } from "./deposit.js"; import { InputNotify } from "./notify.js"; -export type BuiltinByteString = t.TypeOf -export const BuiltinByteString = t.string +export type BuiltinByteString = t.TypeOf; +export const BuiltinByteString = t.string; -export type InputContent = t.TypeOf -export const InputContent - = t.union ([ InputDeposit - , InputChoice - , InputNotify]) +export type InputContent = t.TypeOf; +export const InputContent = t.union([InputDeposit, InputChoice, InputNotify]); -export type NormalInput = t.TypeOf -export const NormalInput = InputContent +export type NormalInput = t.TypeOf; +export const NormalInput = InputContent; -export type MerkleizedInput = t.TypeOf -export const MerkleizedInput - = t.intersection( - [ InputContent - ,t.partial({ continuation_hash : BuiltinByteString - , merkleized_continuation:Contract }) - ]) +export type MerkleizedInput = t.TypeOf; +export const MerkleizedInput = t.intersection([ + InputContent, + t.partial({ + continuation_hash: BuiltinByteString, + merkleized_continuation: Contract, + }), +]); - -export type Input = t.TypeOf -export const Input = t.union([NormalInput,MerkleizedInput]) \ No newline at end of file +export type Input = t.TypeOf; +export const Input = t.union([NormalInput, MerkleizedInput]); diff --git a/packages/language/core/v1/src/semantics/contract/when/input/notify.ts b/packages/language/core/v1/src/semantics/contract/when/input/notify.ts index 70158e0b..5be2493f 100644 --- a/packages/language/core/v1/src/semantics/contract/when/input/notify.ts +++ b/packages/language/core/v1/src/semantics/contract/when/input/notify.ts @@ -1,6 +1,5 @@ import * as t from "io-ts/lib/index.js"; - -export const inputNotify = 'input_notify' -export type InputNotify = t.TypeOf -export const InputNotify = t.literal ('input_notify') +export const inputNotify = "input_notify"; +export type InputNotify = t.TypeOf; +export const InputNotify = t.literal("input_notify"); diff --git a/packages/language/core/v1/src/semantics/environment.ts b/packages/language/core/v1/src/semantics/environment.ts index b5468e5f..46ff2eed 100644 --- a/packages/language/core/v1/src/semantics/environment.ts +++ b/packages/language/core/v1/src/semantics/environment.ts @@ -1,12 +1,15 @@ import * as t from "io-ts/lib/index.js"; import { ISO8601, datetoIso8601 } from "@marlowe.io/adapter/time"; -export const mkEnvironment : (validityStart:Date) => (validityEnd:Date) => Environment - = (start) => (end) => ({ validityStart: datetoIso8601(start), validityEnd: datetoIso8601(end)}) +export const mkEnvironment: ( + validityStart: Date +) => (validityEnd: Date) => Environment = (start) => (end) => ({ + validityStart: datetoIso8601(start), + validityEnd: datetoIso8601(end), +}); -export type Environment = t.TypeOf -export const Environment - = t.type( - { validityStart: ISO8601 - , validityEnd: ISO8601 - }) \ No newline at end of file +export type Environment = t.TypeOf; +export const Environment = t.type({ + validityStart: ISO8601, + validityEnd: ISO8601, +}); diff --git a/packages/language/core/v1/src/semantics/next/applicables/canChoose.ts b/packages/language/core/v1/src/semantics/next/applicables/canChoose.ts index 62edd2b3..26872bec 100644 --- a/packages/language/core/v1/src/semantics/next/applicables/canChoose.ts +++ b/packages/language/core/v1/src/semantics/next/applicables/canChoose.ts @@ -5,17 +5,17 @@ import { IsMerkleizedContinuation } from "../common/IsMerkleizedContinuation.js" import { CaseIndex } from "../common/caseIndex.js"; import { ChosenNum, InputChoice } from "../../contract/when/input/choice.js"; +export type CanChoose = t.TypeOf; +export const CanChoose = t.type({ + case_index: CaseIndex, + for_choice: ChoiceId, + can_choose_between: t.array(Bound), + is_merkleized_continuation: IsMerkleizedContinuation, +}); -export type CanChoose = t.TypeOf -export const CanChoose - = t.type( - { case_index: CaseIndex - , for_choice : ChoiceId - , can_choose_between : t.array(Bound) - , is_merkleized_continuation: IsMerkleizedContinuation - }) - -export const toInput : (canChoose : CanChoose) => (chosenNum : ChosenNum) => (InputChoice) = - (canChoose) => (chosenNum) => - ({ for_choice_id: canChoose.for_choice - , input_that_chooses_num: chosenNum }) \ No newline at end of file +export const toInput: ( + canChoose: CanChoose +) => (chosenNum: ChosenNum) => InputChoice = (canChoose) => (chosenNum) => ({ + for_choice_id: canChoose.for_choice, + input_that_chooses_num: chosenNum, +}); diff --git a/packages/language/core/v1/src/semantics/next/applicables/canDeposit.ts b/packages/language/core/v1/src/semantics/next/applicables/canDeposit.ts index 90b15848..3f9c5cac 100644 --- a/packages/language/core/v1/src/semantics/next/applicables/canDeposit.ts +++ b/packages/language/core/v1/src/semantics/next/applicables/canDeposit.ts @@ -7,20 +7,21 @@ import { IsMerkleizedContinuation } from "../common/IsMerkleizedContinuation.js" import { CaseIndex } from "../common/caseIndex.js"; import { InputDeposit } from "../../contract/when/input/deposit.js"; -export type CanDeposit = t.TypeOf -export const CanDeposit - = t.type( - { case_index: CaseIndex - , party : Party - , can_deposit : t.bigint - , of_token : Token - , into_account : AccountId - , is_merkleized_continuation: IsMerkleizedContinuation - }) +export type CanDeposit = t.TypeOf; +export const CanDeposit = t.type({ + case_index: CaseIndex, + party: Party, + can_deposit: t.bigint, + of_token: Token, + into_account: AccountId, + is_merkleized_continuation: IsMerkleizedContinuation, +}); -export const toInput : (canDeposit : CanDeposit) => (InputDeposit) = - (canDeposit) => - ({input_from_party: canDeposit.party - , that_deposits: canDeposit.can_deposit - , of_token: canDeposit.of_token - , into_account: canDeposit.into_account}) \ No newline at end of file +export const toInput: (canDeposit: CanDeposit) => InputDeposit = ( + canDeposit +) => ({ + input_from_party: canDeposit.party, + that_deposits: canDeposit.can_deposit, + of_token: canDeposit.of_token, + into_account: canDeposit.into_account, +}); diff --git a/packages/language/core/v1/src/semantics/next/applicables/canNotify.ts b/packages/language/core/v1/src/semantics/next/applicables/canNotify.ts index 2708e56c..1820a141 100644 --- a/packages/language/core/v1/src/semantics/next/applicables/canNotify.ts +++ b/packages/language/core/v1/src/semantics/next/applicables/canNotify.ts @@ -3,14 +3,11 @@ import { IsMerkleizedContinuation } from "../common/IsMerkleizedContinuation.js" import { CaseIndex } from "../common/caseIndex.js"; import { InputNotify } from "../../contract/when/input/notify.js"; - -export type CanNotify = t.TypeOf -export const CanNotify - = t.type( - { case_index: CaseIndex - , is_merkleized_continuation: IsMerkleizedContinuation - }) - - -export const toInput : (canNotify : CanNotify) => (InputNotify) = - (canNotify) => ('input_notify') \ No newline at end of file +export type CanNotify = t.TypeOf; +export const CanNotify = t.type({ + case_index: CaseIndex, + is_merkleized_continuation: IsMerkleizedContinuation, +}); + +export const toInput: (canNotify: CanNotify) => InputNotify = (canNotify) => + "input_notify"; diff --git a/packages/language/core/v1/src/semantics/next/applicables/index.ts b/packages/language/core/v1/src/semantics/next/applicables/index.ts index 59f64bf0..1477f003 100644 --- a/packages/language/core/v1/src/semantics/next/applicables/index.ts +++ b/packages/language/core/v1/src/semantics/next/applicables/index.ts @@ -4,11 +4,9 @@ import { CanDeposit } from "./canDeposit.js"; import { CanChoose } from "./canChoose.js"; import { CanNotify } from "./canNotify.js"; - -export type ApplicableInputs = t.TypeOf -export const ApplicableInputs - = t.type( - { notify: optionFromNullable(CanNotify) - , deposits: t.array(CanDeposit) - , choices: t.array(CanChoose) - }) \ No newline at end of file +export type ApplicableInputs = t.TypeOf; +export const ApplicableInputs = t.type({ + notify: optionFromNullable(CanNotify), + deposits: t.array(CanDeposit), + choices: t.array(CanChoose), +}); diff --git a/packages/language/core/v1/src/semantics/next/common/IsMerkleizedContinuation.ts b/packages/language/core/v1/src/semantics/next/common/IsMerkleizedContinuation.ts index 2dab42b6..e7518b95 100644 --- a/packages/language/core/v1/src/semantics/next/common/IsMerkleizedContinuation.ts +++ b/packages/language/core/v1/src/semantics/next/common/IsMerkleizedContinuation.ts @@ -1,4 +1,4 @@ import * as t from "io-ts/lib/index.js"; -export type IsMerkleizedContinuation = boolean -export const IsMerkleizedContinuation = t.boolean \ No newline at end of file +export type IsMerkleizedContinuation = boolean; +export const IsMerkleizedContinuation = t.boolean; diff --git a/packages/language/core/v1/src/semantics/next/common/caseIndex.ts b/packages/language/core/v1/src/semantics/next/common/caseIndex.ts index e3a5ca90..b9554d43 100644 --- a/packages/language/core/v1/src/semantics/next/common/caseIndex.ts +++ b/packages/language/core/v1/src/semantics/next/common/caseIndex.ts @@ -1,4 +1,4 @@ import * as t from "io-ts/lib/index.js"; -export type CaseIndex = bigint -export const CaseIndex = t.bigint +export type CaseIndex = bigint; +export const CaseIndex = t.bigint; diff --git a/packages/language/core/v1/src/semantics/next/index.ts b/packages/language/core/v1/src/semantics/next/index.ts index 5b881080..371de984 100644 --- a/packages/language/core/v1/src/semantics/next/index.ts +++ b/packages/language/core/v1/src/semantics/next/index.ts @@ -2,9 +2,8 @@ import * as t from "io-ts/lib/index.js"; import { ApplicableInputs } from "./applicables/index.js"; export { toInput } from "./applicables/canDeposit.js"; -export type Next = t.TypeOf -export const Next - = t.type( - { can_reduce: t.boolean - , applicable_inputs: ApplicableInputs - }) \ No newline at end of file +export type Next = t.TypeOf; +export const Next = t.type({ + can_reduce: t.boolean, + applicable_inputs: ApplicableInputs, +}); diff --git a/packages/language/core/v1/src/semantics/state.ts b/packages/language/core/v1/src/semantics/state.ts index bce33013..8f77ff2a 100644 --- a/packages/language/core/v1/src/semantics/state.ts +++ b/packages/language/core/v1/src/semantics/state.ts @@ -3,10 +3,11 @@ import * as t from "io-ts/lib/index.js"; import { Accounts } from "./contract/common/payee/account.js"; import { ChoiceId, ValueId } from "./contract/common/value.js"; - -export type MarloweState = t.TypeOf - -export const MarloweState = t.type({ accounts:Accounts - , boundValues: t.array(t.tuple([ValueId, t.bigint])) - , choices: t.array(t.tuple([ChoiceId, t.bigint])) - , minTime:t.bigint}) \ No newline at end of file +export type MarloweState = t.TypeOf; + +export const MarloweState = t.type({ + accounts: Accounts, + boundValues: t.array(t.tuple([ValueId, t.bigint])), + choices: t.array(t.tuple([ChoiceId, t.bigint])), + minTime: t.bigint, +}); diff --git a/packages/language/core/v1/src/semantics/version.ts b/packages/language/core/v1/src/semantics/version.ts index 927cea42..f542753e 100644 --- a/packages/language/core/v1/src/semantics/version.ts +++ b/packages/language/core/v1/src/semantics/version.ts @@ -1,5 +1,4 @@ - import * as t from "io-ts/lib/index.js"; export type MarloweVersion = t.TypeOf; -export const MarloweVersion = t.literal('v1') \ No newline at end of file +export const MarloweVersion = t.literal("v1"); diff --git a/packages/language/core/v1/src/tsconfig.json b/packages/language/core/v1/src/tsconfig.json index 8d17eb91..53b57ed9 100644 --- a/packages/language/core/v1/src/tsconfig.json +++ b/packages/language/core/v1/src/tsconfig.json @@ -3,10 +3,8 @@ "compilerOptions": { "outDir": "../dist", "paths": { - "@marlowe.io/adapter/*": ["../../../../adapter/src/*"], + "@marlowe.io/adapter/*": ["../../../../adapter/src/*"] } }, - "references": [ - {"path": "../../../../adapter/src"} - ] -} \ No newline at end of file + "references": [{ "path": "../../../../adapter/src" }] +} diff --git a/packages/language/core/v1/test/examples/jsons/contractForDifferences.json b/packages/language/core/v1/test/examples/jsons/contractForDifferences.json index d065c38b..848bef23 100644 --- a/packages/language/core/v1/test/examples/jsons/contractForDifferences.json +++ b/packages/language/core/v1/test/examples/jsons/contractForDifferences.json @@ -1,219 +1,231 @@ { - "when": [{ - "then": { - "when": [{ - "then": { - "when": [], - "timeout_continuation": { - "when": [{ - "then": { - "when": [], - "timeout_continuation": { - "when": [{ - "then": { - "then": { - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "account": { - "role_token": "Party" - } - }, - "then": "close", - "pay": { - "then": { - "use_value": "Decrease in price" - }, - "if": { - "value": { - "use_value": "Decrease in price" - }, - "lt": 0 - }, - "else": 0 - }, - "from_account": { - "role_token": "Counterparty" - } - }, - "let": "Decrease in price", - "be": { - "value": { - "value_of_choice": { - "choice_owner": { - "role_token": "Oracle" - }, - "choice_name": "Price in first window" - } - }, - "minus": { - "value_of_choice": { - "choice_owner": { - "role_token": "Oracle" - }, - "choice_name": "Price in second window" - } - } - } - }, - "if": { - "value": { - "value_of_choice": { - "choice_owner": { - "role_token": "Oracle" - }, - "choice_name": "Price in first window" - } - }, - "gt": { - "value_of_choice": { - "choice_owner": { - "role_token": "Oracle" - }, - "choice_name": "Price in second window" - } - } - }, - "else": { - "then": { - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "account": { - "role_token": "Counterparty" - } - }, - "then": "close", - "pay": { - "then": { - "use_value": "Increase in price" - }, - "if": { - "value": { - "use_value": "Increase in price" - }, - "lt": 0 - }, - "else": 0 - }, - "from_account": { - "role_token": "Party" - } - }, - "let": "Increase in price", - "be": { - "value": { - "value_of_choice": { - "choice_owner": { - "role_token": "Oracle" - }, - "choice_name": "Price in second window" - } - }, - "minus": { - "value_of_choice": { - "choice_owner": { - "role_token": "Oracle" - }, - "choice_name": "Price in first window" - } - } - } - }, - "if": { - "value": { - "value_of_choice": { - "choice_owner": { - "role_token": "Oracle" - }, - "choice_name": "Price in first window" - } - }, - "lt": { - "value_of_choice": { - "choice_owner": { - "role_token": "Oracle" - }, - "choice_name": "Price in second window" - } - } - }, - "else": "close" - } - }, - "case": { - "for_choice": { - "choice_owner": { - "role_token": "Oracle" - }, - "choice_name": "Price in second window" - }, - "choose_between": [{ - "to": 1000000000, - "from": 0 - }] - } - }], - "timeout_continuation": "close", - "timeout": 1679043795918 - }, - "timeout": 1679043495918 - }, - "case": { - "for_choice": { - "choice_owner": { - "role_token": "Oracle" - }, - "choice_name": "Price in first window" - }, - "choose_between": [{ - "to": 1000000000, - "from": 0 - }] - } - }], - "timeout_continuation": "close", - "timeout": 1679043195918 - }, - "timeout": 1679042895918 - }, - "case": { - "party": { - "role_token": "Counterparty" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Counterparty" - }, - "deposits": 0 - } - }], - "timeout_continuation": "close", - "timeout": 1679042595918 - }, - "case": { - "party": { - "role_token": "Party" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Party" - }, - "deposits": 0 - } - }], - "timeout_continuation": "close", - "timeout": 1679042295918 -} \ No newline at end of file + "when": [ + { + "then": { + "when": [ + { + "then": { + "when": [], + "timeout_continuation": { + "when": [ + { + "then": { + "when": [], + "timeout_continuation": { + "when": [ + { + "then": { + "then": { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "account": { + "role_token": "Party" + } + }, + "then": "close", + "pay": { + "then": { + "use_value": "Decrease in price" + }, + "if": { + "value": { + "use_value": "Decrease in price" + }, + "lt": 0 + }, + "else": 0 + }, + "from_account": { + "role_token": "Counterparty" + } + }, + "let": "Decrease in price", + "be": { + "value": { + "value_of_choice": { + "choice_owner": { + "role_token": "Oracle" + }, + "choice_name": "Price in first window" + } + }, + "minus": { + "value_of_choice": { + "choice_owner": { + "role_token": "Oracle" + }, + "choice_name": "Price in second window" + } + } + } + }, + "if": { + "value": { + "value_of_choice": { + "choice_owner": { + "role_token": "Oracle" + }, + "choice_name": "Price in first window" + } + }, + "gt": { + "value_of_choice": { + "choice_owner": { + "role_token": "Oracle" + }, + "choice_name": "Price in second window" + } + } + }, + "else": { + "then": { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "account": { + "role_token": "Counterparty" + } + }, + "then": "close", + "pay": { + "then": { + "use_value": "Increase in price" + }, + "if": { + "value": { + "use_value": "Increase in price" + }, + "lt": 0 + }, + "else": 0 + }, + "from_account": { + "role_token": "Party" + } + }, + "let": "Increase in price", + "be": { + "value": { + "value_of_choice": { + "choice_owner": { + "role_token": "Oracle" + }, + "choice_name": "Price in second window" + } + }, + "minus": { + "value_of_choice": { + "choice_owner": { + "role_token": "Oracle" + }, + "choice_name": "Price in first window" + } + } + } + }, + "if": { + "value": { + "value_of_choice": { + "choice_owner": { + "role_token": "Oracle" + }, + "choice_name": "Price in first window" + } + }, + "lt": { + "value_of_choice": { + "choice_owner": { + "role_token": "Oracle" + }, + "choice_name": "Price in second window" + } + } + }, + "else": "close" + } + }, + "case": { + "for_choice": { + "choice_owner": { + "role_token": "Oracle" + }, + "choice_name": "Price in second window" + }, + "choose_between": [ + { + "to": 1000000000, + "from": 0 + } + ] + } + } + ], + "timeout_continuation": "close", + "timeout": 1679043795918 + }, + "timeout": 1679043495918 + }, + "case": { + "for_choice": { + "choice_owner": { + "role_token": "Oracle" + }, + "choice_name": "Price in first window" + }, + "choose_between": [ + { + "to": 1000000000, + "from": 0 + } + ] + } + } + ], + "timeout_continuation": "close", + "timeout": 1679043195918 + }, + "timeout": 1679042895918 + }, + "case": { + "party": { + "role_token": "Counterparty" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Counterparty" + }, + "deposits": 0 + } + } + ], + "timeout_continuation": "close", + "timeout": 1679042595918 + }, + "case": { + "party": { + "role_token": "Party" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Party" + }, + "deposits": 0 + } + } + ], + "timeout_continuation": "close", + "timeout": 1679042295918 +} diff --git a/packages/language/core/v1/test/examples/jsons/contractForDifferencesWithOracle.json b/packages/language/core/v1/test/examples/jsons/contractForDifferencesWithOracle.json index b31a462b..9103c0ab 100644 --- a/packages/language/core/v1/test/examples/jsons/contractForDifferencesWithOracle.json +++ b/packages/language/core/v1/test/examples/jsons/contractForDifferencesWithOracle.json @@ -1,198 +1,210 @@ { - "when": [{ - "then": { - "when": [{ - "then": { - "when": [], - "timeout_continuation": { - "when": [{ - "then": { - "when": [], - "timeout_continuation": { - "when": [{ - "then": { - "then": { - "then": { - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "account": { - "role_token": "Party" - } - }, - "then": "close", - "pay": { - "then": { - "use_value": "Decrease in price" - }, - "if": { - "value": { - "use_value": "Decrease in price" - }, - "lt": 0 - }, - "else": 0 - }, - "from_account": { - "role_token": "Counterparty" - } - }, - "let": "Decrease in price", - "be": { - "value": 0, - "minus": { - "use_value": "Price in second window" - } - } - }, - "if": { - "value": 0, - "gt": { - "use_value": "Price in second window" - } - }, - "else": { - "then": { - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "account": { - "role_token": "Counterparty" - } - }, - "then": "close", - "pay": { - "then": { - "use_value": "Increase in price" - }, - "if": { - "value": { - "use_value": "Increase in price" - }, - "lt": 0 - }, - "else": 0 - }, - "from_account": { - "role_token": "Party" - } - }, - "let": "Increase in price", - "be": { - "value": { - "use_value": "Price in second window" - }, - "minus": 0 - } - }, - "if": { - "value": 0, - "lt": { - "use_value": "Price in second window" - } - }, - "else": "close" - } - }, - "let": "Price in second window", - "be": { - "divide": { - "times": { - "times": { - "value_of_choice": { - "choice_owner": { - "role_token": "kraken" - }, - "choice_name": "inv-adausd" - } - }, - "multiply": { - "value_of_choice": { - "choice_owner": { - "role_token": "kraken" - }, - "choice_name": "dir-adausd" - } - } - }, - "multiply": 0 - }, - "by": 10000000000000000 - } - }, - "case": { - "for_choice": { - "choice_owner": { - "role_token": "kraken" - }, - "choice_name": "inv-adausd" - }, - "choose_between": [{ - "to": 100000000000, - "from": 0 - }] - } - }], - "timeout_continuation": "close", - "timeout": 1679043829460 - }, - "timeout": 1679043529460 - }, - "case": { - "for_choice": { - "choice_owner": { - "role_token": "kraken" - }, - "choice_name": "dir-adausd" - }, - "choose_between": [{ - "to": 100000000000, - "from": 0 - }] - } - }], - "timeout_continuation": "close", - "timeout": 1679043229460 - }, - "timeout": 1679042929460 - }, - "case": { - "party": { - "role_token": "Counterparty" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Counterparty" - }, - "deposits": 0 - } - }], - "timeout_continuation": "close", - "timeout": 1679042629460 - }, - "case": { - "party": { - "role_token": "Party" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Party" - }, - "deposits": 0 - } - }], - "timeout_continuation": "close", - "timeout": 1679042329460 -} \ No newline at end of file + "when": [ + { + "then": { + "when": [ + { + "then": { + "when": [], + "timeout_continuation": { + "when": [ + { + "then": { + "when": [], + "timeout_continuation": { + "when": [ + { + "then": { + "then": { + "then": { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "account": { + "role_token": "Party" + } + }, + "then": "close", + "pay": { + "then": { + "use_value": "Decrease in price" + }, + "if": { + "value": { + "use_value": "Decrease in price" + }, + "lt": 0 + }, + "else": 0 + }, + "from_account": { + "role_token": "Counterparty" + } + }, + "let": "Decrease in price", + "be": { + "value": 0, + "minus": { + "use_value": "Price in second window" + } + } + }, + "if": { + "value": 0, + "gt": { + "use_value": "Price in second window" + } + }, + "else": { + "then": { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "account": { + "role_token": "Counterparty" + } + }, + "then": "close", + "pay": { + "then": { + "use_value": "Increase in price" + }, + "if": { + "value": { + "use_value": "Increase in price" + }, + "lt": 0 + }, + "else": 0 + }, + "from_account": { + "role_token": "Party" + } + }, + "let": "Increase in price", + "be": { + "value": { + "use_value": "Price in second window" + }, + "minus": 0 + } + }, + "if": { + "value": 0, + "lt": { + "use_value": "Price in second window" + } + }, + "else": "close" + } + }, + "let": "Price in second window", + "be": { + "divide": { + "times": { + "times": { + "value_of_choice": { + "choice_owner": { + "role_token": "kraken" + }, + "choice_name": "inv-adausd" + } + }, + "multiply": { + "value_of_choice": { + "choice_owner": { + "role_token": "kraken" + }, + "choice_name": "dir-adausd" + } + } + }, + "multiply": 0 + }, + "by": 10000000000000000 + } + }, + "case": { + "for_choice": { + "choice_owner": { + "role_token": "kraken" + }, + "choice_name": "inv-adausd" + }, + "choose_between": [ + { + "to": 100000000000, + "from": 0 + } + ] + } + } + ], + "timeout_continuation": "close", + "timeout": 1679043829460 + }, + "timeout": 1679043529460 + }, + "case": { + "for_choice": { + "choice_owner": { + "role_token": "kraken" + }, + "choice_name": "dir-adausd" + }, + "choose_between": [ + { + "to": 100000000000, + "from": 0 + } + ] + } + } + ], + "timeout_continuation": "close", + "timeout": 1679043229460 + }, + "timeout": 1679042929460 + }, + "case": { + "party": { + "role_token": "Counterparty" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Counterparty" + }, + "deposits": 0 + } + } + ], + "timeout_continuation": "close", + "timeout": 1679042629460 + }, + "case": { + "party": { + "role_token": "Party" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Party" + }, + "deposits": 0 + } + } + ], + "timeout_continuation": "close", + "timeout": 1679042329460 +} diff --git a/packages/language/core/v1/test/examples/jsons/couponBondGuaranteed.json b/packages/language/core/v1/test/examples/jsons/couponBondGuaranteed.json index 879e1b47..1966bb3a 100644 --- a/packages/language/core/v1/test/examples/jsons/couponBondGuaranteed.json +++ b/packages/language/core/v1/test/examples/jsons/couponBondGuaranteed.json @@ -1,237 +1,247 @@ { - "when": [{ - "then": { - "when": [{ - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "role_token": "Borrower" - } - }, - "then": { - "when": [{ - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "role_token": "Lender" - } - }, - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "role_token": "Guarantor" - } - }, - "then": { - "when": [{ - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "role_token": "Lender" - } - }, - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "role_token": "Guarantor" - } - }, - "then": { - "when": [{ - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "role_token": "Lender" - } - }, - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "role_token": "Guarantor" - } - }, - "then": "close", - "pay": { - "and": 0, - "add": 0 - }, - "from_account": { - "role_token": "Lender" - } - }, - "pay": { - "and": 0, - "add": 0 - }, - "from_account": { - "role_token": "Lender" - } - }, - "case": { - "party": { - "role_token": "Borrower" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Lender" - }, - "deposits": { - "and": 0, - "add": 0 - } - } - }], - "timeout_continuation": "close", - "timeout": 1500 - }, - "pay": 0, - "from_account": { - "role_token": "Lender" - } - }, - "pay": 0, - "from_account": { - "role_token": "Lender" - } - }, - "case": { - "party": { - "role_token": "Borrower" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Lender" - }, - "deposits": 0 - } - }], - "timeout_continuation": "close", - "timeout": 1200 - }, - "pay": 0, - "from_account": { - "role_token": "Lender" - } - }, - "pay": 0, - "from_account": { - "role_token": "Lender" - } - }, - "case": { - "party": { - "role_token": "Borrower" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Lender" - }, - "deposits": 0 - } - }], - "timeout_continuation": "close", - "timeout": 900 - }, - "pay": 0, - "from_account": { - "role_token": "Borrower" - } - }, - "case": { - "party": { - "role_token": "Lender" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Borrower" - }, - "deposits": 0 - } - }], - "timeout_continuation": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "role_token": "Guarantor" - } - }, - "then": "close", - "pay": { - "and": 0, - "add": { - "times": 0, - "multiply": 3 - } - }, - "from_account": { - "role_token": "Lender" - } - }, - "timeout": 600 - }, - "case": { - "party": { - "role_token": "Guarantor" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Lender" - }, - "deposits": { - "and": 0, - "add": { - "times": 0, - "multiply": 3 - } - } - } - }], - "timeout_continuation": "close", - "timeout": 300 -} \ No newline at end of file + "when": [ + { + "then": { + "when": [ + { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "role_token": "Borrower" + } + }, + "then": { + "when": [ + { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "role_token": "Lender" + } + }, + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "role_token": "Guarantor" + } + }, + "then": { + "when": [ + { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "role_token": "Lender" + } + }, + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "role_token": "Guarantor" + } + }, + "then": { + "when": [ + { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "role_token": "Lender" + } + }, + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "role_token": "Guarantor" + } + }, + "then": "close", + "pay": { + "and": 0, + "add": 0 + }, + "from_account": { + "role_token": "Lender" + } + }, + "pay": { + "and": 0, + "add": 0 + }, + "from_account": { + "role_token": "Lender" + } + }, + "case": { + "party": { + "role_token": "Borrower" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Lender" + }, + "deposits": { + "and": 0, + "add": 0 + } + } + } + ], + "timeout_continuation": "close", + "timeout": 1500 + }, + "pay": 0, + "from_account": { + "role_token": "Lender" + } + }, + "pay": 0, + "from_account": { + "role_token": "Lender" + } + }, + "case": { + "party": { + "role_token": "Borrower" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Lender" + }, + "deposits": 0 + } + } + ], + "timeout_continuation": "close", + "timeout": 1200 + }, + "pay": 0, + "from_account": { + "role_token": "Lender" + } + }, + "pay": 0, + "from_account": { + "role_token": "Lender" + } + }, + "case": { + "party": { + "role_token": "Borrower" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Lender" + }, + "deposits": 0 + } + } + ], + "timeout_continuation": "close", + "timeout": 900 + }, + "pay": 0, + "from_account": { + "role_token": "Borrower" + } + }, + "case": { + "party": { + "role_token": "Lender" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Borrower" + }, + "deposits": 0 + } + } + ], + "timeout_continuation": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "role_token": "Guarantor" + } + }, + "then": "close", + "pay": { + "and": 0, + "add": { + "times": 0, + "multiply": 3 + } + }, + "from_account": { + "role_token": "Lender" + } + }, + "timeout": 600 + }, + "case": { + "party": { + "role_token": "Guarantor" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Lender" + }, + "deposits": { + "and": 0, + "add": { + "times": 0, + "multiply": 3 + } + } + } + } + ], + "timeout_continuation": "close", + "timeout": 300 +} diff --git a/packages/language/core/v1/test/examples/jsons/escrow.json b/packages/language/core/v1/test/examples/jsons/escrow.json index b2707b13..959fa234 100644 --- a/packages/language/core/v1/test/examples/jsons/escrow.json +++ b/packages/language/core/v1/test/examples/jsons/escrow.json @@ -1,146 +1,169 @@ { - "when": [{ - "then": { - "when": [{ - "then": "close", - "case": { - "for_choice": { - "choice_owner": { - "role_token": "Buyer" - }, - "choice_name": "Everything is alright" - }, - "choose_between": [{ - "to": 0, - "from": 0 - }] - } - }, { - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "account": { - "role_token": "Buyer" - } - }, - "then": { - "when": [{ - "then": "close", - "case": { - "for_choice": { - "choice_owner": { - "role_token": "Seller" - }, - "choice_name": "Confirm problem" - }, - "choose_between": [{ - "to": 1, - "from": 1 - }] - } - }, { - "then": { - "when": [{ - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "role_token": "Seller" - } - }, - "then": "close", - "pay": 12000000, - "from_account": { - "role_token": "Buyer" - } - }, - "case": { - "for_choice": { - "choice_owner": { - "role_token": "Mediator" - }, - "choice_name": "Dismiss claim" - }, - "choose_between": [{ - "to": 0, - "from": 0 - }] - } - }, { - "then": "close", - "case": { - "for_choice": { - "choice_owner": { - "role_token": "Mediator" - }, - "choice_name": "Confirm problem" - }, - "choose_between": [{ - "to": 1, - "from": 1 - }] - } - }], - "timeout_continuation": "close", - "timeout": 1679038507831 - }, - "case": { - "for_choice": { - "choice_owner": { - "role_token": "Seller" - }, - "choice_name": "Dispute problem" - }, - "choose_between": [{ - "to": 0, - "from": 0 - }] - } - }], - "timeout_continuation": "close", - "timeout": 1679038207831 - }, - "pay": 12000000, - "from_account": { - "role_token": "Seller" - } - }, - "case": { - "for_choice": { - "choice_owner": { - "role_token": "Buyer" - }, - "choice_name": "Report problem" - }, - "choose_between": [{ - "to": 1, - "from": 1 - }] - } - }], - "timeout_continuation": "close", - "timeout": 1679037907831 - }, - "case": { - "party": { - "role_token": "Buyer" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Seller" - }, - "deposits": 12000000 - } - }], - "timeout_continuation": "close", - "timeout": 1679037607831 -} \ No newline at end of file + "when": [ + { + "then": { + "when": [ + { + "then": "close", + "case": { + "for_choice": { + "choice_owner": { + "role_token": "Buyer" + }, + "choice_name": "Everything is alright" + }, + "choose_between": [ + { + "to": 0, + "from": 0 + } + ] + } + }, + { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "account": { + "role_token": "Buyer" + } + }, + "then": { + "when": [ + { + "then": "close", + "case": { + "for_choice": { + "choice_owner": { + "role_token": "Seller" + }, + "choice_name": "Confirm problem" + }, + "choose_between": [ + { + "to": 1, + "from": 1 + } + ] + } + }, + { + "then": { + "when": [ + { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "role_token": "Seller" + } + }, + "then": "close", + "pay": 12000000, + "from_account": { + "role_token": "Buyer" + } + }, + "case": { + "for_choice": { + "choice_owner": { + "role_token": "Mediator" + }, + "choice_name": "Dismiss claim" + }, + "choose_between": [ + { + "to": 0, + "from": 0 + } + ] + } + }, + { + "then": "close", + "case": { + "for_choice": { + "choice_owner": { + "role_token": "Mediator" + }, + "choice_name": "Confirm problem" + }, + "choose_between": [ + { + "to": 1, + "from": 1 + } + ] + } + } + ], + "timeout_continuation": "close", + "timeout": 1679038507831 + }, + "case": { + "for_choice": { + "choice_owner": { + "role_token": "Seller" + }, + "choice_name": "Dispute problem" + }, + "choose_between": [ + { + "to": 0, + "from": 0 + } + ] + } + } + ], + "timeout_continuation": "close", + "timeout": 1679038207831 + }, + "pay": 12000000, + "from_account": { + "role_token": "Seller" + } + }, + "case": { + "for_choice": { + "choice_owner": { + "role_token": "Buyer" + }, + "choice_name": "Report problem" + }, + "choose_between": [ + { + "to": 1, + "from": 1 + } + ] + } + } + ], + "timeout_continuation": "close", + "timeout": 1679037907831 + }, + "case": { + "party": { + "role_token": "Buyer" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Seller" + }, + "deposits": 12000000 + } + } + ], + "timeout_continuation": "close", + "timeout": 1679037607831 +} diff --git a/packages/language/core/v1/test/examples/jsons/escrowWithCollateral.json b/packages/language/core/v1/test/examples/jsons/escrowWithCollateral.json index eba750bd..f40eaa4e 100644 --- a/packages/language/core/v1/test/examples/jsons/escrowWithCollateral.json +++ b/packages/language/core/v1/test/examples/jsons/escrowWithCollateral.json @@ -1,167 +1,187 @@ { - "when": [{ - "then": { - "when": [{ - "then": { - "when": [{ - "then": { - "when": [{ - "then": "close", - "case": { - "for_choice": { - "choice_owner": { - "role_token": "Buyer" - }, - "choice_name": "Everything is alright" - }, - "choose_between": [{ - "to": 0, - "from": 0 - }] - } - }, { - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "account": { - "role_token": "Buyer" - } - }, - "then": { - "when": [{ - "then": "close", - "case": { - "for_choice": { - "choice_owner": { - "role_token": "Seller" - }, - "choice_name": "Confirm problem" - }, - "choose_between": [{ - "to": 1, - "from": 1 - }] - } - }, { - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "address": "0000000000000000000000000000000000000000000000000000000000000000" - } - }, - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "address": "0000000000000000000000000000000000000000000000000000000000000000" - } - }, - "then": "close", - "pay": 0, - "from_account": { - "role_token": "Buyer" - } - }, - "pay": 0, - "from_account": { - "role_token": "Seller" - } - }, - "case": { - "for_choice": { - "choice_owner": { - "role_token": "Seller" - }, - "choice_name": "Dispute problem" - }, - "choose_between": [{ - "to": 0, - "from": 0 - }] - } - }], - "timeout_continuation": "close", - "timeout": 1679038852138 - }, - "pay": 0, - "from_account": { - "role_token": "Seller" - } - }, - "case": { - "for_choice": { - "choice_owner": { - "role_token": "Buyer" - }, - "choice_name": "Report problem" - }, - "choose_between": [{ - "to": 1, - "from": 1 - }] - } - }], - "timeout_continuation": "close", - "timeout": 1679038552138 - }, - "case": { - "party": { - "role_token": "Buyer" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Seller" - }, - "deposits": 0 - } - }], - "timeout_continuation": "close", - "timeout": 1679038252138 - }, - "case": { - "party": { - "role_token": "Buyer" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Buyer" - }, - "deposits": 0 - } - }], - "timeout_continuation": "close", - "timeout": 1679037952138 - }, - "case": { - "party": { - "role_token": "Seller" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Seller" - }, - "deposits": 0 - } - }], - "timeout_continuation": "close", - "timeout": 1679037652138 -} \ No newline at end of file + "when": [ + { + "then": { + "when": [ + { + "then": { + "when": [ + { + "then": { + "when": [ + { + "then": "close", + "case": { + "for_choice": { + "choice_owner": { + "role_token": "Buyer" + }, + "choice_name": "Everything is alright" + }, + "choose_between": [ + { + "to": 0, + "from": 0 + } + ] + } + }, + { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "account": { + "role_token": "Buyer" + } + }, + "then": { + "when": [ + { + "then": "close", + "case": { + "for_choice": { + "choice_owner": { + "role_token": "Seller" + }, + "choice_name": "Confirm problem" + }, + "choose_between": [ + { + "to": 1, + "from": 1 + } + ] + } + }, + { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "address": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "address": "0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "then": "close", + "pay": 0, + "from_account": { + "role_token": "Buyer" + } + }, + "pay": 0, + "from_account": { + "role_token": "Seller" + } + }, + "case": { + "for_choice": { + "choice_owner": { + "role_token": "Seller" + }, + "choice_name": "Dispute problem" + }, + "choose_between": [ + { + "to": 0, + "from": 0 + } + ] + } + } + ], + "timeout_continuation": "close", + "timeout": 1679038852138 + }, + "pay": 0, + "from_account": { + "role_token": "Seller" + } + }, + "case": { + "for_choice": { + "choice_owner": { + "role_token": "Buyer" + }, + "choice_name": "Report problem" + }, + "choose_between": [ + { + "to": 1, + "from": 1 + } + ] + } + } + ], + "timeout_continuation": "close", + "timeout": 1679038552138 + }, + "case": { + "party": { + "role_token": "Buyer" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Seller" + }, + "deposits": 0 + } + } + ], + "timeout_continuation": "close", + "timeout": 1679038252138 + }, + "case": { + "party": { + "role_token": "Buyer" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Buyer" + }, + "deposits": 0 + } + } + ], + "timeout_continuation": "close", + "timeout": 1679037952138 + }, + "case": { + "party": { + "role_token": "Seller" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Seller" + }, + "deposits": 0 + } + } + ], + "timeout_continuation": "close", + "timeout": 1679037652138 +} diff --git a/packages/language/core/v1/test/examples/jsons/swap.json b/packages/language/core/v1/test/examples/jsons/swap.json index bd0963bb..743578d3 100644 --- a/packages/language/core/v1/test/examples/jsons/swap.json +++ b/packages/language/core/v1/test/examples/jsons/swap.json @@ -1,75 +1,79 @@ { - "when": [{ - "then": { - "when": [{ - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "role_token": "Dollar provider" - } - }, - "then": { - "token": { - "token_name": "dollar", - "currency_symbol": "85bb65" - }, - "to": { - "party": { - "role_token": "Ada provider" - } - }, - "then": "close", - "pay": 0, - "from_account": { - "role_token": "Dollar provider" - } - }, - "pay": { - "times": 0, - "multiply": 1000000 - }, - "from_account": { - "role_token": "Ada provider" - } - }, - "case": { - "party": { - "role_token": "Dollar provider" - }, - "of_token": { - "token_name": "dollar", - "currency_symbol": "85bb65" - }, - "into_account": { - "role_token": "Dollar provider" - }, - "deposits": 0 - } - }], - "timeout_continuation": "close", - "timeout": 1678970171344 - }, - "case": { - "party": { - "role_token": "Ada provider" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Ada provider" - }, - "deposits": { - "times": 0, - "multiply": 1000000 - } - } - }], - "timeout_continuation": "close", - "timeout": 1678969871344 -} \ No newline at end of file + "when": [ + { + "then": { + "when": [ + { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "role_token": "Dollar provider" + } + }, + "then": { + "token": { + "token_name": "dollar", + "currency_symbol": "85bb65" + }, + "to": { + "party": { + "role_token": "Ada provider" + } + }, + "then": "close", + "pay": 0, + "from_account": { + "role_token": "Dollar provider" + } + }, + "pay": { + "times": 0, + "multiply": 1000000 + }, + "from_account": { + "role_token": "Ada provider" + } + }, + "case": { + "party": { + "role_token": "Dollar provider" + }, + "of_token": { + "token_name": "dollar", + "currency_symbol": "85bb65" + }, + "into_account": { + "role_token": "Dollar provider" + }, + "deposits": 0 + } + } + ], + "timeout_continuation": "close", + "timeout": 1678970171344 + }, + "case": { + "party": { + "role_token": "Ada provider" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Ada provider" + }, + "deposits": { + "times": 0, + "multiply": 1000000 + } + } + } + ], + "timeout_continuation": "close", + "timeout": 1678969871344 +} diff --git a/packages/language/core/v1/test/examples/jsons/zeroCouponBond.json b/packages/language/core/v1/test/examples/jsons/zeroCouponBond.json index 234b886b..0b54d764 100644 --- a/packages/language/core/v1/test/examples/jsons/zeroCouponBond.json +++ b/packages/language/core/v1/test/examples/jsons/zeroCouponBond.json @@ -1,75 +1,79 @@ { - "when": [{ - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "role_token": "Borrower" - } - }, - "then": { - "when": [{ - "then": { - "token": { - "token_name": "", - "currency_symbol": "" - }, - "to": { - "party": { - "role_token": "Lender" - } - }, - "then": "close", - "pay": { - "and": 0, - "add": 0 - }, - "from_account": { - "role_token": "Borrower" - } - }, - "case": { - "party": { - "role_token": "Borrower" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Borrower" - }, - "deposits": { - "and": 0, - "add": 0 - } - } - }], - "timeout_continuation": "close", - "timeout": 1679042482797 - }, - "pay": 0, - "from_account": { - "role_token": "Lender" - } - }, - "case": { - "party": { - "role_token": "Lender" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Lender" - }, - "deposits": 0 - } - }], - "timeout_continuation": "close", - "timeout": 1679042182797 -} \ No newline at end of file + "when": [ + { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "role_token": "Borrower" + } + }, + "then": { + "when": [ + { + "then": { + "token": { + "token_name": "", + "currency_symbol": "" + }, + "to": { + "party": { + "role_token": "Lender" + } + }, + "then": "close", + "pay": { + "and": 0, + "add": 0 + }, + "from_account": { + "role_token": "Borrower" + } + }, + "case": { + "party": { + "role_token": "Borrower" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Borrower" + }, + "deposits": { + "and": 0, + "add": 0 + } + } + } + ], + "timeout_continuation": "close", + "timeout": 1679042482797 + }, + "pay": 0, + "from_account": { + "role_token": "Lender" + } + }, + "case": { + "party": { + "role_token": "Lender" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Lender" + }, + "deposits": 0 + } + } + ], + "timeout_continuation": "close", + "timeout": 1679042182797 +} diff --git a/packages/language/core/v1/test/examples/parsing.spec.ts b/packages/language/core/v1/test/examples/parsing.spec.ts index cf9dd78d..d0517e09 100644 --- a/packages/language/core/v1/test/examples/parsing.spec.ts +++ b/packages/language/core/v1/test/examples/parsing.spec.ts @@ -1,43 +1,53 @@ - -import * as TE from 'fp-ts/lib/TaskEither.js' -import * as E from 'fp-ts/lib/Either.js' - -import '@relmify/jest-fp-ts' -import { pipe } from 'fp-ts/lib/function.js'; -import {formatValidationErrors} from 'jsonbigint-io-ts-reporters' -import {Contract} from '@marlowe.io/language-core-v1' -import * as path from 'path' -import { fileURLToPath } from 'url'; -import {MarloweJSONCodec, minify} from '@marlowe.io/adapter/codec' -import { getFileContents } from '@marlowe.io/adapter/file';; - +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as E from "fp-ts/lib/Either.js"; + +import "@relmify/jest-fp-ts"; +import { pipe } from "fp-ts/lib/function.js"; +import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; +import { Contract } from "@marlowe.io/language-core-v1"; +import * as path from "path"; +import { fileURLToPath } from "url"; +import { MarloweJSONCodec, minify } from "@marlowe.io/adapter/codec"; +import { getFileContents } from "@marlowe.io/adapter/file"; const getfilename = () => fileURLToPath(import.meta.url); -export const currentDirectoryPath = () => path.dirname(getfilename()); - -describe('examples', () => { - -it.each([ 'swap' - , 'escrow' - , 'escrowWithCollateral' - , 'contractForDifferences' - , 'contractForDifferencesWithOracle' - , 'zeroCouponBond' - , 'couponBondGuaranteed' - ]) - ('(%p) can be decoded/encoded and is isomorphic', async (filename) => { - - await pipe( TE.Do - , TE.bind('uncoded', () => getFileContents(path.join(currentDirectoryPath(), `/jsons/${filename}.json`))) - , TE.bind('decoded', ({uncoded}) => TE.of(MarloweJSONCodec.decode(uncoded))) - , TE.bindW('typed', ({decoded}) => - TE.fromEither(pipe( Contract.decode(decoded) - , E.mapLeft(formatValidationErrors)))) - , TE.bindW('encoded', ({typed}) => TE.of(MarloweJSONCodec.encode(typed))) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined()}, - ({encoded,uncoded}) => {expect(minify(encoded)).toEqual(minify(uncoded))})) () - - }) -}) - +export const currentDirectoryPath = () => path.dirname(getfilename()); + +describe("examples", () => { + it.each([ + "swap", + "escrow", + "escrowWithCollateral", + "contractForDifferences", + "contractForDifferencesWithOracle", + "zeroCouponBond", + "couponBondGuaranteed", + ])("(%p) can be decoded/encoded and is isomorphic", async (filename) => { + await pipe( + TE.Do, + TE.bind("uncoded", () => + getFileContents( + path.join(currentDirectoryPath(), `/jsons/${filename}.json`) + ) + ), + TE.bind("decoded", ({ uncoded }) => + TE.of(MarloweJSONCodec.decode(uncoded)) + ), + TE.bindW("typed", ({ decoded }) => + TE.fromEither( + pipe(Contract.decode(decoded), E.mapLeft(formatValidationErrors)) + ) + ), + TE.bindW("encoded", ({ typed }) => TE.of(MarloweJSONCodec.encode(typed))), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + ({ encoded, uncoded }) => { + expect(minify(encoded)).toEqual(minify(uncoded)); + } + ) + )(); + }); +}); diff --git a/packages/language/core/v1/test/semantics/contract/common/payee/accounts/jsons/one-account-with-ada.json b/packages/language/core/v1/test/semantics/contract/common/payee/accounts/jsons/one-account-with-ada.json index 8f77933e..ca236d8c 100644 --- a/packages/language/core/v1/test/semantics/contract/common/payee/accounts/jsons/one-account-with-ada.json +++ b/packages/language/core/v1/test/semantics/contract/common/payee/accounts/jsons/one-account-with-ada.json @@ -1,14 +1,14 @@ [ + [ [ - [ - { - "address": "addr_test1vqpxg5welxsfg8m7gf76unura6esfctexsg0sa8kx4u207ga5zckw" - }, - { - "currency_symbol": "", - "token_name": "" - } - ], - 3000000 - ] - ] \ No newline at end of file + { + "address": "addr_test1vqpxg5welxsfg8m7gf76unura6esfctexsg0sa8kx4u207ga5zckw" + }, + { + "currency_symbol": "", + "token_name": "" + } + ], + 3000000 + ] +] diff --git a/packages/language/core/v1/test/semantics/contract/common/payee/accounts/parsing.spec.ts b/packages/language/core/v1/test/semantics/contract/common/payee/accounts/parsing.spec.ts index abc78004..bd8e3514 100644 --- a/packages/language/core/v1/test/semantics/contract/common/payee/accounts/parsing.spec.ts +++ b/packages/language/core/v1/test/semantics/contract/common/payee/accounts/parsing.spec.ts @@ -1,36 +1,49 @@ +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as E from "fp-ts/lib/Either.js"; -import * as TE from 'fp-ts/lib/TaskEither.js' -import * as E from 'fp-ts/lib/Either.js' - -import { pipe } from 'fp-ts/lib/function.js'; -import {formatValidationErrors} from 'jsonbigint-io-ts-reporters' -import * as path from 'path' -import { MarloweJSONCodec, minify } from '@marlowe.io/adapter/codec'; -import { fileURLToPath } from 'url'; -import { Accounts } from '@marlowe.io/language-core-v1'; -import { getFileContents } from '@marlowe.io/adapter/file'; +import { pipe } from "fp-ts/lib/function.js"; +import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; +import * as path from "path"; +import { MarloweJSONCodec, minify } from "@marlowe.io/adapter/codec"; +import { fileURLToPath } from "url"; +import { Accounts } from "@marlowe.io/language-core-v1"; +import { getFileContents } from "@marlowe.io/adapter/file"; const getfilename = () => fileURLToPath(import.meta.url); -export const currentDirectoryPath = () => path.dirname(getfilename()); - -describe('Accounts', () => { - - it.each(['one-account-with-ada']) - ('(%p) can be decoded/encoded and is isomorphic', async (filename) => { - - await pipe( TE.Do - , TE.bind('uncoded', () => getFileContents(path.join(currentDirectoryPath(), `/jsons/${filename}.json`))) - , TE.bind('decoded', ({uncoded}) => TE.of(MarloweJSONCodec.decode(uncoded))) - , TE.bindW('typed', ({decoded}) => - TE.fromEither(pipe( Accounts.decode(decoded) - , E.mapLeft(formatValidationErrors)))) - , TE.bindW('encoded', ({typed}) => TE.of(MarloweJSONCodec.encode(typed))) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined()}, - ({encoded,uncoded}) => {expect(minify(encoded)).toEqual(minify(uncoded))})) () - - }) - -}) - - +export const currentDirectoryPath = () => path.dirname(getfilename()); + +describe("Accounts", () => { + it.each(["one-account-with-ada"])( + "(%p) can be decoded/encoded and is isomorphic", + async (filename) => { + await pipe( + TE.Do, + TE.bind("uncoded", () => + getFileContents( + path.join(currentDirectoryPath(), `/jsons/${filename}.json`) + ) + ), + TE.bind("decoded", ({ uncoded }) => + TE.of(MarloweJSONCodec.decode(uncoded)) + ), + TE.bindW("typed", ({ decoded }) => + TE.fromEither( + pipe(Accounts.decode(decoded), E.mapLeft(formatValidationErrors)) + ) + ), + TE.bindW("encoded", ({ typed }) => + TE.of(MarloweJSONCodec.encode(typed)) + ), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + ({ encoded, uncoded }) => { + expect(minify(encoded)).toEqual(minify(uncoded)); + } + ) + )(); + } + ); +}); diff --git a/packages/language/core/v1/test/semantics/contract/common/value/jsons/value.json b/packages/language/core/v1/test/semantics/contract/common/value/jsons/value.json index ffa90ed8..b5428c9d 100644 --- a/packages/language/core/v1/test/semantics/contract/common/value/jsons/value.json +++ b/packages/language/core/v1/test/semantics/contract/common/value/jsons/value.json @@ -1,24 +1,24 @@ - { - "divide": { - "times": { - "times": { - "value_of_choice": { - "choice_owner": { - "role_token": "kraken" - }, - "choice_name": "inv-adausd" - } - }, - "multiply": { - "value_of_choice": { - "choice_owner": { - "role_token": "kraken" - }, - "choice_name": "dir-adausd" - } - } - }, - "multiply": 0 - }, - "by": 10000000000000000 -} \ No newline at end of file +{ + "divide": { + "times": { + "times": { + "value_of_choice": { + "choice_owner": { + "role_token": "kraken" + }, + "choice_name": "inv-adausd" + } + }, + "multiply": { + "value_of_choice": { + "choice_owner": { + "role_token": "kraken" + }, + "choice_name": "dir-adausd" + } + } + }, + "multiply": 0 + }, + "by": 10000000000000000 +} diff --git a/packages/language/core/v1/test/semantics/contract/common/value/parsing.spec.ts b/packages/language/core/v1/test/semantics/contract/common/value/parsing.spec.ts index 131b6fb0..2767e379 100644 --- a/packages/language/core/v1/test/semantics/contract/common/value/parsing.spec.ts +++ b/packages/language/core/v1/test/semantics/contract/common/value/parsing.spec.ts @@ -1,37 +1,49 @@ +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as E from "fp-ts/lib/Either.js"; -import * as TE from 'fp-ts/lib/TaskEither.js' -import * as E from 'fp-ts/lib/Either.js' - -import { pipe } from 'fp-ts/lib/function.js'; -import {formatValidationErrors} from 'jsonbigint-io-ts-reporters' -import { Value } from '@marlowe.io/language-core-v1' -import * as path from 'path' -import { MarloweJSONCodec, minify } from '@marlowe.io/adapter/codec'; -import { fileURLToPath } from 'url'; -import { getFileContents } from '@marlowe.io/adapter/file'; - +import { pipe } from "fp-ts/lib/function.js"; +import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; +import { Value } from "@marlowe.io/language-core-v1"; +import * as path from "path"; +import { MarloweJSONCodec, minify } from "@marlowe.io/adapter/codec"; +import { fileURLToPath } from "url"; +import { getFileContents } from "@marlowe.io/adapter/file"; const getfilename = () => fileURLToPath(import.meta.url); -export const currentDirectoryPath = () => path.dirname(getfilename()); - -describe('value', () => { - - it.each(['value']) - ('(%p) can be decoded/encoded and is isomorphic', async (filename) => { - - await pipe( TE.Do - , TE.bind('uncoded', () => getFileContents(path.join(currentDirectoryPath(), `/jsons/${filename}.json`))) - , TE.bind('decoded', ({uncoded}) => TE.of(MarloweJSONCodec.decode(uncoded))) - , TE.bindW('typed', ({decoded}) => - TE.fromEither(pipe( Value.decode(decoded) - , E.mapLeft(formatValidationErrors)))) - , TE.bindW('encoded', ({typed}) => TE.of(MarloweJSONCodec.encode(typed))) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined()}, - ({encoded,uncoded}) => {expect(minify(encoded)).toEqual(minify(uncoded))})) () - - }) - -}) - - +export const currentDirectoryPath = () => path.dirname(getfilename()); + +describe("value", () => { + it.each(["value"])( + "(%p) can be decoded/encoded and is isomorphic", + async (filename) => { + await pipe( + TE.Do, + TE.bind("uncoded", () => + getFileContents( + path.join(currentDirectoryPath(), `/jsons/${filename}.json`) + ) + ), + TE.bind("decoded", ({ uncoded }) => + TE.of(MarloweJSONCodec.decode(uncoded)) + ), + TE.bindW("typed", ({ decoded }) => + TE.fromEither( + pipe(Value.decode(decoded), E.mapLeft(formatValidationErrors)) + ) + ), + TE.bindW("encoded", ({ typed }) => + TE.of(MarloweJSONCodec.encode(typed)) + ), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + ({ encoded, uncoded }) => { + expect(minify(encoded)).toEqual(minify(uncoded)); + } + ) + )(); + } + ); +}); diff --git a/packages/language/core/v1/test/semantics/contract/jsons/close.json b/packages/language/core/v1/test/semantics/contract/jsons/close.json index fbd0dd02..fb98fff2 100644 --- a/packages/language/core/v1/test/semantics/contract/jsons/close.json +++ b/packages/language/core/v1/test/semantics/contract/jsons/close.json @@ -1 +1 @@ -"close" \ No newline at end of file +"close" diff --git a/packages/language/core/v1/test/semantics/contract/jsons/let.json b/packages/language/core/v1/test/semantics/contract/jsons/let.json index 8f3e98cd..514400f0 100644 --- a/packages/language/core/v1/test/semantics/contract/jsons/let.json +++ b/packages/language/core/v1/test/semantics/contract/jsons/let.json @@ -1,6 +1,5 @@ { - "let": "Price in second window", - "be": 0, - "then":"close" - -} \ No newline at end of file + "let": "Price in second window", + "be": 0, + "then": "close" +} diff --git a/packages/language/core/v1/test/semantics/contract/jsons/pay.json b/packages/language/core/v1/test/semantics/contract/jsons/pay.json index d81570d5..f845def6 100644 --- a/packages/language/core/v1/test/semantics/contract/jsons/pay.json +++ b/packages/language/core/v1/test/semantics/contract/jsons/pay.json @@ -1,16 +1,16 @@ { - "token": { - "token_name": "dollar", - "currency_symbol": "85bb65" - }, - "to": { - "party": { - "role_token": "Ada provider" - } - }, - "then": "close", - "pay": 0, - "from_account": { - "role_token": "Dollar provider" - } -} \ No newline at end of file + "token": { + "token_name": "dollar", + "currency_symbol": "85bb65" + }, + "to": { + "party": { + "role_token": "Ada provider" + } + }, + "then": "close", + "pay": 0, + "from_account": { + "role_token": "Dollar provider" + } +} diff --git a/packages/language/core/v1/test/semantics/contract/jsons/when.json b/packages/language/core/v1/test/semantics/contract/jsons/when.json index cf8f735c..b9dc4ad3 100644 --- a/packages/language/core/v1/test/semantics/contract/jsons/when.json +++ b/packages/language/core/v1/test/semantics/contract/jsons/when.json @@ -1,5 +1,5 @@ { - "when": [], - "timeout_continuation": "close", - "timeout": 1678969871344 -} \ No newline at end of file + "when": [], + "timeout_continuation": "close", + "timeout": 1678969871344 +} diff --git a/packages/language/core/v1/test/semantics/contract/parsing.spec.ts b/packages/language/core/v1/test/semantics/contract/parsing.spec.ts index a79edfc0..a6d98c6e 100644 --- a/packages/language/core/v1/test/semantics/contract/parsing.spec.ts +++ b/packages/language/core/v1/test/semantics/contract/parsing.spec.ts @@ -1,39 +1,50 @@ - -import * as TE from 'fp-ts/lib/TaskEither.js' -import * as E from 'fp-ts/lib/Either.js' - -import '@relmify/jest-fp-ts' -import { pipe } from 'fp-ts/lib/function.js'; -import {formatValidationErrors} from 'jsonbigint-io-ts-reporters' -import {Contract} from '@marlowe.io/language-core-v1' -import * as path from 'path' -import { fileURLToPath } from 'url'; -import {MarloweJSONCodec, minify} from '@marlowe.io/adapter/codec' -import { getFileContents } from '@marlowe.io/adapter/file'; +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as E from "fp-ts/lib/Either.js"; + +import "@relmify/jest-fp-ts"; +import { pipe } from "fp-ts/lib/function.js"; +import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; +import { Contract } from "@marlowe.io/language-core-v1"; +import * as path from "path"; +import { fileURLToPath } from "url"; +import { MarloweJSONCodec, minify } from "@marlowe.io/adapter/codec"; +import { getFileContents } from "@marlowe.io/adapter/file"; const getfilename = () => fileURLToPath(import.meta.url); -export const currentDirectoryPath = () => path.dirname(getfilename()); - -describe('contract', () => { - - it.each(['close' - ,'when' - ,'pay' - ,'let' - ]) - ('(%p) can be decoded/encoded and is isomorphic', async (filename) => { - - await pipe( TE.Do - , TE.bind('uncoded', () => getFileContents(path.join(currentDirectoryPath(), `/jsons/${filename}.json`))) - , TE.bind('decoded', ({uncoded}) => TE.of(MarloweJSONCodec.decode(uncoded))) - , TE.bindW('typed', ({decoded}) => - TE.fromEither(pipe( Contract.decode(decoded) - , E.mapLeft(formatValidationErrors)))) - , TE.bindW('encoded', ({typed}) => TE.of(MarloweJSONCodec.encode(typed))) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined()}, - ({encoded,uncoded}) => {expect(minify(encoded)).toEqual(minify(uncoded))})) () - }) -}) - - +export const currentDirectoryPath = () => path.dirname(getfilename()); + +describe("contract", () => { + it.each(["close", "when", "pay", "let"])( + "(%p) can be decoded/encoded and is isomorphic", + async (filename) => { + await pipe( + TE.Do, + TE.bind("uncoded", () => + getFileContents( + path.join(currentDirectoryPath(), `/jsons/${filename}.json`) + ) + ), + TE.bind("decoded", ({ uncoded }) => + TE.of(MarloweJSONCodec.decode(uncoded)) + ), + TE.bindW("typed", ({ decoded }) => + TE.fromEither( + pipe(Contract.decode(decoded), E.mapLeft(formatValidationErrors)) + ) + ), + TE.bindW("encoded", ({ typed }) => + TE.of(MarloweJSONCodec.encode(typed)) + ), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + ({ encoded, uncoded }) => { + expect(minify(encoded)).toEqual(minify(uncoded)); + } + ) + )(); + } + ); +}); diff --git a/packages/language/core/v1/test/semantics/contract/when/action/jsons/deposit.json b/packages/language/core/v1/test/semantics/contract/when/action/jsons/deposit.json index 9def070b..1845276f 100644 --- a/packages/language/core/v1/test/semantics/contract/when/action/jsons/deposit.json +++ b/packages/language/core/v1/test/semantics/contract/when/action/jsons/deposit.json @@ -1,16 +1,16 @@ { - "party": { - "role_token": "Ada provider" - }, - "of_token": { - "token_name": "", - "currency_symbol": "" - }, - "into_account": { - "role_token": "Ada provider" - }, - "deposits": { - "times": 0, - "multiply": 1000000 - } + "party": { + "role_token": "Ada provider" + }, + "of_token": { + "token_name": "", + "currency_symbol": "" + }, + "into_account": { + "role_token": "Ada provider" + }, + "deposits": { + "times": 0, + "multiply": 1000000 + } } diff --git a/packages/language/core/v1/test/semantics/contract/when/action/parsing.spec.ts b/packages/language/core/v1/test/semantics/contract/when/action/parsing.spec.ts index 93ad86f9..4880d64c 100644 --- a/packages/language/core/v1/test/semantics/contract/when/action/parsing.spec.ts +++ b/packages/language/core/v1/test/semantics/contract/when/action/parsing.spec.ts @@ -1,37 +1,50 @@ - -import * as TE from 'fp-ts/lib/TaskEither.js' -import * as E from 'fp-ts/lib/Either.js' - -import '@relmify/jest-fp-ts' -import { pipe } from 'fp-ts/lib/function.js'; -import {formatValidationErrors} from 'jsonbigint-io-ts-reporters' -import {Action} from '@marlowe.io/language-core-v1' -import * as path from 'path' -import { MarloweJSONCodec, minify } from '@marlowe.io/adapter/codec'; -import { getFileContents } from '@marlowe.io/adapter/file'; -import { fileURLToPath } from 'url'; +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as E from "fp-ts/lib/Either.js"; + +import "@relmify/jest-fp-ts"; +import { pipe } from "fp-ts/lib/function.js"; +import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; +import { Action } from "@marlowe.io/language-core-v1"; +import * as path from "path"; +import { MarloweJSONCodec, minify } from "@marlowe.io/adapter/codec"; +import { getFileContents } from "@marlowe.io/adapter/file"; +import { fileURLToPath } from "url"; const getfilename = () => fileURLToPath(import.meta.url); -export const currentDirectoryPath = () => path.dirname(getfilename()); - -describe('contract', () => { - - it.each(['deposit']) - ('(%p) can be decoded/encoded and is isomorphic', async (filename) => { - - await pipe( TE.Do - , TE.bind('uncoded', () => getFileContents(path.join(currentDirectoryPath(), `/jsons/${filename}.json`))) - , TE.bind('decoded', ({uncoded}) => TE.of(MarloweJSONCodec.decode(uncoded))) - , TE.bindW('typed', ({decoded}) => - TE.fromEither(pipe( Action.decode(decoded) - , E.mapLeft(formatValidationErrors)))) - , TE.bindW('encoded', ({typed}) => TE.of(MarloweJSONCodec.encode(typed))) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined()}, - ({encoded,uncoded}) => {expect(minify(encoded)).toEqual(minify(uncoded))})) () - - }) - -}) - - +export const currentDirectoryPath = () => path.dirname(getfilename()); + +describe("contract", () => { + it.each(["deposit"])( + "(%p) can be decoded/encoded and is isomorphic", + async (filename) => { + await pipe( + TE.Do, + TE.bind("uncoded", () => + getFileContents( + path.join(currentDirectoryPath(), `/jsons/${filename}.json`) + ) + ), + TE.bind("decoded", ({ uncoded }) => + TE.of(MarloweJSONCodec.decode(uncoded)) + ), + TE.bindW("typed", ({ decoded }) => + TE.fromEither( + pipe(Action.decode(decoded), E.mapLeft(formatValidationErrors)) + ) + ), + TE.bindW("encoded", ({ typed }) => + TE.of(MarloweJSONCodec.encode(typed)) + ), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + ({ encoded, uncoded }) => { + expect(minify(encoded)).toEqual(minify(uncoded)); + } + ) + )(); + } + ); +}); diff --git a/packages/language/core/v1/test/tsconfig.json b/packages/language/core/v1/test/tsconfig.json index 39b34dfc..fe56c8dc 100644 --- a/packages/language/core/v1/test/tsconfig.json +++ b/packages/language/core/v1/test/tsconfig.json @@ -3,14 +3,14 @@ "compilerOptions": { "outDir": "../test-dist", "paths": { - "@marlowe.io/adapter/*": ["../../../../adapter/src/*"], - "@marlowe.io/language-core-v1/*": ["../../../../language/core/v1/src*"] + "@marlowe.io/adapter/*": ["../../../../adapter/src/*"], + "@marlowe.io/language-core-v1/*": ["../../../../language/core/v1/src*"] }, "types": ["node", "jest"] }, "references": [ - {"path": "../../../../adapter/src"}, - {"path": "../../../../language/core/v1/src"}, - {"path": "../src"} + { "path": "../../../../adapter/src" }, + { "path": "../../../../language/core/v1/src" }, + { "path": "../src" } ] -} \ No newline at end of file +} diff --git a/packages/runtime/client/rest/Readme.md b/packages/runtime/client/rest/Readme.md index f8de0d5b..7b52708b 100644 --- a/packages/runtime/client/rest/Readme.md +++ b/packages/runtime/client/rest/Readme.md @@ -1,2 +1,3 @@ # @marlowe.io/runtime-rest-client -TODO \ No newline at end of file + +TODO diff --git a/packages/runtime/client/rest/package.json b/packages/runtime/client/rest/package.json index da5d1098..4c4249df 100644 --- a/packages/runtime/client/rest/package.json +++ b/packages/runtime/client/rest/package.json @@ -51,4 +51,4 @@ "json-bigint": "^1.0.0", "jsonbigint-io-ts-reporters": "2.0.1" } -} \ No newline at end of file +} diff --git a/packages/runtime/client/rest/src/contract/details.ts b/packages/runtime/client/rest/src/contract/details.ts index 610db1de..afb03cd7 100644 --- a/packages/runtime/client/rest/src/contract/details.ts +++ b/packages/runtime/client/rest/src/contract/details.ts @@ -8,32 +8,29 @@ import { ContractId } from "@marlowe.io/runtime-core"; import { TxStatus } from "./transaction/status.js"; import { RoleName } from "./role.js"; -import { TxOutRef, BlockHeader, Metadata, TextEnvelope,PolicyId } from "@marlowe.io/runtime-core"; - - -export type Payout = t.TypeOf -export const Payout - = t.type( - { payoutId: TxOutRef - , role: RoleName - }) - -export type ContractDetails = t.TypeOf -export const ContractDetails - = t.type( - { contractId: ContractId - , roleTokenMintingPolicyId: PolicyId - , version: MarloweVersion - , status: TxStatus - , block: optionFromNullable(BlockHeader) - , metadata: Metadata - , initialContract: Contract - , currentContract: optionFromNullable(Contract) // 3 actions - , state: optionFromNullable(MarloweState) - , txBody: optionFromNullable(TextEnvelope) - , utxo: optionFromNullable(TxOutRef) - , unclaimedPayouts: t.array(Payout) - }) - - - +import { + TxOutRef, + BlockHeader, + Metadata, + TextEnvelope, + PolicyId, +} from "@marlowe.io/runtime-core"; + +export type Payout = t.TypeOf; +export const Payout = t.type({ payoutId: TxOutRef, role: RoleName }); + +export type ContractDetails = t.TypeOf; +export const ContractDetails = t.type({ + contractId: ContractId, + roleTokenMintingPolicyId: PolicyId, + version: MarloweVersion, + status: TxStatus, + block: optionFromNullable(BlockHeader), + metadata: Metadata, + initialContract: Contract, + currentContract: optionFromNullable(Contract), // 3 actions + state: optionFromNullable(MarloweState), + txBody: optionFromNullable(TextEnvelope), + utxo: optionFromNullable(TxOutRef), + unclaimedPayouts: t.array(Payout), +}); diff --git a/packages/runtime/client/rest/src/contract/endpoints/collection.ts b/packages/runtime/client/rest/src/contract/endpoints/collection.ts index 82708fc8..e498c097 100644 --- a/packages/runtime/client/rest/src/contract/endpoints/collection.ts +++ b/packages/runtime/client/rest/src/contract/endpoints/collection.ts @@ -1,114 +1,169 @@ - -import { AxiosInstance, ParamEncoder, ParamsSerializerOptions } from 'axios'; +import { AxiosInstance, ParamEncoder, ParamsSerializerOptions } from "axios"; import * as t from "io-ts/lib/index.js"; -import * as TE from 'fp-ts/lib/TaskEither.js' -import { pipe } from 'fp-ts/lib/function.js'; -import * as E from 'fp-ts/lib/Either.js' -import * as A from 'fp-ts/lib/Array.js' -import * as O from 'fp-ts/lib/Option.js'; -import { Newtype, iso } from 'newtype-ts' -import { formatValidationErrors } from 'jsonbigint-io-ts-reporters' -import { fromNewtype, optionFromNullable } from 'io-ts-types'; -import { stringify } from 'qs'; - -import { Contract } from '@marlowe.io/language-core-v1'; -import { MarloweVersion } from '@marlowe.io/language-core-v1/version'; - -import * as HTTP from '@marlowe.io/adapter/http'; -import { DecodingError } from '@marlowe.io/adapter/codec'; - -import { Tag, Tags, Metadata, TextEnvelope, unAddressBech32, unTxOutRef, AddressesAndCollaterals } from '@marlowe.io/runtime-core'; - -import { Header } from '../header.js'; -import { RolesConfig } from '../role.js'; +import * as TE from "fp-ts/lib/TaskEither.js"; +import { pipe } from "fp-ts/lib/function.js"; +import * as E from "fp-ts/lib/Either.js"; +import * as A from "fp-ts/lib/Array.js"; +import * as O from "fp-ts/lib/Option.js"; +import { Newtype, iso } from "newtype-ts"; +import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; +import { fromNewtype, optionFromNullable } from "io-ts-types"; +import { stringify } from "qs"; + +import { Contract } from "@marlowe.io/language-core-v1"; +import { MarloweVersion } from "@marlowe.io/language-core-v1/version"; + +import * as HTTP from "@marlowe.io/adapter/http"; +import { DecodingError } from "@marlowe.io/adapter/codec"; + +import { + Tag, + Tags, + Metadata, + TextEnvelope, + unAddressBech32, + unTxOutRef, + AddressesAndCollaterals, +} from "@marlowe.io/runtime-core"; + +import { Header } from "../header.js"; +import { RolesConfig } from "../role.js"; import { ContractId } from "@marlowe.io/runtime-core"; -export interface ContractsRange extends Newtype<{ readonly ContractsRange: unique symbol }, string> {} -export const ContractsRange = fromNewtype(t.string) -export const unContractsRange = iso().unwrap -export const contractsRange = iso().wrap - -export type GETHeadersByRange = (rangeOption: O.Option) => (tags : Tag[])=> TE.TaskEither - - - -export const getHeadersByRangeViaAxios:(axiosInstance: AxiosInstance) => GETHeadersByRange - = (axiosInstance) => (rangeOption) => (tags) => - pipe( ({ url : '/contracts?' + stringify(({tag:tags}), { indices: false }) - , configs : pipe(rangeOption - , O.match( () => ({}) - , range => ({ headers: { Range: unContractsRange(range) }})))}) - , ({url,configs}) => HTTP.GetWithDataAndHeaders(axiosInstance) (url,configs) - , TE.map(([headers,data]) => - ({ data:data - , previousRange: headers['prev-range'] - , nextRange : headers['next-range']})) - , TE.chainW((data) => TE.fromEither(E.mapLeft(formatValidationErrors)(GETByRangeRawResponse.decode(data)))) - , TE.map(rawResponse => - ({ headers: pipe( rawResponse.data.results - , A.map(result => result.resource) - , A.filter(header => eqSetString(new Set(Object.keys(header.tags)),new Set(tags)))) // All logic instead of Any, TODO : Add the flexibility to chose between Any and All - , previousRange: rawResponse.previousRange - , nextRange : rawResponse.nextRange}))) - - -const eqSetString = (xs : Set, ys: Set) => xs.size === ys.size && [...xs].every((x) => ys.has(x)); +export interface ContractsRange + extends Newtype<{ readonly ContractsRange: unique symbol }, string> {} +export const ContractsRange = fromNewtype(t.string); +export const unContractsRange = iso().unwrap; +export const contractsRange = iso().wrap; + +export type GETHeadersByRange = ( + rangeOption: O.Option +) => (tags: Tag[]) => TE.TaskEither; + +export const getHeadersByRangeViaAxios: ( + axiosInstance: AxiosInstance +) => GETHeadersByRange = (axiosInstance) => (rangeOption) => (tags) => + pipe( + { + url: "/contracts?" + stringify({ tag: tags }, { indices: false }), + configs: pipe( + rangeOption, + O.match( + () => ({}), + (range) => ({ headers: { Range: unContractsRange(range) } }) + ) + ), + }, + ({ url, configs }) => + HTTP.GetWithDataAndHeaders(axiosInstance)(url, configs), + TE.map(([headers, data]) => ({ + data: data, + previousRange: headers["prev-range"], + nextRange: headers["next-range"], + })), + TE.chainW((data) => + TE.fromEither( + E.mapLeft(formatValidationErrors)(GETByRangeRawResponse.decode(data)) + ) + ), + TE.map((rawResponse) => ({ + headers: pipe( + rawResponse.data.results, + A.map((result) => result.resource), + A.filter((header) => + eqSetString(new Set(Object.keys(header.tags)), new Set(tags)) + ) + ), // All logic instead of Any, TODO : Add the flexibility to chose between Any and All + previousRange: rawResponse.previousRange, + nextRange: rawResponse.nextRange, + })) + ); + +const eqSetString = (xs: Set, ys: Set) => + xs.size === ys.size && [...xs].every((x) => ys.has(x)); export type GETByRangeRawResponse = t.TypeOf; -export const GETByRangeRawResponse - = t.type({ data : t.type({ results : t.array(t.type({ links : t.type({ contract:t.string, transactions:t.string}) - , resource: Header}))}) - , previousRange : optionFromNullable(ContractsRange) - , nextRange :optionFromNullable(ContractsRange) - }); +export const GETByRangeRawResponse = t.type({ + data: t.type({ + results: t.array( + t.type({ + links: t.type({ contract: t.string, transactions: t.string }), + resource: Header, + }) + ), + }), + previousRange: optionFromNullable(ContractsRange), + nextRange: optionFromNullable(ContractsRange), +}); export type GETByRangeResponse = t.TypeOf; -export const GETByRangeResponse - = t.type({ headers : t.array(Header) - , previousRange : optionFromNullable(ContractsRange) - , nextRange :optionFromNullable(ContractsRange) - }); - -export type POST = ( postContractsRequest: PostContractsRequest - , addressesAndCollaterals: AddressesAndCollaterals) => TE.TaskEither - -export type PostContractsRequest = t.TypeOf -export const PostContractsRequest - = t.intersection( - [ t.type({ contract: Contract - , version: MarloweVersion - , tags : Tags - , metadata: Metadata - , minUTxODeposit: t.number}) - , t.partial({roles: RolesConfig}) - ]) - +export const GETByRangeResponse = t.type({ + headers: t.array(Header), + previousRange: optionFromNullable(ContractsRange), + nextRange: optionFromNullable(ContractsRange), +}); + +export type POST = ( + postContractsRequest: PostContractsRequest, + addressesAndCollaterals: AddressesAndCollaterals +) => TE.TaskEither; + +export type PostContractsRequest = t.TypeOf; +export const PostContractsRequest = t.intersection([ + t.type({ + contract: Contract, + version: MarloweVersion, + tags: Tags, + metadata: Metadata, + minUTxODeposit: t.number, + }), + t.partial({ roles: RolesConfig }), +]); export type ContractTextEnvelope = t.TypeOf; -export const ContractTextEnvelope = t.type({ contractId:ContractId, tx : TextEnvelope}) +export const ContractTextEnvelope = t.type({ + contractId: ContractId, + tx: TextEnvelope, +}); export type PostResponse = t.TypeOf; export const PostResponse = t.type({ - links : t.type({ contract:t.string}), - resource: ContractTextEnvelope - }); - -export const postViaAxios:(axiosInstance: AxiosInstance) => POST - = (axiosInstance) => (postContractsRequest, addressesAndCollaterals) => - pipe( HTTP.Post (axiosInstance) - ( '/contracts' - , postContractsRequest - , { headers: { 'Accept': 'application/vendor.iog.marlowe-runtime.contract-tx-json', - 'Content-Type':'application/json', - 'X-Change-Address': unAddressBech32(addressesAndCollaterals.changeAddress), - 'X-Address' : pipe(addressesAndCollaterals.usedAddresses , A.fromOption, A.flatten, A.map (unAddressBech32) , (a) => a.join(',')), - 'X-Collateral-UTxO': pipe(addressesAndCollaterals.collateralUTxOs, A.fromOption, A.flatten, A.map (unTxOutRef) , (a) => a.join(','))}}) - , TE.chainW((data) => TE.fromEither(E.mapLeft(formatValidationErrors)(PostResponse.decode(data)))) - , TE.map((payload) => payload.resource)) - - - - - + links: t.type({ contract: t.string }), + resource: ContractTextEnvelope, +}); + +export const postViaAxios: (axiosInstance: AxiosInstance) => POST = + (axiosInstance) => (postContractsRequest, addressesAndCollaterals) => + pipe( + HTTP.Post(axiosInstance)("/contracts", postContractsRequest, { + headers: { + Accept: "application/vendor.iog.marlowe-runtime.contract-tx-json", + "Content-Type": "application/json", + "X-Change-Address": unAddressBech32( + addressesAndCollaterals.changeAddress + ), + "X-Address": pipe( + addressesAndCollaterals.usedAddresses, + A.fromOption, + A.flatten, + A.map(unAddressBech32), + (a) => a.join(",") + ), + "X-Collateral-UTxO": pipe( + addressesAndCollaterals.collateralUTxOs, + A.fromOption, + A.flatten, + A.map(unTxOutRef), + (a) => a.join(",") + ), + }, + }), + TE.chainW((data) => + TE.fromEither( + E.mapLeft(formatValidationErrors)(PostResponse.decode(data)) + ) + ), + TE.map((payload) => payload.resource) + ); diff --git a/packages/runtime/client/rest/src/contract/endpoints/singleton.ts b/packages/runtime/client/rest/src/contract/endpoints/singleton.ts index a04d3342..78eb7c34 100644 --- a/packages/runtime/client/rest/src/contract/endpoints/singleton.ts +++ b/packages/runtime/client/rest/src/contract/endpoints/singleton.ts @@ -1,50 +1,66 @@ - -import * as E from 'fp-ts/lib/Either.js' -import * as TE from 'fp-ts/lib/TaskEither.js' -import { pipe } from 'fp-ts/lib/function.js'; +import * as E from "fp-ts/lib/Either.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import { pipe } from "fp-ts/lib/function.js"; import * as t from "io-ts/lib/index.js"; -import { AxiosInstance } from 'axios'; +import { AxiosInstance } from "axios"; -import {formatValidationErrors} from 'jsonbigint-io-ts-reporters' +import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; -import * as HTTP from '@marlowe.io/adapter/http'; -import { DecodingError } from '@marlowe.io/adapter/codec'; +import * as HTTP from "@marlowe.io/adapter/http"; +import { DecodingError } from "@marlowe.io/adapter/codec"; -import { HexTransactionWitnessSet, transactionWitnessSetTextEnvelope } from '@marlowe.io/runtime-core'; +import { + HexTransactionWitnessSet, + transactionWitnessSetTextEnvelope, +} from "@marlowe.io/runtime-core"; -import { ContractDetails } from '../details.js'; +import { ContractDetails } from "../details.js"; import { ContractId, unContractId } from "@marlowe.io/runtime-core"; -export type GET = ( contractId: ContractId) => TE.TaskEither - -type GETPayload = t.TypeOf -const GETPayload = t.type({ links: t.type ({}), resource: ContractDetails}) - -export const getViaAxios:(axiosInstance: AxiosInstance) => GET - = (axiosInstance) => (contractId) => - pipe(HTTP.Get(axiosInstance) - ( contractEndpoint(contractId) - , { headers: { Accept: 'application/json' - , 'Content-Type':'application/json'}}) - , TE.chainW( data => TE.fromEither(E.mapLeft(formatValidationErrors)(GETPayload.decode(data)))) - , TE.map( payload => payload.resource)) - -export type PUT = ( contractId: ContractId - , hexTransactionWitnessSet: HexTransactionWitnessSet) - => TE.TaskEither +export type GET = ( + contractId: ContractId +) => TE.TaskEither; -export const putViaAxios:(axiosInstance: AxiosInstance) => PUT - = (axiosInstance) => (contractId, hexTransactionWitnessSet) => - pipe(HTTP.Put(axiosInstance) - ( contractEndpoint(contractId) - , transactionWitnessSetTextEnvelope(hexTransactionWitnessSet) - , { headers: { Accept: 'application/json' - , 'Content-Type':'application/json'}}) - ) +type GETPayload = t.TypeOf; +const GETPayload = t.type({ links: t.type({}), resource: ContractDetails }); -const contractEndpoint = (contractId: ContractId):string => - (`/contracts/${encodeURIComponent(unContractId(contractId))}`) +export const getViaAxios: (axiosInstance: AxiosInstance) => GET = + (axiosInstance) => (contractId) => + pipe( + HTTP.Get(axiosInstance)(contractEndpoint(contractId), { + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + }), + TE.chainW((data) => + TE.fromEither( + E.mapLeft(formatValidationErrors)(GETPayload.decode(data)) + ) + ), + TE.map((payload) => payload.resource) + ); +export type PUT = ( + contractId: ContractId, + hexTransactionWitnessSet: HexTransactionWitnessSet +) => TE.TaskEither; +export const putViaAxios: (axiosInstance: AxiosInstance) => PUT = + (axiosInstance) => (contractId, hexTransactionWitnessSet) => + pipe( + HTTP.Put(axiosInstance)( + contractEndpoint(contractId), + transactionWitnessSetTextEnvelope(hexTransactionWitnessSet), + { + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + } + ) + ); +const contractEndpoint = (contractId: ContractId): string => + `/contracts/${encodeURIComponent(unContractId(contractId))}`; diff --git a/packages/runtime/client/rest/src/contract/header.ts b/packages/runtime/client/rest/src/contract/header.ts index b025dcff..6f5a5074 100644 --- a/packages/runtime/client/rest/src/contract/header.ts +++ b/packages/runtime/client/rest/src/contract/header.ts @@ -1,23 +1,25 @@ - import * as t from "io-ts/lib/index.js"; import { optionFromNullable } from "io-ts-types"; import { MarloweVersion } from "@marlowe.io/language-core-v1/version"; -import { BlockHeader, Metadata, PolicyId, Tags } from "@marlowe.io/runtime-core"; +import { + BlockHeader, + Metadata, + PolicyId, + Tags, +} from "@marlowe.io/runtime-core"; import { TxStatus } from "./transaction/status.js"; import { ContractId } from "@marlowe.io/runtime-core"; - -export type Header = t.TypeOf -export const Header - = t.type( - { contractId: ContractId - , roleTokenMintingPolicyId: PolicyId - , version: MarloweVersion - , status: TxStatus - , block: optionFromNullable(BlockHeader) - , metadata: Metadata - , tags : Tags - }) \ No newline at end of file +export type Header = t.TypeOf; +export const Header = t.type({ + contractId: ContractId, + roleTokenMintingPolicyId: PolicyId, + version: MarloweVersion, + status: TxStatus, + block: optionFromNullable(BlockHeader), + metadata: Metadata, + tags: Tags, +}); diff --git a/packages/runtime/client/rest/src/contract/index.ts b/packages/runtime/client/rest/src/contract/index.ts index 902a4da5..3c2ddd45 100644 --- a/packages/runtime/client/rest/src/contract/index.ts +++ b/packages/runtime/client/rest/src/contract/index.ts @@ -1,3 +1,3 @@ -export * from './header.js' -export * from './details.js' -export * from './role.js' \ No newline at end of file +export * from "./header.js"; +export * from "./details.js"; +export * from "./role.js"; diff --git a/packages/runtime/client/rest/src/contract/next/endpoint.ts b/packages/runtime/client/rest/src/contract/next/endpoint.ts index 6cac7333..35dcac50 100644 --- a/packages/runtime/client/rest/src/contract/next/endpoint.ts +++ b/packages/runtime/client/rest/src/contract/next/endpoint.ts @@ -1,33 +1,40 @@ -import { AxiosInstance } from 'axios'; -import * as E from 'fp-ts/lib/Either.js' -import * as TE from 'fp-ts/lib/TaskEither.js' -import { pipe } from 'fp-ts/lib/function.js'; -import * as HTTP from '@marlowe.io/adapter/http'; -import {formatValidationErrors} from 'jsonbigint-io-ts-reporters' +import { AxiosInstance } from "axios"; +import * as E from "fp-ts/lib/Either.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import { pipe } from "fp-ts/lib/function.js"; +import * as HTTP from "@marlowe.io/adapter/http"; +import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; import { ContractId, unContractId } from "@marlowe.io/runtime-core"; -import { Environment } from '@marlowe.io/language-core-v1/environment'; -import { Next } from '@marlowe.io/language-core-v1/next'; -import { Party } from '@marlowe.io/language-core-v1/semantics/contract/common/payee/party.js'; -import { stringify } from 'qs'; -import { DecodingError } from '@marlowe.io/adapter/codec'; +import { Environment } from "@marlowe.io/language-core-v1/environment"; +import { Next } from "@marlowe.io/language-core-v1/next"; +import { Party } from "@marlowe.io/language-core-v1/semantics/contract/common/payee/party.js"; +import { stringify } from "qs"; +import { DecodingError } from "@marlowe.io/adapter/codec"; -export type GET - = ( contractId: ContractId) - => (environment : Environment) - => (parties : Party[]) - => TE.TaskEither +export type GET = ( + contractId: ContractId +) => ( + environment: Environment +) => (parties: Party[]) => TE.TaskEither; -export const getViaAxios:(axiosInstance: AxiosInstance) => GET - = (axiosInstance) => (contractId) => (environment) => (parties) => - pipe(HTTP.Get(axiosInstance) - ( contractNextEndpoint(contractId) - + `?validityStart=${environment.validityStart}&validityEnd=${environment.validityEnd}` - + stringify(({party:parties}), { indices: false }) - , { headers: { Accept: 'application/json' - , 'Content-Type':'application/json'}}) - , TE.chainW( data => - TE.fromEither(E.mapLeft(formatValidationErrors)(Next.decode(data))))) +export const getViaAxios: (axiosInstance: AxiosInstance) => GET = + (axiosInstance) => (contractId) => (environment) => (parties) => + pipe( + HTTP.Get(axiosInstance)( + contractNextEndpoint(contractId) + + `?validityStart=${environment.validityStart}&validityEnd=${environment.validityEnd}` + + stringify({ party: parties }, { indices: false }), + { + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + } + ), + TE.chainW((data) => + TE.fromEither(E.mapLeft(formatValidationErrors)(Next.decode(data))) + ) + ); - -const contractNextEndpoint = (contractId: ContractId):string => - (`/contracts/${encodeURIComponent(unContractId(contractId))}/next`) \ No newline at end of file +const contractNextEndpoint = (contractId: ContractId): string => + `/contracts/${encodeURIComponent(unContractId(contractId))}/next`; diff --git a/packages/runtime/client/rest/src/contract/role.ts b/packages/runtime/client/rest/src/contract/role.ts index 5bfc65c5..bbaef7f5 100644 --- a/packages/runtime/client/rest/src/contract/role.ts +++ b/packages/runtime/client/rest/src/contract/role.ts @@ -1,42 +1,44 @@ -import * as t from "io-ts/lib/index.js" +import * as t from "io-ts/lib/index.js"; import { optionFromNullable } from "io-ts-types"; import { PolicyId } from "@marlowe.io/language-core-v1"; import { AddressBech32 } from "@marlowe.io/runtime-core"; - -export type RoleName = string -export const RoleName = t.string - -export type UsePolicy = t.TypeOf -export const UsePolicy = PolicyId - -export type RoleTokenSimple = t.TypeOf -export const RoleTokenSimple = AddressBech32 - -export type TokenMetadataFile = t.TypeOf -export const TokenMetadataFile - = t.type({ name : t.string - , src : t.string - , mediaType : t.string - }) - -export type TokenMetadata = t.TypeOf -export const TokenMetadata - = t.type({ name : optionFromNullable(t.string) - , image : optionFromNullable(t.string) - , mediaType: t.string - , description:t.string - , files:t.array(TokenMetadataFile)}) - -export type RoleTokenAdvanced = t.TypeOf -export const RoleTokenAdvanced = t.type ({address : AddressBech32, metadata : TokenMetadata}) - - -export type RoleTokenConfig = t.TypeOf -export const RoleTokenConfig = t.union ([RoleTokenSimple,RoleTokenAdvanced]) - -export type Mint = t.TypeOf -export const Mint = t.record(RoleName, RoleTokenConfig) - -export type RolesConfig = t.TypeOf -export const RolesConfig = t.union([UsePolicy,Mint]) \ No newline at end of file +export type RoleName = string; +export const RoleName = t.string; + +export type UsePolicy = t.TypeOf; +export const UsePolicy = PolicyId; + +export type RoleTokenSimple = t.TypeOf; +export const RoleTokenSimple = AddressBech32; + +export type TokenMetadataFile = t.TypeOf; +export const TokenMetadataFile = t.type({ + name: t.string, + src: t.string, + mediaType: t.string, +}); + +export type TokenMetadata = t.TypeOf; +export const TokenMetadata = t.type({ + name: optionFromNullable(t.string), + image: optionFromNullable(t.string), + mediaType: t.string, + description: t.string, + files: t.array(TokenMetadataFile), +}); + +export type RoleTokenAdvanced = t.TypeOf; +export const RoleTokenAdvanced = t.type({ + address: AddressBech32, + metadata: TokenMetadata, +}); + +export type RoleTokenConfig = t.TypeOf; +export const RoleTokenConfig = t.union([RoleTokenSimple, RoleTokenAdvanced]); + +export type Mint = t.TypeOf; +export const Mint = t.record(RoleName, RoleTokenConfig); + +export type RolesConfig = t.TypeOf; +export const RolesConfig = t.union([UsePolicy, Mint]); diff --git a/packages/runtime/client/rest/src/contract/transaction/details.ts b/packages/runtime/client/rest/src/contract/transaction/details.ts index 75a58812..1786790f 100644 --- a/packages/runtime/client/rest/src/contract/transaction/details.ts +++ b/packages/runtime/client/rest/src/contract/transaction/details.ts @@ -7,32 +7,35 @@ import { BuiltinByteString, Input } from "@marlowe.io/language-core-v1"; import { MarloweState } from "@marlowe.io/language-core-v1/state"; import { Contract } from "@marlowe.io/language-core-v1"; -import { Tags, Metadata, BlockHeader, TxOutRef, TxId, TextEnvelope } from "@marlowe.io/runtime-core"; +import { + Tags, + Metadata, + BlockHeader, + TxOutRef, + TxId, + TextEnvelope, +} from "@marlowe.io/runtime-core"; import { ContractId } from "@marlowe.io/runtime-core"; import { TransactionId } from "./id.js"; import { TxStatus } from "./status.js"; - -export type Details = t.TypeOf -export const Details - = t.type( - { contractId: ContractId - , transactionId: TransactionId - , continuations : optionFromNullable(BuiltinByteString) - , tags : Tags - , metadata : Metadata - , status: TxStatus - , block: optionFromNullable(BlockHeader) - , inputUtxo : TxOutRef - , inputs : t.array(Input) - , outputUtxo :optionFromNullable(TxOutRef) - , outputContract : optionFromNullable(Contract) - , outputState : optionFromNullable(MarloweState) - , consumingTx : optionFromNullable(TxId) - , invalidBefore : ISO8601 - , invalidHereafter : ISO8601 - , txBody : optionFromNullable(TextEnvelope) - }) - - +export type Details = t.TypeOf; +export const Details = t.type({ + contractId: ContractId, + transactionId: TransactionId, + continuations: optionFromNullable(BuiltinByteString), + tags: Tags, + metadata: Metadata, + status: TxStatus, + block: optionFromNullable(BlockHeader), + inputUtxo: TxOutRef, + inputs: t.array(Input), + outputUtxo: optionFromNullable(TxOutRef), + outputContract: optionFromNullable(Contract), + outputState: optionFromNullable(MarloweState), + consumingTx: optionFromNullable(TxId), + invalidBefore: ISO8601, + invalidHereafter: ISO8601, + txBody: optionFromNullable(TextEnvelope), +}); diff --git a/packages/runtime/client/rest/src/contract/transaction/endpoints/collection.ts b/packages/runtime/client/rest/src/contract/transaction/endpoints/collection.ts index 0a30b300..d3a6ec61 100644 --- a/packages/runtime/client/rest/src/contract/transaction/endpoints/collection.ts +++ b/packages/runtime/client/rest/src/contract/transaction/endpoints/collection.ts @@ -1,106 +1,165 @@ import * as t from "io-ts/lib/index.js"; -import { Newtype, iso } from 'newtype-ts' -import * as E from 'fp-ts/lib/Either.js' -import * as A from 'fp-ts/lib/Array.js' -import * as O from 'fp-ts/lib/Option.js'; -import * as TE from 'fp-ts/lib/TaskEither.js' -import { pipe } from 'fp-ts/lib/function.js'; +import { Newtype, iso } from "newtype-ts"; +import * as E from "fp-ts/lib/Either.js"; +import * as A from "fp-ts/lib/Array.js"; +import * as O from "fp-ts/lib/Option.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import { pipe } from "fp-ts/lib/function.js"; import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; -import { fromNewtype, optionFromNullable } from 'io-ts-types'; +import { fromNewtype, optionFromNullable } from "io-ts-types"; import { AxiosInstance } from "axios"; import { Input } from "@marlowe.io/language-core-v1"; import { MarloweVersion } from "@marlowe.io/language-core-v1/version"; -import * as HTTP from '@marlowe.io/adapter/http'; +import * as HTTP from "@marlowe.io/adapter/http"; import { DecodingError } from "@marlowe.io/adapter/codec"; import { ISO8601 } from "@marlowe.io/adapter/time"; - -import { AddressesAndCollaterals, Metadata, Tags, TextEnvelope, unAddressBech32, unTxOutRef } from "@marlowe.io/runtime-core"; +import { + AddressesAndCollaterals, + Metadata, + Tags, + TextEnvelope, + unAddressBech32, + unTxOutRef, +} from "@marlowe.io/runtime-core"; import { Header } from "../header.js"; import { TransactionId } from "../id.js"; import { ContractId, unContractId } from "@marlowe.io/runtime-core"; - -export interface TransactionsRange extends Newtype<{ readonly TransactionsRange: unique symbol }, string> {} -export const TransactionsRange = fromNewtype(t.string) -export const unTransactionsRange = iso().unwrap -export const transactionsRange = iso().wrap - -export type GETHeadersByRange = (contractId: ContractId,rangeOption: O.Option) => TE.TaskEither - -export const getHeadersByRangeViaAxios:(axiosInstance: AxiosInstance) => GETHeadersByRange - = (axiosInstance) => (contractId,rangeOption) => - pipe( HTTP.GetWithDataAndHeaders - (axiosInstance) - (transactionsEndpoint(contractId) - ,pipe(rangeOption,O.match(() => ({}), range => ({ headers: { Range: unTransactionsRange(range) }})))) - , TE.map(([headers,data]) => - ({ data:data - , previousRange: headers['prev-range'] - , nextRange : headers['next-range']})) - , TE.chainW((data) => TE.fromEither(E.mapLeft(formatValidationErrors)(GETByRangeRawResponse.decode(data)))) - , TE.map((rawResponse) => - ({ headers: pipe(rawResponse.data.results,A.map((result) => result.resource)) - , previousRange: rawResponse.previousRange - , nextRange : rawResponse.nextRange}))) +export interface TransactionsRange + extends Newtype<{ readonly TransactionsRange: unique symbol }, string> {} +export const TransactionsRange = fromNewtype(t.string); +export const unTransactionsRange = iso().unwrap; +export const transactionsRange = iso().wrap; + +export type GETHeadersByRange = ( + contractId: ContractId, + rangeOption: O.Option +) => TE.TaskEither; + +export const getHeadersByRangeViaAxios: ( + axiosInstance: AxiosInstance +) => GETHeadersByRange = (axiosInstance) => (contractId, rangeOption) => + pipe( + HTTP.GetWithDataAndHeaders(axiosInstance)( + transactionsEndpoint(contractId), + pipe( + rangeOption, + O.match( + () => ({}), + (range) => ({ headers: { Range: unTransactionsRange(range) } }) + ) + ) + ), + TE.map(([headers, data]) => ({ + data: data, + previousRange: headers["prev-range"], + nextRange: headers["next-range"], + })), + TE.chainW((data) => + TE.fromEither( + E.mapLeft(formatValidationErrors)(GETByRangeRawResponse.decode(data)) + ) + ), + TE.map((rawResponse) => ({ + headers: pipe( + rawResponse.data.results, + A.map((result) => result.resource) + ), + previousRange: rawResponse.previousRange, + nextRange: rawResponse.nextRange, + })) + ); type GETByRangeRawResponse = t.TypeOf; -const GETByRangeRawResponse - = t.type({ data : t.type({ results : t.array(t.type({ links : t.type({ }) - , resource: Header}))}) - , previousRange : optionFromNullable(TransactionsRange) - , nextRange :optionFromNullable(TransactionsRange) - }); +const GETByRangeRawResponse = t.type({ + data: t.type({ + results: t.array(t.type({ links: t.type({}), resource: Header })), + }), + previousRange: optionFromNullable(TransactionsRange), + nextRange: optionFromNullable(TransactionsRange), +}); export type GETByRangeResponse = t.TypeOf; -export const GETByRangeResponse - = t.type({ headers : t.array(Header) - , previousRange : optionFromNullable(TransactionsRange) - , nextRange :optionFromNullable(TransactionsRange) - }); +export const GETByRangeResponse = t.type({ + headers: t.array(Header), + previousRange: optionFromNullable(TransactionsRange), + nextRange: optionFromNullable(TransactionsRange), +}); export type TransactionTextEnvelope = t.TypeOf; -export const TransactionTextEnvelope = t.type({ contractId:ContractId, transactionId:TransactionId, tx : TextEnvelope}) - -export type POST = ( contractId:ContractId - , postTransactionsRequest: PostTransactionsRequest - , addressesAndCollaterals: AddressesAndCollaterals) => TE.TaskEither - - -export const postViaAxios:(axiosInstance: AxiosInstance) => POST - = (axiosInstance) => (contractId, postTransactionsRequest, addressesAndCollaterals) => - pipe( HTTP.Post (axiosInstance) - ( transactionsEndpoint(contractId) - , postTransactionsRequest - , { headers: { - 'Accept': 'application/vendor.iog.marlowe-runtime.apply-inputs-tx-json', - 'Content-Type':'application/json', - 'X-Change-Address': unAddressBech32(addressesAndCollaterals.changeAddress), - 'X-Address' : pipe(addressesAndCollaterals.usedAddresses , A.fromOption, A.flatten, A.map (unAddressBech32) , (a) => a.join(',')), - 'X-Collateral-UTxO': pipe(addressesAndCollaterals.collateralUTxOs, A.fromOption, A.flatten, A.map (unTxOutRef) , (a) => a.join(','))}}) - , TE.chainW((data) => TE.fromEither(E.mapLeft(formatValidationErrors)(PostResponse.decode(data)))) - , TE.map((payload) => payload.resource)) - -export type PostTransactionsRequest = t.TypeOf -export const PostTransactionsRequest - = t.intersection( - [ t.type({ version: MarloweVersion - , inputs: t.array(Input) - , metadata: Metadata - , tags : Tags - }) - , t.partial({ invalidBefore: ISO8601}) - , t.partial({ invalidHereafter: ISO8601}) - ]) +export const TransactionTextEnvelope = t.type({ + contractId: ContractId, + transactionId: TransactionId, + tx: TextEnvelope, +}); + +export type POST = ( + contractId: ContractId, + postTransactionsRequest: PostTransactionsRequest, + addressesAndCollaterals: AddressesAndCollaterals +) => TE.TaskEither; + +export const postViaAxios: (axiosInstance: AxiosInstance) => POST = + (axiosInstance) => + (contractId, postTransactionsRequest, addressesAndCollaterals) => + pipe( + HTTP.Post(axiosInstance)( + transactionsEndpoint(contractId), + postTransactionsRequest, + { + headers: { + Accept: + "application/vendor.iog.marlowe-runtime.apply-inputs-tx-json", + "Content-Type": "application/json", + "X-Change-Address": unAddressBech32( + addressesAndCollaterals.changeAddress + ), + "X-Address": pipe( + addressesAndCollaterals.usedAddresses, + A.fromOption, + A.flatten, + A.map(unAddressBech32), + (a) => a.join(",") + ), + "X-Collateral-UTxO": pipe( + addressesAndCollaterals.collateralUTxOs, + A.fromOption, + A.flatten, + A.map(unTxOutRef), + (a) => a.join(",") + ), + }, + } + ), + TE.chainW((data) => + TE.fromEither( + E.mapLeft(formatValidationErrors)(PostResponse.decode(data)) + ) + ), + TE.map((payload) => payload.resource) + ); + +export type PostTransactionsRequest = t.TypeOf; +export const PostTransactionsRequest = t.intersection([ + t.type({ + version: MarloweVersion, + inputs: t.array(Input), + metadata: Metadata, + tags: Tags, + }), + t.partial({ invalidBefore: ISO8601 }), + t.partial({ invalidHereafter: ISO8601 }), +]); export type PostResponse = t.TypeOf; export const PostResponse = t.type({ - links : t.type({ transaction:t.string}), - resource: TransactionTextEnvelope - }); + links: t.type({ transaction: t.string }), + resource: TransactionTextEnvelope, +}); -const transactionsEndpoint = (contractId: ContractId):string => - (`/contracts/${encodeURIComponent(unContractId(contractId))}/transactions`) \ No newline at end of file +const transactionsEndpoint = (contractId: ContractId): string => + `/contracts/${encodeURIComponent(unContractId(contractId))}/transactions`; diff --git a/packages/runtime/client/rest/src/contract/transaction/endpoints/singleton.ts b/packages/runtime/client/rest/src/contract/transaction/endpoints/singleton.ts index 7aa0edf3..369e9450 100644 --- a/packages/runtime/client/rest/src/contract/transaction/endpoints/singleton.ts +++ b/packages/runtime/client/rest/src/contract/transaction/endpoints/singleton.ts @@ -1,46 +1,75 @@ - -import * as TE from 'fp-ts/lib/TaskEither.js' -import * as E from 'fp-ts/lib/Either.js' -import { pipe } from 'fp-ts/lib/function.js'; +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as E from "fp-ts/lib/Either.js"; +import { pipe } from "fp-ts/lib/function.js"; import * as t from "io-ts/lib/index.js"; import { AxiosInstance } from "axios"; import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; -import * as HTTP from '@marlowe.io/adapter/http'; -import { DecodingError } from '@marlowe.io/adapter/codec'; +import * as HTTP from "@marlowe.io/adapter/http"; +import { DecodingError } from "@marlowe.io/adapter/codec"; -import { HexTransactionWitnessSet, transactionWitnessSetTextEnvelope } from '@marlowe.io/runtime-core'; +import { + HexTransactionWitnessSet, + transactionWitnessSetTextEnvelope, +} from "@marlowe.io/runtime-core"; import { Details } from "../details.js"; import { ContractId, unContractId } from "@marlowe.io/runtime-core"; import { TransactionId, unTransactionId } from "../id.js"; -export type GET = ( contractId: ContractId, transactionId : TransactionId) => TE.TaskEither - -type GETPayload = t.TypeOf -const GETPayload = t.type({ links: t.type ({}), resource: Details}) - -export const getViaAxios:(axiosInstance: AxiosInstance) => GET - = (axiosInstance) => (contractId,transactionId) => - pipe(HTTP.Get(axiosInstance) - ( endpointURI(contractId,transactionId) - , { headers: { Accept: 'application/json', 'Content-Type':'application/json'}}) - , TE.chainW((data) => TE.fromEither(E.mapLeft(formatValidationErrors)(GETPayload.decode(data)))) - , TE.map((payload) => payload.resource)) - -export type PUT = ( contractId: ContractId - , transactionId : TransactionId - , hexTransactionWitnessSet: HexTransactionWitnessSet) - => TE.TaskEither - -export const putViaAxios:(axiosInstance: AxiosInstance) => PUT - = (axiosInstance) => (contractId,transactionId, hexTransactionWitnessSet) => - pipe(HTTP.Put(axiosInstance) - ( endpointURI(contractId,transactionId) - , transactionWitnessSetTextEnvelope(hexTransactionWitnessSet) - , { headers: { Accept: 'application/json', 'Content-Type':'application/json'}}) - ) - -const endpointURI = (contractId: ContractId, transactionId: TransactionId):string => - (`/contracts/${pipe(contractId,unContractId,encodeURIComponent)}/transactions/${pipe(transactionId,unTransactionId,encodeURIComponent)}`) \ No newline at end of file +export type GET = ( + contractId: ContractId, + transactionId: TransactionId +) => TE.TaskEither; + +type GETPayload = t.TypeOf; +const GETPayload = t.type({ links: t.type({}), resource: Details }); + +export const getViaAxios: (axiosInstance: AxiosInstance) => GET = + (axiosInstance) => (contractId, transactionId) => + pipe( + HTTP.Get(axiosInstance)(endpointURI(contractId, transactionId), { + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + }), + TE.chainW((data) => + TE.fromEither( + E.mapLeft(formatValidationErrors)(GETPayload.decode(data)) + ) + ), + TE.map((payload) => payload.resource) + ); + +export type PUT = ( + contractId: ContractId, + transactionId: TransactionId, + hexTransactionWitnessSet: HexTransactionWitnessSet +) => TE.TaskEither; + +export const putViaAxios: (axiosInstance: AxiosInstance) => PUT = + (axiosInstance) => (contractId, transactionId, hexTransactionWitnessSet) => + pipe( + HTTP.Put(axiosInstance)( + endpointURI(contractId, transactionId), + transactionWitnessSetTextEnvelope(hexTransactionWitnessSet), + { + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + } + ) + ); + +const endpointURI = ( + contractId: ContractId, + transactionId: TransactionId +): string => + `/contracts/${pipe( + contractId, + unContractId, + encodeURIComponent + )}/transactions/${pipe(transactionId, unTransactionId, encodeURIComponent)}`; diff --git a/packages/runtime/client/rest/src/contract/transaction/header.ts b/packages/runtime/client/rest/src/contract/transaction/header.ts index 659b5411..924cddda 100644 --- a/packages/runtime/client/rest/src/contract/transaction/header.ts +++ b/packages/runtime/client/rest/src/contract/transaction/header.ts @@ -2,24 +2,25 @@ import * as t from "io-ts/lib/index.js"; import { optionFromNullable } from "io-ts-types"; import { BuiltinByteString } from "@marlowe.io/language-core-v1"; -import { Tags, Metadata, BlockHeader, TxOutRef } from "@marlowe.io/runtime-core"; - +import { + Tags, + Metadata, + BlockHeader, + TxOutRef, +} from "@marlowe.io/runtime-core"; import { ContractId } from "@marlowe.io/runtime-core"; import { TransactionId } from "./id.js"; import { TxStatus } from "./status.js"; - -export type Header = t.TypeOf -export const Header - = t.type( - { contractId: ContractId - , transactionId: TransactionId - , continuations : optionFromNullable(BuiltinByteString) - , tags : Tags - , metadata : Metadata - , status: TxStatus - , block: optionFromNullable(BlockHeader) - , utxo: optionFromNullable(TxOutRef) - }) - +export type Header = t.TypeOf; +export const Header = t.type({ + contractId: ContractId, + transactionId: TransactionId, + continuations: optionFromNullable(BuiltinByteString), + tags: Tags, + metadata: Metadata, + status: TxStatus, + block: optionFromNullable(BlockHeader), + utxo: optionFromNullable(TxOutRef), +}); diff --git a/packages/runtime/client/rest/src/contract/transaction/id.ts b/packages/runtime/client/rest/src/contract/transaction/id.ts index 0bc1091f..1b5d2950 100644 --- a/packages/runtime/client/rest/src/contract/transaction/id.ts +++ b/packages/runtime/client/rest/src/contract/transaction/id.ts @@ -1,4 +1,3 @@ - import * as t from "io-ts/lib/index.js"; import { iso, Newtype } from "newtype-ts"; import { fromNewtype } from "io-ts-types"; @@ -6,13 +5,14 @@ import { fromNewtype } from "io-ts-types"; import { pipe } from "fp-ts/lib/function.js"; import { TxId } from "@marlowe.io/runtime-core"; -export type TransactionId = Newtype<{ readonly TransactionId: unique symbol }, string> -export const TransactionId = fromNewtype(t.string) -export const unTransactionId = iso().unwrap -export const transactionId = iso().wrap +export type TransactionId = Newtype< + { readonly TransactionId: unique symbol }, + string +>; +export const TransactionId = fromNewtype(t.string); +export const unTransactionId = iso().unwrap; +export const transactionId = iso().wrap; -export const idToTxId : (transactionId : TransactionId) => TxId - = (transactionId) => - pipe( transactionId - , unTransactionId - ) \ No newline at end of file +export const idToTxId: (transactionId: TransactionId) => TxId = ( + transactionId +) => pipe(transactionId, unTransactionId); diff --git a/packages/runtime/client/rest/src/contract/transaction/index.ts b/packages/runtime/client/rest/src/contract/transaction/index.ts index 4315bd62..51c8a332 100644 --- a/packages/runtime/client/rest/src/contract/transaction/index.ts +++ b/packages/runtime/client/rest/src/contract/transaction/index.ts @@ -1 +1 @@ -export * from "./id.js" \ No newline at end of file +export * from "./id.js"; diff --git a/packages/runtime/client/rest/src/contract/transaction/status.ts b/packages/runtime/client/rest/src/contract/transaction/status.ts index f01356ab..e43af142 100644 --- a/packages/runtime/client/rest/src/contract/transaction/status.ts +++ b/packages/runtime/client/rest/src/contract/transaction/status.ts @@ -1,4 +1,8 @@ import * as t from "io-ts/lib/index.js"; -export type TxStatus = t.TypeOf -export const TxStatus = t.union([ t.literal('unsigned'),t.literal('submitted'),t.literal('confirmed') ]) +export type TxStatus = t.TypeOf; +export const TxStatus = t.union([ + t.literal("unsigned"), + t.literal("submitted"), + t.literal("confirmed"), +]); diff --git a/packages/runtime/client/rest/src/index.ts b/packages/runtime/client/rest/src/index.ts index 79964668..98794a31 100644 --- a/packages/runtime/client/rest/src/index.ts +++ b/packages/runtime/client/rest/src/index.ts @@ -1,100 +1,98 @@ +import axios from "axios"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import { pipe } from "fp-ts/lib/function.js"; -import axios from 'axios'; -import * as TE from 'fp-ts/lib/TaskEither.js' -import { pipe } from 'fp-ts/lib/function.js'; +import { MarloweJSONCodec } from "@marlowe.io/adapter/codec"; +import * as HTTP from "@marlowe.io/adapter/http"; -import { MarloweJSONCodec } from '@marlowe.io/adapter/codec'; -import * as HTTP from '@marlowe.io/adapter/http'; +import * as Payouts from "./payout/endpoints/collection.js"; +import * as Payout from "./payout/endpoints/singleton.js"; -import * as Payouts from './payout/endpoints/collection.js'; -import * as Payout from './payout/endpoints/singleton.js'; - -import * as Withdrawal from './withdrawal/endpoints/singleton.js'; -import * as Withdrawals from './withdrawal/endpoints/collection.js'; -import * as Contract from './contract/endpoints/singleton.js'; -import * as Contracts from './contract/endpoints/collection.js'; -import * as Transaction from './contract/transaction/endpoints/singleton.js'; -import * as Transactions from './contract/transaction/endpoints/collection.js'; -import * as ContractNext from './contract/next/endpoint.js'; +import * as Withdrawal from "./withdrawal/endpoints/singleton.js"; +import * as Withdrawals from "./withdrawal/endpoints/collection.js"; +import * as Contract from "./contract/endpoints/singleton.js"; +import * as Contracts from "./contract/endpoints/collection.js"; +import * as Transaction from "./contract/transaction/endpoints/singleton.js"; +import * as Transactions from "./contract/transaction/endpoints/collection.js"; +import * as ContractNext from "./contract/next/endpoint.js"; // import curlirize from 'axios-curlirize'; - -export * from './contract/index.js' -export * from './withdrawal/index.js' -export * from './payout/index.js' +export * from "./contract/index.js"; +export * from "./withdrawal/index.js"; +export * from "./payout/index.js"; export interface RestAPI { - healthcheck : () => TE.TaskEither - payouts : { - getHeadersByRange: Payouts.GETHeadersByRange - get: Payout.GET - } + healthcheck: () => TE.TaskEither; + payouts: { + getHeadersByRange: Payouts.GETHeadersByRange; + get: Payout.GET; + }; withdrawals: { - getHeadersByRange: Withdrawals.GETHeadersByRange - post: Withdrawals.POST + getHeadersByRange: Withdrawals.GETHeadersByRange; + post: Withdrawals.POST; withdrawal: { - get: Withdrawal.GET - put: Withdrawal.PUT - } - } + get: Withdrawal.GET; + put: Withdrawal.PUT; + }; + }; contracts: { - getHeadersByRange: Contracts.GETHeadersByRange - post: Contracts.POST + getHeadersByRange: Contracts.GETHeadersByRange; + post: Contracts.POST; contract: { - get: Contract.GET - put: Contract.PUT - next: ContractNext.GET + get: Contract.GET; + put: Contract.PUT; + next: ContractNext.GET; transactions: { - getHeadersByRange: Transactions.GETHeadersByRange - post: Transactions.POST + getHeadersByRange: Transactions.GETHeadersByRange; + post: Transactions.POST; transaction: { - get: Transaction.GET - put: Transaction.PUT - } - } - } - } + get: Transaction.GET; + put: Transaction.PUT; + }; + }; + }; + }; } -export const mkRestClient : (baseURL: string) => RestAPI = - (baseURL) => - pipe(axios.create - ({ baseURL:baseURL - , transformRequest: MarloweJSONCodec.encode - , transformResponse: MarloweJSONCodec.decode - }) - // , (axiosInstance) => {curlirize(axiosInstance) ;return axiosInstance } - , (axiosInstance) => - ({ healthcheck: () => HTTP.Get(axiosInstance)('/healthcheck') - , payouts : - { getHeadersByRange: Payouts.getHeadersByRangeViaAxios(axiosInstance) - , get: Payout.getViaAxios(axiosInstance) - } - , withdrawals: - { getHeadersByRange: Withdrawals.getHeadersByRangeViaAxios(axiosInstance) - , post: Withdrawals.postViaAxios(axiosInstance) - , withdrawal: - { get: Withdrawal.getViaAxios(axiosInstance) - , put: Withdrawal.putViaAxios(axiosInstance)} - } - , contracts: - { getHeadersByRange: Contracts.getHeadersByRangeViaAxios(axiosInstance) - , post: Contracts.postViaAxios(axiosInstance) - , contract: - { get: Contract.getViaAxios(axiosInstance) - , put: Contract.putViaAxios(axiosInstance) - , next: ContractNext.getViaAxios(axiosInstance) - , transactions: - { getHeadersByRange: Transactions.getHeadersByRangeViaAxios(axiosInstance) - , post: Transactions.postViaAxios(axiosInstance) - , transaction: - { get: Transaction.getViaAxios(axiosInstance) - , put: Transaction.putViaAxios(axiosInstance) - } - } - } - } - })) - - - +export const mkRestClient: (baseURL: string) => RestAPI = (baseURL) => + pipe( + axios.create({ + baseURL: baseURL, + transformRequest: MarloweJSONCodec.encode, + transformResponse: MarloweJSONCodec.decode, + }), + // , (axiosInstance) => {curlirize(axiosInstance) ;return axiosInstance } + (axiosInstance) => ({ + healthcheck: () => HTTP.Get(axiosInstance)("/healthcheck"), + payouts: { + getHeadersByRange: Payouts.getHeadersByRangeViaAxios(axiosInstance), + get: Payout.getViaAxios(axiosInstance), + }, + withdrawals: { + getHeadersByRange: Withdrawals.getHeadersByRangeViaAxios(axiosInstance), + post: Withdrawals.postViaAxios(axiosInstance), + withdrawal: { + get: Withdrawal.getViaAxios(axiosInstance), + put: Withdrawal.putViaAxios(axiosInstance), + }, + }, + contracts: { + getHeadersByRange: Contracts.getHeadersByRangeViaAxios(axiosInstance), + post: Contracts.postViaAxios(axiosInstance), + contract: { + get: Contract.getViaAxios(axiosInstance), + put: Contract.putViaAxios(axiosInstance), + next: ContractNext.getViaAxios(axiosInstance), + transactions: { + getHeadersByRange: + Transactions.getHeadersByRangeViaAxios(axiosInstance), + post: Transactions.postViaAxios(axiosInstance), + transaction: { + get: Transaction.getViaAxios(axiosInstance), + put: Transaction.putViaAxios(axiosInstance), + }, + }, + }, + }, + }) + ); diff --git a/packages/runtime/client/rest/src/payout/details.ts b/packages/runtime/client/rest/src/payout/details.ts index 5d07f9b9..de5454be 100644 --- a/packages/runtime/client/rest/src/payout/details.ts +++ b/packages/runtime/client/rest/src/payout/details.ts @@ -1,31 +1,30 @@ - import * as t from "io-ts/lib/index.js"; import { optionFromNullable } from "io-ts-types"; -import { ContractId, AssetId, PayoutId, AddressBech32, WithdrawalId, AssetQuantity } from "@marlowe.io/runtime-core"; +import { + ContractId, + AssetId, + PayoutId, + AddressBech32, + WithdrawalId, + AssetQuantity, +} from "@marlowe.io/runtime-core"; import { PayoutStatus } from "./status.js"; -export type Tokens = t.TypeOf -export const Tokens = t.record(t.string, t.record(t.string, t.bigint)) - -export type Assets = t.TypeOf -export const Assets - = t.type( - { lovelace: AssetQuantity - , tokens: Tokens - }) - -export type PayoutDetails = t.TypeOf -export const PayoutDetails - = t.type( - { payoutId: PayoutId - , contractId: ContractId - , withdrawalId : optionFromNullable(WithdrawalId) - , role: AssetId - , payoutValidatorAddress: AddressBech32 - , status : PayoutStatus - , assets : Assets - }) - - +export type Tokens = t.TypeOf; +export const Tokens = t.record(t.string, t.record(t.string, t.bigint)); + +export type Assets = t.TypeOf; +export const Assets = t.type({ lovelace: AssetQuantity, tokens: Tokens }); + +export type PayoutDetails = t.TypeOf; +export const PayoutDetails = t.type({ + payoutId: PayoutId, + contractId: ContractId, + withdrawalId: optionFromNullable(WithdrawalId), + role: AssetId, + payoutValidatorAddress: AddressBech32, + status: PayoutStatus, + assets: Assets, +}); diff --git a/packages/runtime/client/rest/src/payout/endpoints/collection.ts b/packages/runtime/client/rest/src/payout/endpoints/collection.ts index a14cf99c..65f680ba 100644 --- a/packages/runtime/client/rest/src/payout/endpoints/collection.ts +++ b/packages/runtime/client/rest/src/payout/endpoints/collection.ts @@ -1,71 +1,118 @@ - -import { AxiosInstance } from 'axios'; +import { AxiosInstance } from "axios"; import * as t from "io-ts/lib/index.js"; -import * as TE from 'fp-ts/lib/TaskEither.js' -import { pipe } from 'fp-ts/lib/function.js'; -import * as E from 'fp-ts/lib/Either.js' -import * as A from 'fp-ts/lib/Array.js' -import * as O from 'fp-ts/lib/Option.js'; -import { Newtype, iso } from 'newtype-ts' -import { formatValidationErrors } from 'jsonbigint-io-ts-reporters' -import { fromNewtype, optionFromNullable } from 'io-ts-types'; -import { stringify } from 'qs'; +import * as TE from "fp-ts/lib/TaskEither.js"; +import { pipe } from "fp-ts/lib/function.js"; +import * as E from "fp-ts/lib/Either.js"; +import * as A from "fp-ts/lib/Array.js"; +import * as O from "fp-ts/lib/Option.js"; +import { Newtype, iso } from "newtype-ts"; +import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; +import { fromNewtype, optionFromNullable } from "io-ts-types"; +import { stringify } from "qs"; -import * as HTTP from '@marlowe.io/adapter/http'; -import { DecodingError } from '@marlowe.io/adapter/codec'; +import * as HTTP from "@marlowe.io/adapter/http"; +import { DecodingError } from "@marlowe.io/adapter/codec"; -import { AssetId, unPolicyId, unContractId } from '@marlowe.io/runtime-core'; +import { AssetId, unPolicyId, unContractId } from "@marlowe.io/runtime-core"; import { ContractId } from "@marlowe.io/runtime-core"; -import { PayoutHeader } from '../header.js'; -import { PayoutStatus } from '../status.js'; - -export interface ContractsRange extends Newtype<{ readonly ContractsRange: unique symbol }, string> {} -export const ContractsRange = fromNewtype(t.string) -export const unContractsRange = iso().unwrap -export const contractsRange = iso().wrap +import { PayoutHeader } from "../header.js"; +import { PayoutStatus } from "../status.js"; -export type GETHeadersByRange = (rangeOption: O.Option) - => (contractIds : ContractId[]) - => (roles : AssetId[]) - => (statusOption : O.Option) - => TE.TaskEither +export interface ContractsRange + extends Newtype<{ readonly ContractsRange: unique symbol }, string> {} +export const ContractsRange = fromNewtype(t.string); +export const unContractsRange = iso().unwrap; +export const contractsRange = iso().wrap; -const roleToParameter = (roleToken : AssetId) => `${unPolicyId(roleToken.policyId)}.${roleToken.assetName}` -const contractIdToParameter = (contractId : ContractId) => unContractId(contractId) -const statusOptionToParameter = (statusOption : O.Option) => pipe ( statusOption, O.match(() => '', a => `status=${a}&`)) +export type GETHeadersByRange = ( + rangeOption: O.Option +) => ( + contractIds: ContractId[] +) => ( + roles: AssetId[] +) => ( + statusOption: O.Option +) => TE.TaskEither; -export const getHeadersByRangeViaAxios:(axiosInstance: AxiosInstance) => GETHeadersByRange - = (axiosInstance) => (rangeOption) => (contractIds) => (roles) => (statusOption) => - pipe( ({ url : '/payouts?' + statusOptionToParameter(statusOption) + stringify(({contractId:contractIds.map(contractIdToParameter) - ,roleToken:roles.map(roleToParameter)}), { indices: false }) - , configs : pipe(rangeOption - , O.match( () => ({}) - , range => ({ headers: { Range: unContractsRange(range) }})))}) - , ({url,configs}) => HTTP.GetWithDataAndHeaders(axiosInstance) (url,configs) - , TE.map(([headers,data]) => - ({ data:data - , previousRange: headers['prev-range'] - , nextRange : headers['next-range']})) - , TE.chainW((data) => TE.fromEither(E.mapLeft(formatValidationErrors)(GETByRangeRawResponse.decode(data)))) - , TE.map(rawResponse => - ({ headers: pipe( rawResponse.data.results, A.map(result => result.resource)) - , previousRange: rawResponse.previousRange - , nextRange : rawResponse.nextRange}))) +const roleToParameter = (roleToken: AssetId) => + `${unPolicyId(roleToken.policyId)}.${roleToken.assetName}`; +const contractIdToParameter = (contractId: ContractId) => + unContractId(contractId); +const statusOptionToParameter = (statusOption: O.Option) => + pipe( + statusOption, + O.match( + () => "", + (a) => `status=${a}&` + ) + ); +export const getHeadersByRangeViaAxios: ( + axiosInstance: AxiosInstance +) => GETHeadersByRange = + (axiosInstance) => + (rangeOption) => + (contractIds) => + (roles) => + (statusOption) => + pipe( + { + url: + "/payouts?" + + statusOptionToParameter(statusOption) + + stringify( + { + contractId: contractIds.map(contractIdToParameter), + roleToken: roles.map(roleToParameter), + }, + { indices: false } + ), + configs: pipe( + rangeOption, + O.match( + () => ({}), + (range) => ({ headers: { Range: unContractsRange(range) } }) + ) + ), + }, + ({ url, configs }) => + HTTP.GetWithDataAndHeaders(axiosInstance)(url, configs), + TE.map(([headers, data]) => ({ + data: data, + previousRange: headers["prev-range"], + nextRange: headers["next-range"], + })), + TE.chainW((data) => + TE.fromEither( + E.mapLeft(formatValidationErrors)(GETByRangeRawResponse.decode(data)) + ) + ), + TE.map((rawResponse) => ({ + headers: pipe( + rawResponse.data.results, + A.map((result) => result.resource) + ), + previousRange: rawResponse.previousRange, + nextRange: rawResponse.nextRange, + })) + ); export type GETByRangeRawResponse = t.TypeOf; -export const GETByRangeRawResponse - = t.type({ data : t.type({ results : t.array(t.type({ links : t.type({ payout:t.string}) - , resource: PayoutHeader}))}) - , previousRange : optionFromNullable(ContractsRange) - , nextRange :optionFromNullable(ContractsRange) - }); +export const GETByRangeRawResponse = t.type({ + data: t.type({ + results: t.array( + t.type({ links: t.type({ payout: t.string }), resource: PayoutHeader }) + ), + }), + previousRange: optionFromNullable(ContractsRange), + nextRange: optionFromNullable(ContractsRange), +}); export type GETByRangeResponse = t.TypeOf; -export const GETByRangeResponse - = t.type({ headers : t.array(PayoutHeader) - , previousRange : optionFromNullable(ContractsRange) - , nextRange :optionFromNullable(ContractsRange) - }); +export const GETByRangeResponse = t.type({ + headers: t.array(PayoutHeader), + previousRange: optionFromNullable(ContractsRange), + nextRange: optionFromNullable(ContractsRange), +}); diff --git a/packages/runtime/client/rest/src/payout/endpoints/singleton.ts b/packages/runtime/client/rest/src/payout/endpoints/singleton.ts index adf4ef26..d62fd002 100644 --- a/packages/runtime/client/rest/src/payout/endpoints/singleton.ts +++ b/packages/runtime/client/rest/src/payout/endpoints/singleton.ts @@ -1,36 +1,41 @@ - -import * as E from 'fp-ts/lib/Either.js' -import * as TE from 'fp-ts/lib/TaskEither.js' -import { pipe } from 'fp-ts/lib/function.js'; +import * as E from "fp-ts/lib/Either.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import { pipe } from "fp-ts/lib/function.js"; import * as t from "io-ts/lib/index.js"; -import { AxiosInstance } from 'axios'; +import { AxiosInstance } from "axios"; -import {formatValidationErrors} from 'jsonbigint-io-ts-reporters' +import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; -import * as HTTP from '@marlowe.io/adapter/http'; -import { DecodingError } from '@marlowe.io/adapter/codec'; +import * as HTTP from "@marlowe.io/adapter/http"; +import { DecodingError } from "@marlowe.io/adapter/codec"; import { PayoutId, unPayoutId } from "@marlowe.io/runtime-core"; -import { PayoutDetails } from '../details.js'; - -export type GET = ( payoutId: PayoutId) => TE.TaskEither - -type GETPayload = t.TypeOf -const GETPayload = t.type({ links: t.type ({}), resource: PayoutDetails}) - -export const getViaAxios:(axiosInstance: AxiosInstance) => GET - = (axiosInstance) => (contractId) => - pipe(HTTP.Get(axiosInstance) - ( contractEndpoint(contractId) - , { headers: { Accept: 'application/json' - , 'Content-Type':'application/json'}}) - , TE.chainW( data => TE.fromEither(E.mapLeft(formatValidationErrors)(GETPayload.decode(data)))) - , TE.map( payload => payload.resource)) - - -const contractEndpoint = (payoutId: PayoutId):string => - (`/payouts/${encodeURIComponent(unPayoutId(payoutId))}`) - - - +import { PayoutDetails } from "../details.js"; + +export type GET = ( + payoutId: PayoutId +) => TE.TaskEither; + +type GETPayload = t.TypeOf; +const GETPayload = t.type({ links: t.type({}), resource: PayoutDetails }); + +export const getViaAxios: (axiosInstance: AxiosInstance) => GET = + (axiosInstance) => (contractId) => + pipe( + HTTP.Get(axiosInstance)(contractEndpoint(contractId), { + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + }), + TE.chainW((data) => + TE.fromEither( + E.mapLeft(formatValidationErrors)(GETPayload.decode(data)) + ) + ), + TE.map((payload) => payload.resource) + ); + +const contractEndpoint = (payoutId: PayoutId): string => + `/payouts/${encodeURIComponent(unPayoutId(payoutId))}`; diff --git a/packages/runtime/client/rest/src/payout/header.ts b/packages/runtime/client/rest/src/payout/header.ts index 30eb7455..c7a709f2 100644 --- a/packages/runtime/client/rest/src/payout/header.ts +++ b/packages/runtime/client/rest/src/payout/header.ts @@ -1,16 +1,19 @@ - import * as t from "io-ts/lib/index.js"; -import { ContractId, AssetId, PayoutId, WithdrawalId } from "@marlowe.io/runtime-core"; +import { + ContractId, + AssetId, + PayoutId, + WithdrawalId, +} from "@marlowe.io/runtime-core"; import { PayoutStatus } from "./status.js"; import { optionFromNullable } from "io-ts-types"; -export type PayoutHeader = t.TypeOf -export const PayoutHeader - = t.type( - { contractId: ContractId - , payoutId: PayoutId - , withdrawalId : optionFromNullable(WithdrawalId) - , role: AssetId - , status : PayoutStatus - }) \ No newline at end of file +export type PayoutHeader = t.TypeOf; +export const PayoutHeader = t.type({ + contractId: ContractId, + payoutId: PayoutId, + withdrawalId: optionFromNullable(WithdrawalId), + role: AssetId, + status: PayoutStatus, +}); diff --git a/packages/runtime/client/rest/src/payout/index.ts b/packages/runtime/client/rest/src/payout/index.ts index ba910381..f59d736e 100644 --- a/packages/runtime/client/rest/src/payout/index.ts +++ b/packages/runtime/client/rest/src/payout/index.ts @@ -1,3 +1,3 @@ -export * from './details.js' -export * from './header.js' -export * from './status.js' \ No newline at end of file +export * from "./details.js"; +export * from "./header.js"; +export * from "./status.js"; diff --git a/packages/runtime/client/rest/src/payout/status.ts b/packages/runtime/client/rest/src/payout/status.ts index b3f6241c..abb7021a 100644 --- a/packages/runtime/client/rest/src/payout/status.ts +++ b/packages/runtime/client/rest/src/payout/status.ts @@ -1,14 +1,10 @@ - import * as t from "io-ts/lib/index.js"; -export type Available = t.TypeOf -export const Available = t.literal('available') - -export type Withdrawn = t.TypeOf -export const Withdrawn = t.literal('withdrawn') - -export type PayoutStatus = t.TypeOf -export const PayoutStatus = t.union ([Available,Withdrawn]) - +export type Available = t.TypeOf; +export const Available = t.literal("available"); +export type Withdrawn = t.TypeOf; +export const Withdrawn = t.literal("withdrawn"); +export type PayoutStatus = t.TypeOf; +export const PayoutStatus = t.union([Available, Withdrawn]); diff --git a/packages/runtime/client/rest/src/tsconfig.json b/packages/runtime/client/rest/src/tsconfig.json index e1e80755..1ae4c010 100644 --- a/packages/runtime/client/rest/src/tsconfig.json +++ b/packages/runtime/client/rest/src/tsconfig.json @@ -11,6 +11,6 @@ "references": [ { "path": "../../../../adapter/src" }, { "path": "../../../../language/core/v1/src" }, - { "path": "../../../core/src" }, + { "path": "../../../core/src" } ] } diff --git a/packages/runtime/client/rest/src/withdrawal/details.ts b/packages/runtime/client/rest/src/withdrawal/details.ts index fce27b69..1eae659e 100644 --- a/packages/runtime/client/rest/src/withdrawal/details.ts +++ b/packages/runtime/client/rest/src/withdrawal/details.ts @@ -1,4 +1,3 @@ - import * as t from "io-ts/lib/index.js"; import { TxStatus } from "../contract/transaction/status.js"; @@ -7,13 +6,10 @@ import { optionFromNullable } from "io-ts-types/lib/optionFromNullable.js"; import { BlockHeader, WithdrawalId } from "@marlowe.io/runtime-core"; import { PayoutHeader } from "../payout/header.js"; - -export type WithdrawalDetails = t.TypeOf -export const WithdrawalDetails - = t.type( - { withdrawalId: WithdrawalId - , status: TxStatus - , block: optionFromNullable(BlockHeader) - , payouts : t.array(PayoutHeader) - }) - +export type WithdrawalDetails = t.TypeOf; +export const WithdrawalDetails = t.type({ + withdrawalId: WithdrawalId, + status: TxStatus, + block: optionFromNullable(BlockHeader), + payouts: t.array(PayoutHeader), +}); diff --git a/packages/runtime/client/rest/src/withdrawal/endpoints/collection.ts b/packages/runtime/client/rest/src/withdrawal/endpoints/collection.ts index bcf244b4..3c31837c 100644 --- a/packages/runtime/client/rest/src/withdrawal/endpoints/collection.ts +++ b/packages/runtime/client/rest/src/withdrawal/endpoints/collection.ts @@ -1,89 +1,147 @@ +import { AxiosInstance } from "axios"; -import { AxiosInstance } from 'axios'; - -import * as TE from 'fp-ts/lib/TaskEither.js' -import { pipe } from 'fp-ts/lib/function.js'; +import * as TE from "fp-ts/lib/TaskEither.js"; +import { pipe } from "fp-ts/lib/function.js"; import * as t from "io-ts/lib/index.js"; -import * as E from 'fp-ts/lib/Either.js' -import * as A from 'fp-ts/lib/Array.js' -import * as O from 'fp-ts/lib/Option.js'; - -import { Newtype, iso } from 'newtype-ts' -import { fromNewtype, optionFromNullable } from 'io-ts-types'; - -import { formatValidationErrors } from 'jsonbigint-io-ts-reporters' - -import * as HTTP from '@marlowe.io/adapter/http'; -import { DecodingError } from '@marlowe.io/adapter/codec'; - -import { AddressesAndCollaterals, PayoutId, TextEnvelope, WithdrawalId, unAddressBech32, unTxOutRef } from '@marlowe.io/runtime-core'; - -import { WithdrawalHeader } from '../header.js'; - - -export interface WithdrawalsRange extends Newtype<{ readonly WithdrawalsRange: unique symbol }, string> {} -export const WithdrawalsRange = fromNewtype(t.string) -export const unWithdrawalsRange = iso().unwrap -export const contractsRange = iso().wrap - -export type GETHeadersByRange = (rangeOption: O.Option) => TE.TaskEither - -export const getHeadersByRangeViaAxios:(axiosInstance: AxiosInstance) => GETHeadersByRange - = (axiosInstance) => (rangeOption) => - pipe( HTTP.GetWithDataAndHeaders(axiosInstance)( '/withdrawals',pipe(rangeOption,O.match(() => ({}), range => ({ headers: { Range: unWithdrawalsRange(range) }})))) - , TE.map(([headers,data]) => - ({ data:data - , previousRange: headers['prev-range'] - , nextRange : headers['next-range']})) - , TE.chainW((data) => TE.fromEither(E.mapLeft(formatValidationErrors)(GETByRangeRawResponse.decode(data)))) - , TE.map((rawResponse) => - ({ headers: pipe(rawResponse.data.results,A.map((result) => result.resource)) - , previousRange: rawResponse.previousRange - , nextRange : rawResponse.nextRange}))) +import * as E from "fp-ts/lib/Either.js"; +import * as A from "fp-ts/lib/Array.js"; +import * as O from "fp-ts/lib/Option.js"; + +import { Newtype, iso } from "newtype-ts"; +import { fromNewtype, optionFromNullable } from "io-ts-types"; + +import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; + +import * as HTTP from "@marlowe.io/adapter/http"; +import { DecodingError } from "@marlowe.io/adapter/codec"; + +import { + AddressesAndCollaterals, + PayoutId, + TextEnvelope, + WithdrawalId, + unAddressBech32, + unTxOutRef, +} from "@marlowe.io/runtime-core"; + +import { WithdrawalHeader } from "../header.js"; + +export interface WithdrawalsRange + extends Newtype<{ readonly WithdrawalsRange: unique symbol }, string> {} +export const WithdrawalsRange = fromNewtype(t.string); +export const unWithdrawalsRange = iso().unwrap; +export const contractsRange = iso().wrap; + +export type GETHeadersByRange = ( + rangeOption: O.Option +) => TE.TaskEither; + +export const getHeadersByRangeViaAxios: ( + axiosInstance: AxiosInstance +) => GETHeadersByRange = (axiosInstance) => (rangeOption) => + pipe( + HTTP.GetWithDataAndHeaders(axiosInstance)( + "/withdrawals", + pipe( + rangeOption, + O.match( + () => ({}), + (range) => ({ headers: { Range: unWithdrawalsRange(range) } }) + ) + ) + ), + TE.map(([headers, data]) => ({ + data: data, + previousRange: headers["prev-range"], + nextRange: headers["next-range"], + })), + TE.chainW((data) => + TE.fromEither( + E.mapLeft(formatValidationErrors)(GETByRangeRawResponse.decode(data)) + ) + ), + TE.map((rawResponse) => ({ + headers: pipe( + rawResponse.data.results, + A.map((result) => result.resource) + ), + previousRange: rawResponse.previousRange, + nextRange: rawResponse.nextRange, + })) + ); type GETByRangeRawResponse = t.TypeOf; -const GETByRangeRawResponse - = t.type({ data : t.type({ results : t.array(t.type({ links : t.type({ contract:t.string, transactions:t.string}) - , resource: WithdrawalHeader}))}) - , previousRange : optionFromNullable(WithdrawalsRange) - , nextRange :optionFromNullable(WithdrawalsRange) - }); +const GETByRangeRawResponse = t.type({ + data: t.type({ + results: t.array( + t.type({ + links: t.type({ contract: t.string, transactions: t.string }), + resource: WithdrawalHeader, + }) + ), + }), + previousRange: optionFromNullable(WithdrawalsRange), + nextRange: optionFromNullable(WithdrawalsRange), +}); export type GETByRangeResponse = t.TypeOf; -export const GETByRangeResponse - = t.type({ headers : t.array(WithdrawalHeader) - , previousRange : optionFromNullable(WithdrawalsRange) - , nextRange :optionFromNullable(WithdrawalsRange) - }); - +export const GETByRangeResponse = t.type({ + headers: t.array(WithdrawalHeader), + previousRange: optionFromNullable(WithdrawalsRange), + nextRange: optionFromNullable(WithdrawalsRange), +}); -export type POST = ( payoutIds: PayoutId[] - , addressesAndCollaterals: AddressesAndCollaterals) => TE.TaskEither +export type POST = ( + payoutIds: PayoutId[], + addressesAndCollaterals: AddressesAndCollaterals +) => TE.TaskEither; export type WithdrawalTextEnvelope = t.TypeOf; -export const WithdrawalTextEnvelope = t.type({ withdrawalId: WithdrawalId, tx : TextEnvelope}) +export const WithdrawalTextEnvelope = t.type({ + withdrawalId: WithdrawalId, + tx: TextEnvelope, +}); export type PostResponse = t.TypeOf; export const PostResponse = t.type({ - links : t.type({}), - resource: WithdrawalTextEnvelope - }); - -export const postViaAxios:(axiosInstance: AxiosInstance) => POST - = (axiosInstance) => (payoutIds, addressesAndCollaterals) => - pipe( HTTP.Post (axiosInstance) - ( '/withdrawals' - , {payouts : payoutIds} - , { headers: { - 'Accept': 'application/vendor.iog.marlowe-runtime.withdraw-tx-json', - 'Content-Type':'application/json', - 'X-Change-Address': unAddressBech32(addressesAndCollaterals.changeAddress), - 'X-Address' : pipe(addressesAndCollaterals.usedAddresses , A.fromOption, A.flatten, A.map (unAddressBech32) , (a) => a.join(',')), - 'X-Collateral-UTxO': pipe(addressesAndCollaterals.collateralUTxOs, A.fromOption, A.flatten, A.map (unTxOutRef) , (a) => a.join(','))}}) - , TE.chainW((data) => TE.fromEither(E.mapLeft(formatValidationErrors)(PostResponse.decode(data)))) - , TE.map((payload) => payload.resource)) - - - - - + links: t.type({}), + resource: WithdrawalTextEnvelope, +}); + +export const postViaAxios: (axiosInstance: AxiosInstance) => POST = + (axiosInstance) => (payoutIds, addressesAndCollaterals) => + pipe( + HTTP.Post(axiosInstance)( + "/withdrawals", + { payouts: payoutIds }, + { + headers: { + Accept: "application/vendor.iog.marlowe-runtime.withdraw-tx-json", + "Content-Type": "application/json", + "X-Change-Address": unAddressBech32( + addressesAndCollaterals.changeAddress + ), + "X-Address": pipe( + addressesAndCollaterals.usedAddresses, + A.fromOption, + A.flatten, + A.map(unAddressBech32), + (a) => a.join(",") + ), + "X-Collateral-UTxO": pipe( + addressesAndCollaterals.collateralUTxOs, + A.fromOption, + A.flatten, + A.map(unTxOutRef), + (a) => a.join(",") + ), + }, + } + ), + TE.chainW((data) => + TE.fromEither( + E.mapLeft(formatValidationErrors)(PostResponse.decode(data)) + ) + ), + TE.map((payload) => payload.resource) + ); diff --git a/packages/runtime/client/rest/src/withdrawal/endpoints/singleton.ts b/packages/runtime/client/rest/src/withdrawal/endpoints/singleton.ts index 1df4a607..cc3b1959 100644 --- a/packages/runtime/client/rest/src/withdrawal/endpoints/singleton.ts +++ b/packages/runtime/client/rest/src/withdrawal/endpoints/singleton.ts @@ -1,44 +1,61 @@ - /* eslint-disable sort-keys-fix/sort-keys-fix */ /* eslint-disable no-use-before-define */ -import { AxiosInstance } from 'axios'; -import * as E from 'fp-ts/lib/Either.js' -import * as TE from 'fp-ts/lib/TaskEither.js' -import { pipe } from 'fp-ts/lib/function.js'; -import * as HTTP from '@marlowe.io/adapter/http'; - -import {formatValidationErrors} from 'jsonbigint-io-ts-reporters' - -import { WithdrawalDetails } from '../details.js'; -import { DecodingError } from '@marlowe.io/adapter/codec'; -import { HexTransactionWitnessSet, WithdrawalId, transactionWitnessSetTextEnvelope, unWithdrawalId } from '@marlowe.io/runtime-core'; - - -export type GET = ( withdrawalId: WithdrawalId) => TE.TaskEither - -export const getViaAxios:(axiosInstance: AxiosInstance) => GET - = (axiosInstance) => (withdrawalId) => - pipe(HTTP.Get(axiosInstance) - ( endpointURI(withdrawalId) - , { headers: { Accept: 'application/json','Content-Type':'application/json'}}) - , TE.chainW((data) => TE.fromEither(E.mapLeft(formatValidationErrors)(WithdrawalDetails.decode(data))))) - -export type PUT = ( withdrawalId: WithdrawalId - , hexTransactionWitnessSet: HexTransactionWitnessSet) - => TE.TaskEither - -export const putViaAxios:(axiosInstance: AxiosInstance) => PUT - = (axiosInstance) => (withdrawalId, hexTransactionWitnessSet) => - pipe(HTTP.Put(axiosInstance) - ( endpointURI(withdrawalId) - , transactionWitnessSetTextEnvelope(hexTransactionWitnessSet) - , { headers: { Accept: 'application/json', 'Content-Type':'application/json'}}) - ) - - - -const endpointURI = (withdrawalId: WithdrawalId):string => - (`/withdrawals/${encodeURIComponent(unWithdrawalId(withdrawalId))}`) - - - +import { AxiosInstance } from "axios"; +import * as E from "fp-ts/lib/Either.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import { pipe } from "fp-ts/lib/function.js"; +import * as HTTP from "@marlowe.io/adapter/http"; + +import { formatValidationErrors } from "jsonbigint-io-ts-reporters"; + +import { WithdrawalDetails } from "../details.js"; +import { DecodingError } from "@marlowe.io/adapter/codec"; +import { + HexTransactionWitnessSet, + WithdrawalId, + transactionWitnessSetTextEnvelope, + unWithdrawalId, +} from "@marlowe.io/runtime-core"; + +export type GET = ( + withdrawalId: WithdrawalId +) => TE.TaskEither; + +export const getViaAxios: (axiosInstance: AxiosInstance) => GET = + (axiosInstance) => (withdrawalId) => + pipe( + HTTP.Get(axiosInstance)(endpointURI(withdrawalId), { + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + }), + TE.chainW((data) => + TE.fromEither( + E.mapLeft(formatValidationErrors)(WithdrawalDetails.decode(data)) + ) + ) + ); + +export type PUT = ( + withdrawalId: WithdrawalId, + hexTransactionWitnessSet: HexTransactionWitnessSet +) => TE.TaskEither; + +export const putViaAxios: (axiosInstance: AxiosInstance) => PUT = + (axiosInstance) => (withdrawalId, hexTransactionWitnessSet) => + pipe( + HTTP.Put(axiosInstance)( + endpointURI(withdrawalId), + transactionWitnessSetTextEnvelope(hexTransactionWitnessSet), + { + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + } + ) + ); + +const endpointURI = (withdrawalId: WithdrawalId): string => + `/withdrawals/${encodeURIComponent(unWithdrawalId(withdrawalId))}`; diff --git a/packages/runtime/client/rest/src/withdrawal/header.ts b/packages/runtime/client/rest/src/withdrawal/header.ts index 88eb89b8..cc099995 100644 --- a/packages/runtime/client/rest/src/withdrawal/header.ts +++ b/packages/runtime/client/rest/src/withdrawal/header.ts @@ -1,16 +1,12 @@ - import * as t from "io-ts/lib/index.js"; - import { TxStatus } from "../contract/transaction/status.js"; import { optionFromNullable } from "io-ts-types/lib/optionFromNullable.js"; import { BlockHeader, WithdrawalId } from "@marlowe.io/runtime-core"; - -export type WithdrawalHeader = t.TypeOf -export const WithdrawalHeader - = t.type( - { withdrawalId: WithdrawalId - , status: TxStatus - , block: optionFromNullable(BlockHeader) - }) +export type WithdrawalHeader = t.TypeOf; +export const WithdrawalHeader = t.type({ + withdrawalId: WithdrawalId, + status: TxStatus, + block: optionFromNullable(BlockHeader), +}); diff --git a/packages/runtime/client/rest/src/withdrawal/index.ts b/packages/runtime/client/rest/src/withdrawal/index.ts index cdd64738..d025b28f 100644 --- a/packages/runtime/client/rest/src/withdrawal/index.ts +++ b/packages/runtime/client/rest/src/withdrawal/index.ts @@ -1,2 +1,2 @@ -export * from './header.js' -export * from './details.js' \ No newline at end of file +export * from "./header.js"; +export * from "./details.js"; diff --git a/packages/runtime/client/rest/test/context.ts b/packages/runtime/client/rest/test/context.ts index 0b3a12de..4b658a77 100644 --- a/packages/runtime/client/rest/test/context.ts +++ b/packages/runtime/client/rest/test/context.ts @@ -1,7 +1,6 @@ - -export function getMarloweRuntimeUrl () : string { - const { MARLOWE_WEB_SERVER_URL} = process.env; - if (MARLOWE_WEB_SERVER_URL == undefined) throw "environment configurations not available(MARLOWE_WEB_SERVER_URL)" - return MARLOWE_WEB_SERVER_URL as string -}; - +export function getMarloweRuntimeUrl(): string { + const { MARLOWE_WEB_SERVER_URL } = process.env; + if (MARLOWE_WEB_SERVER_URL == undefined) + throw "environment configurations not available(MARLOWE_WEB_SERVER_URL)"; + return MARLOWE_WEB_SERVER_URL as string; +} diff --git a/packages/runtime/client/rest/test/endpoints/contracts.spec.e2e.ts b/packages/runtime/client/rest/test/endpoints/contracts.spec.e2e.ts index 1fdb671b..f0b289c3 100644 --- a/packages/runtime/client/rest/test/endpoints/contracts.spec.e2e.ts +++ b/packages/runtime/client/rest/test/endpoints/contracts.spec.e2e.ts @@ -1,26 +1,33 @@ - -import { pipe } from 'fp-ts/lib/function.js' -import * as TE from 'fp-ts/lib/TaskEither.js'; -import * as O from 'fp-ts/lib/Option.js'; - -import { mkRestClient } from '@marlowe.io/runtime-rest-client/index.js'; - -import { getMarloweRuntimeUrl } from '../context.js'; - -import console from "console" -global.console = console - -describe('contracts endpoints', () => { - - const restClient = mkRestClient(getMarloweRuntimeUrl()) - - it('can navigate throught Initialised Marlowe Contracts pages' + - '(GET: /contracts/)', async () => { - await - pipe(restClient.contracts.getHeadersByRange(O.none)([]) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined() }, - (a) => { console.log("result",a.headers.length)}))() - }) -}) - +import { pipe } from "fp-ts/lib/function.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as O from "fp-ts/lib/Option.js"; + +import { mkRestClient } from "@marlowe.io/runtime-rest-client/index.js"; + +import { getMarloweRuntimeUrl } from "../context.js"; + +import console from "console"; +global.console = console; + +describe("contracts endpoints", () => { + const restClient = mkRestClient(getMarloweRuntimeUrl()); + + it( + "can navigate throught Initialised Marlowe Contracts pages" + + "(GET: /contracts/)", + async () => { + await pipe( + restClient.contracts.getHeadersByRange(O.none)([]), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + (a) => { + console.log("result", a.headers.length); + } + ) + )(); + } + ); +}); diff --git a/packages/runtime/client/rest/test/endpoints/payouts.spec.e2e.ts b/packages/runtime/client/rest/test/endpoints/payouts.spec.e2e.ts index 4e9a4a44..01e4364a 100644 --- a/packages/runtime/client/rest/test/endpoints/payouts.spec.e2e.ts +++ b/packages/runtime/client/rest/test/endpoints/payouts.spec.e2e.ts @@ -1,80 +1,144 @@ +import { pipe } from "fp-ts/lib/function.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as O from "fp-ts/lib/Option.js"; -import { pipe } from 'fp-ts/lib/function.js' -import * as TE from 'fp-ts/lib/TaskEither.js'; -import * as O from 'fp-ts/lib/Option.js'; +import { mkRestClient } from "@marlowe.io/runtime-rest-client/index.js"; -import { mkRestClient } from '@marlowe.io/runtime-rest-client/index.js'; +import { getMarloweRuntimeUrl } from "../context.js"; -import { getMarloweRuntimeUrl } from '../context.js'; +import console from "console"; +global.console = console; -import console from "console" -global.console = console +describe("payouts endpoints", () => { + const restClient = mkRestClient(getMarloweRuntimeUrl()); -describe('payouts endpoints', () => { - - const restClient = mkRestClient(getMarloweRuntimeUrl()) - - it('can navigate throught payout headers' + - '(GET: /payouts)', async () => { - await - pipe( - restClient.payouts.getHeadersByRange(O.none)([])([])(O.none) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined() }, - (a) => { console.log("#payout headers read :",a.headers.length)}))() - }), - it('can navigate throught payout headers filtering by available payouts' + - '(GET: /payouts)', async () => { - await - pipe( - restClient.payouts.getHeadersByRange(O.none)([])([])(O.some("available")) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined() }, - (a) => { console.log("#payout headers read :",a.headers.length)}))() - }), - it('can navigate throught payout headers filtering by withdrawn payouts' + - '(GET: /payouts)', async () => { - await - pipe( - restClient.payouts.getHeadersByRange(O.none)([])([])(O.some("withdrawn")) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined() }, - (a) => { console.log("#payout headers read :",a.headers.length) - expect(a.headers.map(header => header.status)).toContain("withdrawn") - expect(a.headers.map(header => header.status)).not.toContain("available") - }))() + it("can navigate throught payout headers" + "(GET: /payouts)", async () => { + await pipe( + restClient.payouts.getHeadersByRange(O.none)([])([])(O.none), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + (a) => { + console.log("#payout headers read :", a.headers.length); + } + ) + )(); }), - it('can navigate throught payout headers filtering by contractId ' + - '(GET: /payouts)', async () => { - await - pipe( - restClient.payouts.getHeadersByRange(O.none)([])([])(O.none) - , TE.map ((result) => result.headers.map (header => header.contractId)) - , TE.chain ((contracIds) => restClient.payouts.getHeadersByRange(O.none)(contracIds)([])(O.none)) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined() }, - (a) => { console.log("#payout headers read :",a.headers.length)}))() - }), - it('can navigate throught payout headers filtering by role tokens ' + - '(GET: /payouts)', async () => { - await - pipe( - restClient.payouts.getHeadersByRange(O.none)([])([])(O.none) - , TE.map ((result) => result.headers.map (header => header.role)) - , TE.chain ((roles) => restClient.payouts.getHeadersByRange(O.none)([])(roles)(O.none)) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined() }, - (a) => { console.log("#payout headers read :",a.headers.length)}))() - }), - it('can navigate throught payout details' + - '(GET: /payouts/{payoutId})', async () => { - await - pipe - ( restClient.payouts.getHeadersByRange(O.none)([])([])(O.none) - , TE.chain ((result) => TE.sequenceArray(result.headers.map(header => restClient.payouts.get(header.payoutId)))) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined() }, - (a) => { console.log("#payout details read",a.length)}))() - }, 100_000) -}) - + it( + "can navigate throught payout headers filtering by available payouts" + + "(GET: /payouts)", + async () => { + await pipe( + restClient.payouts.getHeadersByRange(O.none)([])([])( + O.some("available") + ), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + (a) => { + console.log("#payout headers read :", a.headers.length); + } + ) + )(); + } + ), + it( + "can navigate throught payout headers filtering by withdrawn payouts" + + "(GET: /payouts)", + async () => { + await pipe( + restClient.payouts.getHeadersByRange(O.none)([])([])( + O.some("withdrawn") + ), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + (a) => { + console.log("#payout headers read :", a.headers.length); + expect(a.headers.map((header) => header.status)).toContain( + "withdrawn" + ); + expect(a.headers.map((header) => header.status)).not.toContain( + "available" + ); + } + ) + )(); + } + ), + it( + "can navigate throught payout headers filtering by contractId " + + "(GET: /payouts)", + async () => { + await pipe( + restClient.payouts.getHeadersByRange(O.none)([])([])(O.none), + TE.map((result) => result.headers.map((header) => header.contractId)), + TE.chain((contracIds) => + restClient.payouts.getHeadersByRange(O.none)(contracIds)([])(O.none) + ), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + (a) => { + console.log("#payout headers read :", a.headers.length); + } + ) + )(); + } + ), + it( + "can navigate throught payout headers filtering by role tokens " + + "(GET: /payouts)", + async () => { + await pipe( + restClient.payouts.getHeadersByRange(O.none)([])([])(O.none), + TE.map((result) => result.headers.map((header) => header.role)), + TE.chain((roles) => + restClient.payouts.getHeadersByRange(O.none)([])(roles)(O.none) + ), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + (a) => { + console.log("#payout headers read :", a.headers.length); + } + ) + )(); + } + ), + it( + "can navigate throught payout details" + "(GET: /payouts/{payoutId})", + async () => { + await pipe( + restClient.payouts.getHeadersByRange(O.none)([])([])(O.none), + TE.chain((result) => + TE.sequenceArray( + result.headers.map((header) => + restClient.payouts.get(header.payoutId) + ) + ) + ), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + (a) => { + console.log("#payout details read", a.length); + } + ) + )(); + }, + 100_000 + ); +}); diff --git a/packages/runtime/client/rest/test/endpoints/transactions.spec.e2e.ts b/packages/runtime/client/rest/test/endpoints/transactions.spec.e2e.ts index 6cca26c8..a111f6a1 100644 --- a/packages/runtime/client/rest/test/endpoints/transactions.spec.e2e.ts +++ b/packages/runtime/client/rest/test/endpoints/transactions.spec.e2e.ts @@ -1,21 +1,17 @@ - - - -import { mkRestClient } from "@marlowe.io/runtime-rest-client/index.js" -import console from "console" -import { getMarloweRuntimeUrl } from "../context.js" - -global.console = console - -describe.skip('ransactions endpoints', () => { - const restClient = mkRestClient(getMarloweRuntimeUrl()) - - it('can navigate throught transaction headers' + - '(GET: /contracts/{contractd}/transactions)', async () => { - // TODO - }) - -}) - - - +import { mkRestClient } from "@marlowe.io/runtime-rest-client/index.js"; +import console from "console"; +import { getMarloweRuntimeUrl } from "../context.js"; + +global.console = console; + +describe.skip("ransactions endpoints", () => { + const restClient = mkRestClient(getMarloweRuntimeUrl()); + + it( + "can navigate throught transaction headers" + + "(GET: /contracts/{contractd}/transactions)", + async () => { + // TODO + } + ); +}); diff --git a/packages/runtime/client/rest/test/endpoints/withdrawals.spec.e2e.ts b/packages/runtime/client/rest/test/endpoints/withdrawals.spec.e2e.ts index 93ca9ec2..6754fadc 100644 --- a/packages/runtime/client/rest/test/endpoints/withdrawals.spec.e2e.ts +++ b/packages/runtime/client/rest/test/endpoints/withdrawals.spec.e2e.ts @@ -1,14 +1,12 @@ +import console from "console"; +global.console = console; -import console from "console" - -global.console = console - -describe.skip('withdrawals endpoints ', () => { - - it('can navigate throught withdrawals headers' + - '(GET: /withdrawals)', async () => { - // TODO - }) +describe.skip("withdrawals endpoints ", () => { + it( + "can navigate throught withdrawals headers" + "(GET: /withdrawals)", + async () => { + // TODO + } + ); }); - diff --git a/packages/runtime/core/Readme.md b/packages/runtime/core/Readme.md index ced8eda3..a8d58a95 100644 --- a/packages/runtime/core/Readme.md +++ b/packages/runtime/core/Readme.md @@ -1,2 +1,3 @@ # @marlowe.io/runtime-core -A Set of core functionalities that supports @marlowe.io libraries \ No newline at end of file + +A Set of core functionalities that supports @marlowe.io libraries diff --git a/packages/runtime/core/package.json b/packages/runtime/core/package.json index 1008c1b8..bd6cbbba 100644 --- a/packages/runtime/core/package.json +++ b/packages/runtime/core/package.json @@ -35,4 +35,4 @@ "io-ts": "2.2.20", "newtype-ts": "0.3.5" } -} \ No newline at end of file +} diff --git a/packages/runtime/core/src/address.ts b/packages/runtime/core/src/address.ts index 789c01ff..a9ed3e97 100644 --- a/packages/runtime/core/src/address.ts +++ b/packages/runtime/core/src/address.ts @@ -1,17 +1,20 @@ import * as t from "io-ts/lib/index.js"; import { iso, Newtype } from "newtype-ts"; import { fromNewtype } from "io-ts-types"; -import { optionFromNullable } from "io-ts-types" +import { optionFromNullable } from "io-ts-types"; import { TxOutRef } from "./tx/outRef.js"; -export type AddressBech32 = Newtype<{ readonly AddressBech32: unique symbol }, string> -export const AddressBech32 = fromNewtype(t.string) -export const unAddressBech32 = iso().unwrap -export const addressBech32 = iso().wrap +export type AddressBech32 = Newtype< + { readonly AddressBech32: unique symbol }, + string +>; +export const AddressBech32 = fromNewtype(t.string); +export const unAddressBech32 = iso().unwrap; +export const addressBech32 = iso().wrap; -export type AddressesAndCollaterals = t.TypeOf -export const AddressesAndCollaterals = t.type( - { changeAddress: AddressBech32 - , usedAddresses: optionFromNullable(t.array(AddressBech32)) - , collateralUTxOs: optionFromNullable(t.array(TxOutRef)) - }) \ No newline at end of file +export type AddressesAndCollaterals = t.TypeOf; +export const AddressesAndCollaterals = t.type({ + changeAddress: AddressBech32, + usedAddresses: optionFromNullable(t.array(AddressBech32)), + collateralUTxOs: optionFromNullable(t.array(TxOutRef)), +}); diff --git a/packages/runtime/core/src/asset/index.ts b/packages/runtime/core/src/asset/index.ts index 158cec99..ec9f238a 100644 --- a/packages/runtime/core/src/asset/index.ts +++ b/packages/runtime/core/src/asset/index.ts @@ -1,49 +1,47 @@ import * as t from "io-ts/lib/index.js"; import { PolicyId, mkPolicyId, unPolicyId } from "../policyId.js"; -import * as Marlowe from '@marlowe.io/language-core-v1/tokenValue' - - -export type AssetName = t.TypeOf -export const AssetName = t.string - -export type AssetQuantity = t.TypeOf -export const AssetQuantity = t.bigint - -export type AssetId = t.TypeOf -export const AssetId - = t.type( - { policyId: PolicyId - , assetName: AssetName }) - -export const assetId : (policyId : PolicyId) => (assetName : AssetName) => AssetId - = (policyId) => (assetName) => ({ policyId: policyId, assetName: assetName}) - -export type Token = t.TypeOf -export const Token - = t.type( - { quantity: AssetQuantity - , assetId: AssetId - }) - -export const token : (quantity : AssetQuantity) => (assetId : AssetId)=> Token = (quantity) => (assetId) => ({quantity: quantity, assetId : assetId}) -export const lovelaces : (quantity : AssetQuantity) => Token = (quantity) => token(quantity)(assetId(mkPolicyId(''))('')) - -export type Tokens = t.TypeOf -export const Tokens = t.array(Token) - -export type Assets = t.TypeOf -export const Assets - = t.type( - { lovelaces: AssetQuantity - , tokens: Tokens - }) - -export const assetIdToString : (assetId : AssetId) => string = (assetId) => `${unPolicyId(assetId.policyId)}|${assetId.assetName}` - -export const runtimeTokenToMarloweTokenValue : (runtimeToken: Token) => Marlowe.TokenValue - = (runtimeToken) => - ({ amount :runtimeToken.quantity - , token: - { currency_symbol:unPolicyId(runtimeToken.assetId.policyId) - , token_name:runtimeToken.assetId.assetName} }) \ No newline at end of file +import * as Marlowe from "@marlowe.io/language-core-v1/tokenValue"; + +export type AssetName = t.TypeOf; +export const AssetName = t.string; + +export type AssetQuantity = t.TypeOf; +export const AssetQuantity = t.bigint; + +export type AssetId = t.TypeOf; +export const AssetId = t.type({ policyId: PolicyId, assetName: AssetName }); + +export const assetId: ( + policyId: PolicyId +) => (assetName: AssetName) => AssetId = (policyId) => (assetName) => ({ + policyId: policyId, + assetName: assetName, +}); + +export type Token = t.TypeOf; +export const Token = t.type({ quantity: AssetQuantity, assetId: AssetId }); + +export const token: (quantity: AssetQuantity) => (assetId: AssetId) => Token = + (quantity) => (assetId) => ({ quantity: quantity, assetId: assetId }); +export const lovelaces: (quantity: AssetQuantity) => Token = (quantity) => + token(quantity)(assetId(mkPolicyId(""))("")); + +export type Tokens = t.TypeOf; +export const Tokens = t.array(Token); + +export type Assets = t.TypeOf; +export const Assets = t.type({ lovelaces: AssetQuantity, tokens: Tokens }); + +export const assetIdToString: (assetId: AssetId) => string = (assetId) => + `${unPolicyId(assetId.policyId)}|${assetId.assetName}`; + +export const runtimeTokenToMarloweTokenValue: ( + runtimeToken: Token +) => Marlowe.TokenValue = (runtimeToken) => ({ + amount: runtimeToken.quantity, + token: { + currency_symbol: unPolicyId(runtimeToken.assetId.policyId), + token_name: runtimeToken.assetId.assetName, + }, +}); diff --git a/packages/runtime/core/src/block.ts b/packages/runtime/core/src/block.ts index 18c5fa9f..2904962a 100644 --- a/packages/runtime/core/src/block.ts +++ b/packages/runtime/core/src/block.ts @@ -1,22 +1,20 @@ - - import * as t from "io-ts/lib/index.js"; -import { failure, success, Type } from 'io-ts/lib/index.js' +import { failure, success, Type } from "io-ts/lib/index.js"; - -export function isBigIntOrNumber(u: unknown): u is (bigint | number) { - return typeof u === 'bigint' || typeof u === 'number' +export function isBigIntOrNumber(u: unknown): u is bigint | number { + return typeof u === "bigint" || typeof u === "number"; } export const bigint = new Type( - 'bigint', - isBigIntOrNumber, - (i, c) => (isBigIntOrNumber(i) ? success(i) : failure(i, c)), - ((number) => BigInt(number)) - ) - -export type BlockHeader = t.TypeOf -export const BlockHeader = t.type({ slotNo:bigint - , blockNo:bigint - , blockHeaderHash:t.string}) + "bigint", + isBigIntOrNumber, + (i, c) => (isBigIntOrNumber(i) ? success(i) : failure(i, c)), + (number) => BigInt(number) +); +export type BlockHeader = t.TypeOf; +export const BlockHeader = t.type({ + slotNo: bigint, + blockNo: bigint, + blockHeaderHash: t.string, +}); diff --git a/packages/runtime/core/src/contract/id.ts b/packages/runtime/core/src/contract/id.ts index d3d418a0..24782b32 100644 --- a/packages/runtime/core/src/contract/id.ts +++ b/packages/runtime/core/src/contract/id.ts @@ -6,16 +6,14 @@ import { pipe } from "fp-ts/lib/function.js"; import { head } from "fp-ts/lib/ReadonlyNonEmptyArray.js"; import { TxId } from "../tx/id.js"; +export type ContractId = Newtype< + { readonly ContractId: unique symbol }, + string +>; +export const ContractId = fromNewtype(t.string); +export const unContractId = iso().unwrap; +export const contractId = iso().wrap; -export type ContractId = Newtype<{ readonly ContractId: unique symbol }, string> -export const ContractId = fromNewtype(t.string) -export const unContractId = iso().unwrap -export const contractId = iso().wrap - - -export const contractIdToTxId : (contractId : ContractId) => TxId - = (contractId) => - pipe( contractId - , unContractId - , split('#') - , head) \ No newline at end of file +export const contractIdToTxId: (contractId: ContractId) => TxId = ( + contractId +) => pipe(contractId, unContractId, split("#"), head); diff --git a/packages/runtime/core/src/index.ts b/packages/runtime/core/src/index.ts index 124b2506..5f3fa11a 100644 --- a/packages/runtime/core/src/index.ts +++ b/packages/runtime/core/src/index.ts @@ -1,10 +1,10 @@ -export * from './address.js' -export * from './block.js' -export * from './policyId.js' -export * from './textEnvelope.js' -export * from './tx/index.js' -export * from './metadata.js' -export * from './tag.js' -export * from './contract/id.js' -export * from './asset/index.js' -export * from './payout/index.js' \ No newline at end of file +export * from "./address.js"; +export * from "./block.js"; +export * from "./policyId.js"; +export * from "./textEnvelope.js"; +export * from "./tx/index.js"; +export * from "./metadata.js"; +export * from "./tag.js"; +export * from "./contract/id.js"; +export * from "./asset/index.js"; +export * from "./payout/index.js"; diff --git a/packages/runtime/core/src/metadata.ts b/packages/runtime/core/src/metadata.ts index 5d2c5f40..63841453 100644 --- a/packages/runtime/core/src/metadata.ts +++ b/packages/runtime/core/src/metadata.ts @@ -1,11 +1,10 @@ import * as t from "io-ts/lib/index.js"; -export type MetadatumLabel = t.TypeOf -export const MetadatumLabel = t.union([t.bigint,t.string]) +export type MetadatumLabel = t.TypeOf; +export const MetadatumLabel = t.union([t.bigint, t.string]); -export type Metadatum = t.TypeOf -export const Metadatum = t.any - -export type Metadata = t.TypeOf -export const Metadata = t.record(MetadatumLabel, Metadatum) +export type Metadatum = t.TypeOf; +export const Metadatum = t.any; +export type Metadata = t.TypeOf; +export const Metadata = t.record(MetadatumLabel, Metadatum); diff --git a/packages/runtime/core/src/payout/index.ts b/packages/runtime/core/src/payout/index.ts index 69a5e6b9..b4b7f685 100644 --- a/packages/runtime/core/src/payout/index.ts +++ b/packages/runtime/core/src/payout/index.ts @@ -8,46 +8,39 @@ import { TxId } from "../tx/id.js"; import { ContractId } from "../contract/id.js"; import { AssetId, Assets } from "../asset/index.js"; - -export type PayoutId = Newtype<{ readonly ContractId: unique symbol }, string> -export const PayoutId = fromNewtype(t.string) -export const unPayoutId = iso().unwrap -export const payoutId = iso().wrap - -export const payoutIdToTxId : (payoutId : PayoutId) => TxId - = (payoutId) => - pipe( payoutId - , unPayoutId - , split('#') - , head) - -export type WithdrawalId = Newtype<{ readonly WithdrawalId: unique symbol }, string> -export const WithdrawalId = fromNewtype(t.string) -export const unWithdrawalId = iso().unwrap -export const withdrawalId= iso().wrap - -export const withdrawalIdToTxId : (withdrawalId : WithdrawalId) => TxId - = (withdrawalId) => - pipe( withdrawalId - , unWithdrawalId) - - -export type PayoutAvailable = t.TypeOf -export const PayoutAvailable - = t.type( - { payoutId: PayoutId - , contractId: ContractId - , role: AssetId - , assets : Assets - }) - -export type PayoutWithdrawn = t.TypeOf -export const PayoutWithdrawn - = t.type( - { withdrawalId : WithdrawalId - , payoutId: PayoutId - , contractId: ContractId - , role: AssetId - , assets : Assets - }) - \ No newline at end of file +export type PayoutId = Newtype<{ readonly ContractId: unique symbol }, string>; +export const PayoutId = fromNewtype(t.string); +export const unPayoutId = iso().unwrap; +export const payoutId = iso().wrap; + +export const payoutIdToTxId: (payoutId: PayoutId) => TxId = (payoutId) => + pipe(payoutId, unPayoutId, split("#"), head); + +export type WithdrawalId = Newtype< + { readonly WithdrawalId: unique symbol }, + string +>; +export const WithdrawalId = fromNewtype(t.string); +export const unWithdrawalId = iso().unwrap; +export const withdrawalId = iso().wrap; + +export const withdrawalIdToTxId: (withdrawalId: WithdrawalId) => TxId = ( + withdrawalId +) => pipe(withdrawalId, unWithdrawalId); + +export type PayoutAvailable = t.TypeOf; +export const PayoutAvailable = t.type({ + payoutId: PayoutId, + contractId: ContractId, + role: AssetId, + assets: Assets, +}); + +export type PayoutWithdrawn = t.TypeOf; +export const PayoutWithdrawn = t.type({ + withdrawalId: WithdrawalId, + payoutId: PayoutId, + contractId: ContractId, + role: AssetId, + assets: Assets, +}); diff --git a/packages/runtime/core/src/policyId.ts b/packages/runtime/core/src/policyId.ts index 0104a6d9..2dd8f341 100644 --- a/packages/runtime/core/src/policyId.ts +++ b/packages/runtime/core/src/policyId.ts @@ -2,7 +2,7 @@ import * as t from "io-ts/lib/index.js"; import { iso, Newtype } from "newtype-ts"; import { fromNewtype } from "io-ts-types"; -export type PolicyId = Newtype<{ readonly PolicyId: unique symbol }, string> -export const PolicyId = fromNewtype(t.string) -export const unPolicyId = iso().unwrap -export const mkPolicyId = iso().wrap +export type PolicyId = Newtype<{ readonly PolicyId: unique symbol }, string>; +export const PolicyId = fromNewtype(t.string); +export const unPolicyId = iso().unwrap; +export const mkPolicyId = iso().wrap; diff --git a/packages/runtime/core/src/tag.ts b/packages/runtime/core/src/tag.ts index 02cd0c40..30218d7f 100644 --- a/packages/runtime/core/src/tag.ts +++ b/packages/runtime/core/src/tag.ts @@ -1,12 +1,12 @@ import * as t from "io-ts/lib/index.js"; -export type Tag = t.TypeOf -export const Tag = t.string +export type Tag = t.TypeOf; +export const Tag = t.string; -export type TagContent = t.TypeOf -export const TagContent = t.any +export type TagContent = t.TypeOf; +export const TagContent = t.any; -export type Tags = t.TypeOf -export const Tags = t.record(Tag, TagContent) +export type Tags = t.TypeOf; +export const Tags = t.record(Tag, TagContent); -export const noTags : Tag[]= [] \ No newline at end of file +export const noTags: Tag[] = []; diff --git a/packages/runtime/core/src/textEnvelope.ts b/packages/runtime/core/src/textEnvelope.ts index 9cf0852c..f6f1d907 100644 --- a/packages/runtime/core/src/textEnvelope.ts +++ b/packages/runtime/core/src/textEnvelope.ts @@ -1,15 +1,24 @@ -import reporter from 'jsonbigint-io-ts-reporters' +import reporter from "jsonbigint-io-ts-reporters"; import { Newtype } from "newtype-ts"; -import { fromNewtype,option, optionFromNullable } from "io-ts-types"; +import { fromNewtype, option, optionFromNullable } from "io-ts-types"; import * as t from "io-ts/lib/index.js"; // see : https://input-output-hk.github.io/cardano-node/cardano-api/lib/Cardano-Api-SerialiseTextEnvelope.html -export type TextEnvelope = t.TypeOf -export const TextEnvelope = t.type({ type:t.string, description:t.string, cborHex:t.string}) +export type TextEnvelope = t.TypeOf; +export const TextEnvelope = t.type({ + type: t.string, + description: t.string, + cborHex: t.string, +}); export type MarloweTxCBORHex = string; -export type HexTransactionWitnessSet = string +export type HexTransactionWitnessSet = string; -export const transactionWitnessSetTextEnvelope : (hexTransactionWitnessSet: HexTransactionWitnessSet) => TextEnvelope - = (hexTransactionWitnessSet) => ({type:"ShelleyTxWitness BabbageEra", description:"",cborHex:hexTransactionWitnessSet}) \ No newline at end of file +export const transactionWitnessSetTextEnvelope: ( + hexTransactionWitnessSet: HexTransactionWitnessSet +) => TextEnvelope = (hexTransactionWitnessSet) => ({ + type: "ShelleyTxWitness BabbageEra", + description: "", + cborHex: hexTransactionWitnessSet, +}); diff --git a/packages/runtime/core/src/tsconfig.json b/packages/runtime/core/src/tsconfig.json index 081dfe82..ebee21bf 100644 --- a/packages/runtime/core/src/tsconfig.json +++ b/packages/runtime/core/src/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "../../../../tsconfig-base.json", "compilerOptions": { - "outDir": "../dist", + "outDir": "../dist" } } diff --git a/packages/runtime/core/src/tx/id.ts b/packages/runtime/core/src/tx/id.ts index 6aa764d8..c7da628b 100644 --- a/packages/runtime/core/src/tx/id.ts +++ b/packages/runtime/core/src/tx/id.ts @@ -1,4 +1,4 @@ import * as t from "io-ts/lib/index.js"; -export type TxId = t.TypeOf -export const TxId = t.string // to refine \ No newline at end of file +export type TxId = t.TypeOf; +export const TxId = t.string; // to refine diff --git a/packages/runtime/core/src/tx/index.ts b/packages/runtime/core/src/tx/index.ts index 1ec81c25..8d1903c5 100644 --- a/packages/runtime/core/src/tx/index.ts +++ b/packages/runtime/core/src/tx/index.ts @@ -1,2 +1,2 @@ -export * from './id.js' -export * from './outRef.js' \ No newline at end of file +export * from "./id.js"; +export * from "./outRef.js"; diff --git a/packages/runtime/core/src/tx/outRef.ts b/packages/runtime/core/src/tx/outRef.ts index e223ecbe..ea71e293 100644 --- a/packages/runtime/core/src/tx/outRef.ts +++ b/packages/runtime/core/src/tx/outRef.ts @@ -2,9 +2,7 @@ import * as t from "io-ts/lib/index.js"; import { iso, Newtype } from "newtype-ts"; import { fromNewtype } from "io-ts-types"; - -export type TxOutRef = Newtype<{ readonly TxOutRef: unique symbol }, string> -export const TxOutRef = fromNewtype(t.string) -export const unTxOutRef = iso().unwrap -export const txOutRef = iso().wrap - +export type TxOutRef = Newtype<{ readonly TxOutRef: unique symbol }, string>; +export const TxOutRef = fromNewtype(t.string); +export const unTxOutRef = iso().unwrap; +export const txOutRef = iso().wrap; diff --git a/packages/runtime/lifecycle/Readme.md b/packages/runtime/lifecycle/Readme.md index 16924e65..aadfa670 100644 --- a/packages/runtime/lifecycle/Readme.md +++ b/packages/runtime/lifecycle/Readme.md @@ -1,2 +1,3 @@ # @marlowe.io/runtime-lifecylce -TODO \ No newline at end of file + +TODO diff --git a/packages/runtime/lifecycle/package.json b/packages/runtime/lifecycle/package.json index b90346dc..d7b0b8e0 100644 --- a/packages/runtime/lifecycle/package.json +++ b/packages/runtime/lifecycle/package.json @@ -59,6 +59,6 @@ "fp-ts": "^2.13.1", "io-ts": "2.2.20", "newtype-ts": "0.3.5", - "monocle-ts":"2.3.13" + "monocle-ts": "2.3.13" } -} \ No newline at end of file +} diff --git a/packages/runtime/lifecycle/src/apis/runtimeLifecycle.ts b/packages/runtime/lifecycle/src/apis/runtimeLifecycle.ts index 28b68e26..e40ae5e5 100644 --- a/packages/runtime/lifecycle/src/apis/runtimeLifecycle.ts +++ b/packages/runtime/lifecycle/src/apis/runtimeLifecycle.ts @@ -1,36 +1,51 @@ +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as F from "fp-ts/lib"; +import { WalletAPI } from "@marlowe.io/wallet/api"; +import * as O from "fp-ts/lib/Option.js"; +import { CreateRequest, ProvideInput, TxAPI } from "./tx.js"; +import { + AssetId, + ContractId, + PayoutAvailable, + PayoutId, + PayoutWithdrawn, +} from "@marlowe.io/runtime-core"; +import { DecodingError } from "@marlowe.io/adapter/codec"; +export type RuntimeLifecycle = { + wallet: WalletAPI; + contracts: { + create: ( + payload: CreateRequest + ) => TE.TaskEither; + applyInputs: ( + contractId: ContractId + ) => ( + provideInput: ProvideInput + ) => TE.TaskEither; + }; + payouts: { + available: ( + filtersOption: O.Option + ) => TE.TaskEither; + withdraw: ( + payoutIds: PayoutId[] + ) => TE.TaskEither; + withdrawn: ( + filtersOption: O.Option + ) => TE.TaskEither; + }; +}; -import * as TE from 'fp-ts/lib/TaskEither.js' -import * as F from 'fp-ts/lib' -import { WalletAPI } from '@marlowe.io/wallet/api'; -import * as O from 'fp-ts/lib/Option.js' -import { CreateRequest, ProvideInput, TxAPI } from './tx.js'; -import { AssetId, ContractId, PayoutAvailable, PayoutId, PayoutWithdrawn } from '@marlowe.io/runtime-core'; -import { DecodingError } from '@marlowe.io/adapter/codec'; - -export type RuntimeLifecycle = - { wallet : WalletAPI - contracts : { - create : (payload: CreateRequest) => TE.TaskEither - applyInputs : (contractId: ContractId) => (provideInput : ProvideInput) => TE.TaskEither - } - payouts : - { available : (filtersOption : O.Option) => TE.TaskEither - , withdraw : (payoutIds : PayoutId[]) => TE.TaskEither - , withdrawn : (filtersOption : O.Option) => TE.TaskEither - } - - } - -export const onlyByContractIds : (contractIds : ContractId[]) => O.Option - = (contractIds) => - O.some ({ - byContractIds : contractIds - , byMyRoleTokens : (myRoles) => myRoles - }) - -export type Filters = ({ - byContractIds : ContractId[] - byMyRoleTokens : (myRolesOnWallet : AssetId[]) => AssetId[] -}) +export const onlyByContractIds: ( + contractIds: ContractId[] +) => O.Option = (contractIds) => + O.some({ + byContractIds: contractIds, + byMyRoleTokens: (myRoles) => myRoles, + }); +export type Filters = { + byContractIds: ContractId[]; + byMyRoleTokens: (myRolesOnWallet: AssetId[]) => AssetId[]; +}; diff --git a/packages/runtime/lifecycle/src/apis/tx.ts b/packages/runtime/lifecycle/src/apis/tx.ts index 156e3e71..78d55df8 100644 --- a/packages/runtime/lifecycle/src/apis/tx.ts +++ b/packages/runtime/lifecycle/src/apis/tx.ts @@ -1,38 +1,43 @@ +import * as TE from "fp-ts/lib/TaskEither.js"; +import { DecodingError } from "@marlowe.io/adapter/codec"; +import { ISO8601 } from "@marlowe.io/adapter/time"; +import { Contract } from "@marlowe.io/language-core-v1/semantics/contract/index.js"; +import { Input } from "@marlowe.io/language-core-v1/semantics/contract/when/input/index.js"; +import { Next } from "@marlowe.io/language-core-v1/semantics/next/index.js"; -import * as TE from 'fp-ts/lib/TaskEither.js' -import { DecodingError } from '@marlowe.io/adapter/codec'; -import { ISO8601 } from '@marlowe.io/adapter/time'; - -import { Contract } from '@marlowe.io/language-core-v1/semantics/contract/index.js'; -import { Input } from '@marlowe.io/language-core-v1/semantics/contract/when/input/index.js'; -import { Next } from '@marlowe.io/language-core-v1/semantics/next/index.js'; - -import { Tags, Metadata,ContractId, PayoutId } from '@marlowe.io/runtime-core'; - -import { RolesConfig } from '@marlowe.io/runtime-rest-client/contract/role.js'; +import { Tags, Metadata, ContractId, PayoutId } from "@marlowe.io/runtime-core"; +import { RolesConfig } from "@marlowe.io/runtime-rest-client/contract/role.js"; export type TxAPI = { - create : (payload: CreateRequest) => TE.TaskEither - applyInputs : (contractId: ContractId) => (provideInput : ProvideInput) => TE.TaskEither - withdraw : (payoutIds : PayoutId[]) => TE.TaskEither - } - -export type ProvideInput = (next:Next) => ApplyInputsRequest - -export type CreateRequest = - ({ contract: Contract - , roles?: RolesConfig - , tags? : Tags - , metadata?: Metadata - , minUTxODeposit?: number}) - - -export type ApplyInputsRequest - = ( { inputs: Input[] - , tags? : Tags - , metadata?: Metadata - , invalidBefore?: ISO8601 - , invalidHereafter?: ISO8601}) - + create: ( + payload: CreateRequest + ) => TE.TaskEither; + applyInputs: ( + contractId: ContractId + ) => ( + provideInput: ProvideInput + ) => TE.TaskEither; + withdraw: ( + payoutIds: PayoutId[] + ) => TE.TaskEither; +}; + +export type ProvideInput = (next: Next) => ApplyInputsRequest; + +export type CreateRequest = { + contract: Contract; + roles?: RolesConfig; + tags?: Tags; + metadata?: Metadata; + minUTxODeposit?: number; +}; + +export type ApplyInputsRequest = { + inputs: Input[]; + tags?: Tags; + metadata?: Metadata; + invalidBefore?: ISO8601; + invalidHereafter?: ISO8601; +}; diff --git a/packages/runtime/lifecycle/src/index.ts b/packages/runtime/lifecycle/src/index.ts index dfecac02..c5051b39 100644 --- a/packages/runtime/lifecycle/src/index.ts +++ b/packages/runtime/lifecycle/src/index.ts @@ -1,4 +1,2 @@ -export * as Browser from './instance/overRestAPI/browser/index.js' -export * as NodeJS from './instance/overRestAPI/browser/index.js' - - +export * as Browser from "./instance/overRestAPI/browser/index.js"; +export * as NodeJS from "./instance/overRestAPI/browser/index.js"; diff --git a/packages/runtime/lifecycle/src/instance/overRestAPI/browser/index.ts b/packages/runtime/lifecycle/src/instance/overRestAPI/browser/index.ts index 64c0677f..c06f114a 100644 --- a/packages/runtime/lifecycle/src/instance/overRestAPI/browser/index.ts +++ b/packages/runtime/lifecycle/src/instance/overRestAPI/browser/index.ts @@ -1,17 +1,17 @@ -import * as T from 'fp-ts/lib/Task.js' -import { pipe } from 'fp-ts/lib/function.js'; +import * as T from "fp-ts/lib/Task.js"; +import { pipe } from "fp-ts/lib/function.js"; -import { getExtensionInstance } from '@marlowe.io/wallet/browser'; -import * as Generic from '../index.js'; -import { RuntimeLifecycle } from '../../../apis/runtimeLifecycle.js'; +import { getExtensionInstance } from "@marlowe.io/wallet/browser"; +import * as Generic from "../index.js"; +import { RuntimeLifecycle } from "../../../apis/runtimeLifecycle.js"; -import { mkRestClient } from '@marlowe.io/runtime-rest-client'; +import { mkRestClient } from "@marlowe.io/runtime-rest-client"; -export const mkRuntimeLifecycle - : (runtimeURL : string) - => (extensionName : string) - => T.Task = +export const mkRuntimeLifecycle: ( + runtimeURL: string +) => (extensionName: string) => T.Task = (runtimeURL) => (extensionName) => - pipe( getExtensionInstance (extensionName) - , T.map (Generic.mkRuntimeLifecycle (mkRestClient(runtimeURL)))) - + pipe( + getExtensionInstance(extensionName), + T.map(Generic.mkRuntimeLifecycle(mkRestClient(runtimeURL))) + ); diff --git a/packages/runtime/lifecycle/src/instance/overRestAPI/index.ts b/packages/runtime/lifecycle/src/instance/overRestAPI/index.ts index f1367ffd..d1699711 100644 --- a/packages/runtime/lifecycle/src/instance/overRestAPI/index.ts +++ b/packages/runtime/lifecycle/src/instance/overRestAPI/index.ts @@ -1,130 +1,205 @@ - - - -import * as Command from './tx.js'; -import * as TE from 'fp-ts/lib/TaskEither.js' -import * as T from 'fp-ts/lib/Task.js' -import { pipe } from 'fp-ts/lib/function.js'; -import * as O from 'fp-ts/lib/Option.js' -import { mkEnvironment } from '@marlowe.io/language-core-v1/environment'; -import { addMinutes, subMinutes } from 'date-fns'; - -import { Party } from '@marlowe.io/language-core-v1/semantics/contract/common/payee/party.js'; -import { Filters, RuntimeLifecycle } from '../../apis/runtimeLifecycle.js'; -import { CreateRequest, ProvideInput } from '../../apis/tx.js'; -import { WalletAPI } from '@marlowe.io/wallet/api'; -import { PolicyId,ContractId, PayoutId, PayoutAvailable, AssetId, PayoutWithdrawn, unPolicyId, Assets, Tokens, assetId, mkPolicyId, token } from '@marlowe.io/runtime-core'; - -import { RestAPI } from '@marlowe.io/runtime-rest-client'; - -import * as Rest from '@marlowe.io/runtime-rest-client'; - -import { DecodingError } from '@marlowe.io/adapter/codec'; -import { stringify } from 'json-bigint'; - -export const mkRuntimeLifecycle - : (restAPI : RestAPI) - => (walletAPI : WalletAPI) - => RuntimeLifecycle - = (restAPI) => (walletAPI) => - ({ wallet : walletAPI - , contracts : - { create : (payload : CreateRequest) => Command.create (restAPI)(walletAPI)(payload) - , applyInputs : (contractId : ContractId) => (provideInput:ProvideInput) => - pipe( restAPI.contracts.contract.get (contractId) - , TE.chain (header => TE.fromTask(getParties(walletAPI)(header.roleTokenMintingPolicyId))) - , TE.chain( parties => - restAPI.contracts.contract.next - (contractId) - (mkEnvironment - (pipe(Date.now(),(date) => subMinutes(date,15))) - (pipe(Date.now(),(date) => addMinutes(date,15)))) - (parties)) - , TE.chain( next => - Command.applyInputs - (restAPI) - (walletAPI) - (contractId) - (provideInput(next))))} - , payouts : - { available : (filtersOption : O.Option) => availablePayouts(restAPI) (walletAPI) (filtersOption) - , withdraw : (payoutIds : PayoutId[]) => Command.withdraw (restAPI) (walletAPI) (payoutIds) - , withdrawn : (filtersOption : O.Option) => withdrawnPayouts(restAPI) (walletAPI) (filtersOption)}}) - - - -const availablePayouts : (restAPI : RestAPI) => (walletApi : WalletAPI) => (filtersOption : O.Option) => TE.TaskEither - = (restAPI) => (walletApi) => (filtersOption) => - pipe(getAssetIds(walletApi) - ,TE.chain ( (walletAssetIds) => - pipe - ( restAPI.payouts.getHeadersByRange - (O.none) - (pipe(filtersOption,O.match(() => [], filters => filters.byContractIds))) - (pipe(filtersOption,O.match(() => walletAssetIds, filters => filters.byMyRoleTokens(walletAssetIds)))) - (O.some("available")) - , TE.map(result => result.headers))) - ,TE.chain(headers => TE.sequenceArray( headers.map (header => restAPI.payouts.get(header.payoutId) ) )) - ,TE.map (payoutsDetails => - payoutsDetails.map(payoutDetails => - ({ payoutId: payoutDetails.payoutId - , contractId: payoutDetails.contractId - , role: payoutDetails.role - , assets : convertAsset(payoutDetails.assets) - })))) - -const withdrawnPayouts : (restAPI : RestAPI) => (walletApi : WalletAPI) => (filtersOption : O.Option) => TE.TaskEither - = (restAPI) => (walletApi) => (filtersOption) => - pipe(getAssetIds(walletApi) - ,TE.chain ( (walletAssetIds) => - pipe(restAPI.payouts.getHeadersByRange - (O.none) - (pipe(filtersOption,O.match(() => [], filters => filters.byContractIds))) - (pipe(filtersOption,O.match(() => walletAssetIds, filters => filters.byMyRoleTokens(walletAssetIds)))) - (O.some("withdrawn")) - , TE.map(result => result.headers))) - ,TE.chain(headers => TE.sequenceArray( headers.map (header => restAPI.payouts.get(header.payoutId)))) - ,TE.map (payoutsDetails => - payoutsDetails.map(payoutDetails => - pipe( payoutDetails.withdrawalId - , O.match - ( () => { throw `Rest API Inconsistencies for Payout API (payout withdrawn without a withdrawalID) : ${stringify(payoutDetails)}`} - , withdrawalId => - ({ withdrawalId : withdrawalId - , payoutId: payoutDetails.payoutId - , contractId: payoutDetails.contractId - , role: payoutDetails.role - , assets : convertAsset(payoutDetails.assets) - }) - ))))) - - -const convertAsset : (assets : Rest.Assets) => Assets = - (restAssets) => - ({lovelaces : restAssets.lovelace - ,tokens : convertTokens(restAssets.tokens) }) - -const convertTokens : (tokens : Rest.Tokens) => Tokens = - (restTokens) => - Object.entries(restTokens).map(([policyId,x]) => - Object.entries(x).map(([assetName,quantity]) => - token - (quantity) - (assetId - (mkPolicyId(policyId)) - (assetName))) ).flat() - - -const getAssetIds - : (walletApi : WalletAPI) - => TE.TaskEither - = (walletAPI) => - pipe (walletAPI.getTokens,TE.map(tokens => tokens.map (token => token.assetId))) - -const getParties - : (walletApi : WalletAPI) - => (roleTokenMintingPolicyId : PolicyId) - => T.Task - = (walletAPI) => (roleMintingPolicyId) => T.of ([]) - - +import * as Command from "./tx.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as T from "fp-ts/lib/Task.js"; +import { pipe } from "fp-ts/lib/function.js"; +import * as O from "fp-ts/lib/Option.js"; +import { mkEnvironment } from "@marlowe.io/language-core-v1/environment"; +import { addMinutes, subMinutes } from "date-fns"; + +import { Party } from "@marlowe.io/language-core-v1/semantics/contract/common/payee/party.js"; +import { Filters, RuntimeLifecycle } from "../../apis/runtimeLifecycle.js"; +import { CreateRequest, ProvideInput } from "../../apis/tx.js"; +import { WalletAPI } from "@marlowe.io/wallet/api"; +import { + PolicyId, + ContractId, + PayoutId, + PayoutAvailable, + AssetId, + PayoutWithdrawn, + unPolicyId, + Assets, + Tokens, + assetId, + mkPolicyId, + token, +} from "@marlowe.io/runtime-core"; + +import { RestAPI } from "@marlowe.io/runtime-rest-client"; + +import * as Rest from "@marlowe.io/runtime-rest-client"; + +import { DecodingError } from "@marlowe.io/adapter/codec"; +import { stringify } from "json-bigint"; + +export const mkRuntimeLifecycle: ( + restAPI: RestAPI +) => (walletAPI: WalletAPI) => RuntimeLifecycle = (restAPI) => (walletAPI) => ({ + wallet: walletAPI, + contracts: { + create: (payload: CreateRequest) => + Command.create(restAPI)(walletAPI)(payload), + applyInputs: (contractId: ContractId) => (provideInput: ProvideInput) => + pipe( + restAPI.contracts.contract.get(contractId), + TE.chain((header) => + TE.fromTask(getParties(walletAPI)(header.roleTokenMintingPolicyId)) + ), + TE.chain((parties) => + restAPI.contracts.contract.next(contractId)( + mkEnvironment(pipe(Date.now(), (date) => subMinutes(date, 15)))( + pipe(Date.now(), (date) => addMinutes(date, 15)) + ) + )(parties) + ), + TE.chain((next) => + Command.applyInputs(restAPI)(walletAPI)(contractId)( + provideInput(next) + ) + ) + ), + }, + payouts: { + available: (filtersOption: O.Option) => + availablePayouts(restAPI)(walletAPI)(filtersOption), + withdraw: (payoutIds: PayoutId[]) => + Command.withdraw(restAPI)(walletAPI)(payoutIds), + withdrawn: (filtersOption: O.Option) => + withdrawnPayouts(restAPI)(walletAPI)(filtersOption), + }, +}); + +const availablePayouts: ( + restAPI: RestAPI +) => ( + walletApi: WalletAPI +) => ( + filtersOption: O.Option +) => TE.TaskEither = + (restAPI) => (walletApi) => (filtersOption) => + pipe( + getAssetIds(walletApi), + TE.chain((walletAssetIds) => + pipe( + restAPI.payouts.getHeadersByRange(O.none)( + pipe( + filtersOption, + O.match( + () => [], + (filters) => filters.byContractIds + ) + ) + )( + pipe( + filtersOption, + O.match( + () => walletAssetIds, + (filters) => filters.byMyRoleTokens(walletAssetIds) + ) + ) + )(O.some("available")), + TE.map((result) => result.headers) + ) + ), + TE.chain((headers) => + TE.sequenceArray( + headers.map((header) => restAPI.payouts.get(header.payoutId)) + ) + ), + TE.map((payoutsDetails) => + payoutsDetails.map((payoutDetails) => ({ + payoutId: payoutDetails.payoutId, + contractId: payoutDetails.contractId, + role: payoutDetails.role, + assets: convertAsset(payoutDetails.assets), + })) + ) + ); + +const withdrawnPayouts: ( + restAPI: RestAPI +) => ( + walletApi: WalletAPI +) => ( + filtersOption: O.Option +) => TE.TaskEither = + (restAPI) => (walletApi) => (filtersOption) => + pipe( + getAssetIds(walletApi), + TE.chain((walletAssetIds) => + pipe( + restAPI.payouts.getHeadersByRange(O.none)( + pipe( + filtersOption, + O.match( + () => [], + (filters) => filters.byContractIds + ) + ) + )( + pipe( + filtersOption, + O.match( + () => walletAssetIds, + (filters) => filters.byMyRoleTokens(walletAssetIds) + ) + ) + )(O.some("withdrawn")), + TE.map((result) => result.headers) + ) + ), + TE.chain((headers) => + TE.sequenceArray( + headers.map((header) => restAPI.payouts.get(header.payoutId)) + ) + ), + TE.map((payoutsDetails) => + payoutsDetails.map((payoutDetails) => + pipe( + payoutDetails.withdrawalId, + O.match( + () => { + throw `Rest API Inconsistencies for Payout API (payout withdrawn without a withdrawalID) : ${stringify( + payoutDetails + )}`; + }, + (withdrawalId) => ({ + withdrawalId: withdrawalId, + payoutId: payoutDetails.payoutId, + contractId: payoutDetails.contractId, + role: payoutDetails.role, + assets: convertAsset(payoutDetails.assets), + }) + ) + ) + ) + ) + ); + +const convertAsset: (assets: Rest.Assets) => Assets = (restAssets) => ({ + lovelaces: restAssets.lovelace, + tokens: convertTokens(restAssets.tokens), +}); + +const convertTokens: (tokens: Rest.Tokens) => Tokens = (restTokens) => + Object.entries(restTokens) + .map(([policyId, x]) => + Object.entries(x).map(([assetName, quantity]) => + token(quantity)(assetId(mkPolicyId(policyId))(assetName)) + ) + ) + .flat(); + +const getAssetIds: (walletApi: WalletAPI) => TE.TaskEither = ( + walletAPI +) => + pipe( + walletAPI.getTokens, + TE.map((tokens) => tokens.map((token) => token.assetId)) + ); + +const getParties: ( + walletApi: WalletAPI +) => (roleTokenMintingPolicyId: PolicyId) => T.Task = + (walletAPI) => (roleMintingPolicyId) => + T.of([]); diff --git a/packages/runtime/lifecycle/src/instance/overRestAPI/nodejs/index.ts b/packages/runtime/lifecycle/src/instance/overRestAPI/nodejs/index.ts index 753def6d..c8b967f8 100644 --- a/packages/runtime/lifecycle/src/instance/overRestAPI/nodejs/index.ts +++ b/packages/runtime/lifecycle/src/instance/overRestAPI/nodejs/index.ts @@ -1,16 +1,18 @@ -import { mkRestClient } from '@marlowe.io/runtime-rest-client/index.js'; -import * as T from 'fp-ts/lib/Task.js'; -import { pipe } from 'fp-ts/lib/function.js'; +import { mkRestClient } from "@marlowe.io/runtime-rest-client/index.js"; +import * as T from "fp-ts/lib/Task.js"; +import { pipe } from "fp-ts/lib/function.js"; -import * as S from '@marlowe.io/wallet/nodejs';; -import * as Generic from '../index.js'; -import { RuntimeLifecycle } from '../../../apis/runtimeLifecycle.js'; +import * as S from "@marlowe.io/wallet/nodejs"; +import * as Generic from "../index.js"; +import { RuntimeLifecycle } from "../../../apis/runtimeLifecycle.js"; -export const mkRuntimeLifecycle - : (runtimeURL : string) - => ( context:S.Context) - => (privateKeyBech32: string) - => T.Task = - (runtimeURL) =>(context) => (privateKeyBech32) => - pipe( S.SingleAddressWallet.Initialise (context,privateKeyBech32) - , T.map (Generic.mkRuntimeLifecycle (mkRestClient(runtimeURL)))) +export const mkRuntimeLifecycle: ( + runtimeURL: string +) => ( + context: S.Context +) => (privateKeyBech32: string) => T.Task = + (runtimeURL) => (context) => (privateKeyBech32) => + pipe( + S.SingleAddressWallet.Initialise(context, privateKeyBech32), + T.map(Generic.mkRuntimeLifecycle(mkRestClient(runtimeURL))) + ); diff --git a/packages/runtime/lifecycle/src/instance/overRestAPI/tx.ts b/packages/runtime/lifecycle/src/instance/overRestAPI/tx.ts index 67375fe7..644b1e8f 100644 --- a/packages/runtime/lifecycle/src/instance/overRestAPI/tx.ts +++ b/packages/runtime/lifecycle/src/instance/overRestAPI/tx.ts @@ -1,79 +1,134 @@ +import * as TE from "fp-ts/lib/TaskEither.js"; -import * as TE from 'fp-ts/lib/TaskEither.js' +import { constVoid, pipe } from "fp-ts/lib/function.js"; +import { RestAPI } from "@marlowe.io/runtime-rest-client/index.js"; +import { WalletAPI, getAddressesAndCollaterals } from "@marlowe.io/wallet/api"; +import { DecodingError } from "@marlowe.io/adapter/codec"; +import { CreateRequest, ApplyInputsRequest } from "../../apis/tx.js"; +import { + ContractId, + PayoutId, + contractIdToTxId, + withdrawalIdToTxId, +} from "@marlowe.io/runtime-core"; -import { constVoid, pipe } from 'fp-ts/lib/function.js' -import { RestAPI } from '@marlowe.io/runtime-rest-client/index.js'; -import { WalletAPI, getAddressesAndCollaterals } from '@marlowe.io/wallet/api'; -import { DecodingError } from '@marlowe.io/adapter/codec'; -import { CreateRequest, ApplyInputsRequest } from '../../apis/tx.js'; -import { ContractId, PayoutId, contractIdToTxId, withdrawalIdToTxId } from "@marlowe.io/runtime-core";; +import * as Tx from "@marlowe.io/runtime-rest-client/transaction"; -import * as Tx from '@marlowe.io/runtime-rest-client/transaction'; +export const create: ( + client: RestAPI +) => ( + wallet: WalletAPI +) => ( + payload: CreateRequest +) => TE.TaskEither = + (client) => (wallet) => (payload) => + pipe( + getAddressesAndCollaterals(wallet), + TE.fromTask, + TE.chain((addressesAndCollaterals) => + client.contracts.post( + { + contract: payload.contract, + version: "v1", + roles: payload.roles, + tags: payload.tags ? payload.tags : {}, + metadata: payload.metadata ? payload.metadata : {}, + minUTxODeposit: payload.minUTxODeposit + ? payload.minUTxODeposit + : 3_000_000, + }, + addressesAndCollaterals + ) + ), + TE.chainW((contractTextEnvelope) => + pipe( + wallet.signTxTheCIP30Way(contractTextEnvelope.tx.cborHex), + TE.chain((hexTransactionWitnessSet) => + client.contracts.contract.put( + contractTextEnvelope.contractId, + hexTransactionWitnessSet + ) + ), + TE.map(() => contractTextEnvelope.contractId) + ) + ), + TE.chainFirstW((contractId) => + wallet.waitConfirmation(pipe(contractId, contractIdToTxId)) + ) + ); -export const create - : (client : RestAPI) - => (wallet : WalletAPI) - => (payload : CreateRequest) - => TE.TaskEither - = (client) => (wallet) => (payload) => - pipe( getAddressesAndCollaterals (wallet) - , TE.fromTask - , TE.chain((addressesAndCollaterals) => - client.contracts.post( - ( { contract: payload.contract - , version: "v1" - , roles : payload.roles - , tags : payload.tags?payload.tags:{} - , metadata: payload.metadata?payload.metadata:{} - , minUTxODeposit: payload.minUTxODeposit?payload.minUTxODeposit:3_000_000}) - , addressesAndCollaterals)) - , TE.chainW((contractTextEnvelope) => - pipe ( wallet.signTxTheCIP30Way(contractTextEnvelope.tx.cborHex) - , TE.chain((hexTransactionWitnessSet) => - client.contracts.contract.put( contractTextEnvelope.contractId, hexTransactionWitnessSet)) - , TE.map (() => contractTextEnvelope.contractId))) - , TE.chainFirstW((contractId) => wallet.waitConfirmation(pipe(contractId, contractIdToTxId))) - ) +export const applyInputs: ( + client: RestAPI +) => ( + wallet: WalletAPI +) => ( + contractId: ContractId +) => ( + payload: ApplyInputsRequest +) => TE.TaskEither = + (client) => (wallet) => (contractId) => (payload) => + pipe( + getAddressesAndCollaterals(wallet), + TE.fromTask, + TE.chain((addressesAndCollaterals) => + client.contracts.contract.transactions.post( + contractId, + { + inputs: payload.inputs, + version: "v1", + tags: payload.tags ? payload.tags : {}, + metadata: payload.metadata ? payload.metadata : {}, + invalidBefore: payload.invalidBefore, + invalidHereafter: payload.invalidHereafter, + }, + addressesAndCollaterals + ) + ), + TE.chainW((transactionTextEnvelope) => + pipe( + wallet.signTxTheCIP30Way(transactionTextEnvelope.tx.cborHex), + TE.chain((hexTransactionWitnessSet) => + client.contracts.contract.transactions.transaction.put( + contractId, + transactionTextEnvelope.transactionId, + hexTransactionWitnessSet + ) + ), + TE.map(() => transactionTextEnvelope.transactionId) + ) + ), + TE.chainFirstW((transactionId) => + wallet.waitConfirmation(pipe(transactionId, Tx.idToTxId)) + ), + TE.map(() => contractId) + ); -export const applyInputs - : (client : RestAPI) - => (wallet : WalletAPI) - => (contractId : ContractId) - => (payload : ApplyInputsRequest) - => TE.TaskEither - = (client) => (wallet) => (contractId) => (payload) => - pipe( getAddressesAndCollaterals (wallet) - , TE.fromTask - , TE.chain((addressesAndCollaterals) => - client.contracts.contract.transactions.post - ( contractId - , { inputs: payload.inputs - , version: "v1" - , tags : payload.tags?payload.tags:{} - , metadata: payload.metadata?payload.metadata:{} - , invalidBefore: payload.invalidBefore - , invalidHereafter: payload.invalidHereafter} - , addressesAndCollaterals)) - , TE.chainW((transactionTextEnvelope) => - pipe ( wallet.signTxTheCIP30Way(transactionTextEnvelope.tx.cborHex) - , TE.chain((hexTransactionWitnessSet) => - client.contracts.contract.transactions.transaction.put( contractId,transactionTextEnvelope.transactionId, hexTransactionWitnessSet)) - , TE.map (() => transactionTextEnvelope.transactionId))) - , TE.chainFirstW((transactionId) => wallet.waitConfirmation(pipe(transactionId, Tx.idToTxId))) - , TE.map (() => contractId)) - -export const withdraw - : (client : RestAPI) - => (wallet : WalletAPI) - => (payoutIds : PayoutId[]) - => TE.TaskEither - = (client) => (wallet) => (payoutIds) => - pipe( getAddressesAndCollaterals (wallet) - , TE.fromTask - , TE.chain((addressesAndCollaterals) => client.withdrawals.post (payoutIds, addressesAndCollaterals)) - , TE.chainW( (withdrawalTextEnvelope) => - pipe ( wallet.signTxTheCIP30Way(withdrawalTextEnvelope.tx.cborHex) - , TE.chain ((hexTransactionWitnessSet) => client.withdrawals.withdrawal.put(withdrawalTextEnvelope.withdrawalId,hexTransactionWitnessSet)) - , TE.map (() => withdrawalTextEnvelope.withdrawalId))) - , TE.chainFirstW((withdrawalId) => wallet.waitConfirmation(pipe(withdrawalId, withdrawalIdToTxId))) - , TE.map (constVoid)) \ No newline at end of file +export const withdraw: ( + client: RestAPI +) => ( + wallet: WalletAPI +) => (payoutIds: PayoutId[]) => TE.TaskEither = + (client) => (wallet) => (payoutIds) => + pipe( + getAddressesAndCollaterals(wallet), + TE.fromTask, + TE.chain((addressesAndCollaterals) => + client.withdrawals.post(payoutIds, addressesAndCollaterals) + ), + TE.chainW((withdrawalTextEnvelope) => + pipe( + wallet.signTxTheCIP30Way(withdrawalTextEnvelope.tx.cborHex), + TE.chain((hexTransactionWitnessSet) => + client.withdrawals.withdrawal.put( + withdrawalTextEnvelope.withdrawalId, + hexTransactionWitnessSet + ) + ), + TE.map(() => withdrawalTextEnvelope.withdrawalId) + ) + ), + TE.chainFirstW((withdrawalId) => + wallet.waitConfirmation(pipe(withdrawalId, withdrawalIdToTxId)) + ), + TE.map(constVoid) + ); diff --git a/packages/runtime/lifecycle/src/tsconfig.json b/packages/runtime/lifecycle/src/tsconfig.json index 35654f54..cea0900b 100644 --- a/packages/runtime/lifecycle/src/tsconfig.json +++ b/packages/runtime/lifecycle/src/tsconfig.json @@ -7,7 +7,9 @@ "@marlowe.io/runtime-core/*": ["../../../runtime/core/src/*"], "@marlowe.io/wallet/*": ["../../../wallet/src/*"], "@marlowe.io/language-core-v1/*": ["../../../language/core/v1/src/*"], - "@marlowe.io/runtime-rest-client/*": ["../../../runtime/client/rest/src/*"] + "@marlowe.io/runtime-rest-client/*": [ + "../../../runtime/client/rest/src/*" + ] } }, "references": [ diff --git a/packages/runtime/lifecycle/test/context.ts b/packages/runtime/lifecycle/test/context.ts index e1cbf48a..9bf0eed9 100644 --- a/packages/runtime/lifecycle/test/context.ts +++ b/packages/runtime/lifecycle/test/context.ts @@ -1,26 +1,31 @@ import { Network } from "lucid-cardano"; -import { Context, getPrivateKeyFromHexString } from '@marlowe.io/wallet/nodejs'; +import { Context, getPrivateKeyFromHexString } from "@marlowe.io/wallet/nodejs"; - -export function getBlockfrostContext () : Context { - const { BLOCKFROST_URL, BLOCKFROST_PROJECT_ID, NETWORK_ID } = process.env; - if (BLOCKFROST_URL == undefined) throw "environment configurations not available (BLOCKFROST_URL)" - if (BLOCKFROST_PROJECT_ID == undefined) throw "environment configurations not available (BLOCKFROST_PROJECT_ID)" - if (NETWORK_ID == undefined) throw "environment configurations not available (NETWORK_ID)" - return new Context ( BLOCKFROST_PROJECT_ID as string - , BLOCKFROST_URL as string - , NETWORK_ID as Network); - }; - -export function getBankPrivateKey () : string { - const { BANK_PK_HEX } = process.env; - if (BANK_PK_HEX == undefined) throw "environment configurations not available (BANK_PK_HEX)" - return getPrivateKeyFromHexString(BANK_PK_HEX as string) +export function getBlockfrostContext(): Context { + const { BLOCKFROST_URL, BLOCKFROST_PROJECT_ID, NETWORK_ID } = process.env; + if (BLOCKFROST_URL == undefined) + throw "environment configurations not available (BLOCKFROST_URL)"; + if (BLOCKFROST_PROJECT_ID == undefined) + throw "environment configurations not available (BLOCKFROST_PROJECT_ID)"; + if (NETWORK_ID == undefined) + throw "environment configurations not available (NETWORK_ID)"; + return new Context( + BLOCKFROST_PROJECT_ID as string, + BLOCKFROST_URL as string, + NETWORK_ID as Network + ); } -export function getMarloweRuntimeUrl () : string { - const { MARLOWE_WEB_SERVER_URL} = process.env; - if (MARLOWE_WEB_SERVER_URL == undefined) throw "environment configurations not available(MARLOWE_WEB_SERVER_URL)" - return MARLOWE_WEB_SERVER_URL as string -}; +export function getBankPrivateKey(): string { + const { BANK_PK_HEX } = process.env; + if (BANK_PK_HEX == undefined) + throw "environment configurations not available (BANK_PK_HEX)"; + return getPrivateKeyFromHexString(BANK_PK_HEX as string); +} +export function getMarloweRuntimeUrl(): string { + const { MARLOWE_WEB_SERVER_URL } = process.env; + if (MARLOWE_WEB_SERVER_URL == undefined) + throw "environment configurations not available(MARLOWE_WEB_SERVER_URL)"; + return MARLOWE_WEB_SERVER_URL as string; +} diff --git a/packages/runtime/lifecycle/test/examples/swap.ada.token.spec.e2e.ts b/packages/runtime/lifecycle/test/examples/swap.ada.token.spec.e2e.ts index f03af883..374e0c7f 100644 --- a/packages/runtime/lifecycle/test/examples/swap.ada.token.spec.e2e.ts +++ b/packages/runtime/lifecycle/test/examples/swap.ada.token.spec.e2e.ts @@ -1,76 +1,131 @@ +import { pipe } from "fp-ts/lib/function.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import { addDays } from "date-fns/fp"; +import { toInput } from "@marlowe.io/language-core-v1/next"; +import * as Examples from "@marlowe.io/language-core-v1/examples"; +import { datetoTimeout, adaValue } from "@marlowe.io/language-core-v1"; +import { mkRestClient } from "@marlowe.io/runtime-rest-client/index.js"; +import { + getBankPrivateKey, + getBlockfrostContext, + getMarloweRuntimeUrl, +} from "../context.js"; +import { provisionAnAdaAndTokenProvider } from "../provisionning.js"; +import console from "console"; +import { runtimeTokenToMarloweTokenValue } from "@marlowe.io/runtime-core"; +import { onlyByContractIds } from "@marlowe.io/runtime-lifecycle/api"; -import { pipe } from 'fp-ts/lib/function.js' -import * as TE from 'fp-ts/lib/TaskEither.js' -import { addDays } from 'date-fns/fp' +global.console = console; -import { toInput } from '@marlowe.io/language-core-v1/next'; -import * as Examples from '@marlowe.io/language-core-v1/examples' -import { datetoTimeout, adaValue } from '@marlowe.io/language-core-v1' -import { mkRestClient } from '@marlowe.io/runtime-rest-client/index.js'; -import { getBankPrivateKey, getBlockfrostContext, getMarloweRuntimeUrl } from '../context.js'; -import { provisionAnAdaAndTokenProvider } from '../provisionning.js' -import console from "console" -import { runtimeTokenToMarloweTokenValue } from '@marlowe.io/runtime-core'; -import { onlyByContractIds } from '@marlowe.io/runtime-lifecycle/api'; +describe("swap", () => { + it("can execute the nominal case", async () => { + const provisionScheme = { + provider: { adaAmount: 20_000_000n }, + swapper: { + adaAmount: 20_000_000n, + tokenAmount: 50n, + tokenName: "TokenA", + }, + }; -global.console = console - -describe('swap', () => { - it('can execute the nominal case', async () => { - const provisionScheme = - { provider : { adaAmount : 20_000_000n} - , swapper : { adaAmount :20_000_000n , tokenAmount : 50n, tokenName : "TokenA" }} - - await - pipe( provisionAnAdaAndTokenProvider - (mkRestClient(getMarloweRuntimeUrl())) - (getBlockfrostContext ()) - (getBankPrivateKey()) - (provisionScheme) - , TE.let (`swapRequest`, ({tokenValueMinted}) => - ({ provider : - { roleName : 'Ada provider' - , depositTimeout : pipe(Date.now(),addDays(1),datetoTimeout) - , value : adaValue(2n)} - , swapper : - { roleName : 'Token provider' - , depositTimeout : pipe(Date.now(),addDays(2),datetoTimeout) - , value : runtimeTokenToMarloweTokenValue(tokenValueMinted)} - })) - , TE.let (`swapContract`, ({swapRequest}) => Examples.SwapADAToken.mkSwapContract(swapRequest)) - , TE.bindW('swapClosedResult',({runtime,adaProvider,tokenProvider,swapRequest,swapContract}) => - pipe( runtime(adaProvider).contracts.create - ( { contract: swapContract - , roles: {[swapRequest.provider.roleName] : adaProvider.address - ,[swapRequest.swapper.roleName] : tokenProvider.address}}) - , TE.chainW ((contractId) => - runtime(adaProvider).contracts.applyInputs(contractId) - ((next) => ({ inputs : [pipe(next.applicable_inputs.deposits[0],toInput)]}))) - , TE.chainW ((contractId) => - runtime(tokenProvider).contracts.applyInputs(contractId) - ((next) => ({ inputs : [pipe(next.applicable_inputs.deposits[0],toInput)]}))) - , TE.chainW ((contractId) => - TE.sequenceArray( - [ pipe - ( runtime(adaProvider).payouts.available (onlyByContractIds([contractId])) - , TE.map (payoutsAvalaible => { expect(payoutsAvalaible.length).toBe(1);return payoutsAvalaible.map(payout => payout.payoutId)}) - , TE.chain (payoutIds => runtime(adaProvider).payouts.withdraw(payoutIds)) - , TE.chain ( _ => runtime(adaProvider).payouts.withdrawn (onlyByContractIds([contractId]))) - , TE.map (payoutsWthdrawn => expect(payoutsWthdrawn.length).toBe(1))) - , pipe - ( runtime(tokenProvider).payouts.available (onlyByContractIds([contractId])) - , TE.map (payoutsAvalaible => { expect(payoutsAvalaible.length).toBe(1);return payoutsAvalaible.map(payout => payout.payoutId)}) - , TE.chain (payoutIds => runtime(tokenProvider).payouts.withdraw (payoutIds)) - , TE.chain ( _ => runtime(adaProvider).payouts.withdrawn (onlyByContractIds([contractId]))) - , TE.map (payoutsWthdrawn => expect(payoutsWthdrawn.length).toBe(1)) - ) - ])) - )) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined()}, - () => { } )) () - - },1_000_000); + await pipe( + provisionAnAdaAndTokenProvider(mkRestClient(getMarloweRuntimeUrl()))( + getBlockfrostContext() + )(getBankPrivateKey())(provisionScheme), + TE.let(`swapRequest`, ({ tokenValueMinted }) => ({ + provider: { + roleName: "Ada provider", + depositTimeout: pipe(Date.now(), addDays(1), datetoTimeout), + value: adaValue(2n), + }, + swapper: { + roleName: "Token provider", + depositTimeout: pipe(Date.now(), addDays(2), datetoTimeout), + value: runtimeTokenToMarloweTokenValue(tokenValueMinted), + }, + })), + TE.let(`swapContract`, ({ swapRequest }) => + Examples.SwapADAToken.mkSwapContract(swapRequest) + ), + TE.bindW( + "swapClosedResult", + ({ runtime, adaProvider, tokenProvider, swapRequest, swapContract }) => + pipe( + runtime(adaProvider).contracts.create({ + contract: swapContract, + roles: { + [swapRequest.provider.roleName]: adaProvider.address, + [swapRequest.swapper.roleName]: tokenProvider.address, + }, + }), + TE.chainW((contractId) => + runtime(adaProvider).contracts.applyInputs(contractId)( + (next) => ({ + inputs: [pipe(next.applicable_inputs.deposits[0], toInput)], + }) + ) + ), + TE.chainW((contractId) => + runtime(tokenProvider).contracts.applyInputs(contractId)( + (next) => ({ + inputs: [pipe(next.applicable_inputs.deposits[0], toInput)], + }) + ) + ), + TE.chainW((contractId) => + TE.sequenceArray([ + pipe( + runtime(adaProvider).payouts.available( + onlyByContractIds([contractId]) + ), + TE.map((payoutsAvalaible) => { + expect(payoutsAvalaible.length).toBe(1); + return payoutsAvalaible.map((payout) => payout.payoutId); + }), + TE.chain((payoutIds) => + runtime(adaProvider).payouts.withdraw(payoutIds) + ), + TE.chain((_) => + runtime(adaProvider).payouts.withdrawn( + onlyByContractIds([contractId]) + ) + ), + TE.map((payoutsWthdrawn) => + expect(payoutsWthdrawn.length).toBe(1) + ) + ), + pipe( + runtime(tokenProvider).payouts.available( + onlyByContractIds([contractId]) + ), + TE.map((payoutsAvalaible) => { + expect(payoutsAvalaible.length).toBe(1); + return payoutsAvalaible.map((payout) => payout.payoutId); + }), + TE.chain((payoutIds) => + runtime(tokenProvider).payouts.withdraw(payoutIds) + ), + TE.chain((_) => + runtime(adaProvider).payouts.withdrawn( + onlyByContractIds([contractId]) + ) + ), + TE.map((payoutsWthdrawn) => + expect(payoutsWthdrawn.length).toBe(1) + ) + ), + ]) + ) + ) + ), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + () => {} + ) + )(); + }, 1_000_000); }); - diff --git a/packages/runtime/lifecycle/test/provisionning.ts b/packages/runtime/lifecycle/test/provisionning.ts index 5395a367..37933963 100644 --- a/packages/runtime/lifecycle/test/provisionning.ts +++ b/packages/runtime/lifecycle/test/provisionning.ts @@ -1,79 +1,143 @@ -import * as TE from 'fp-ts/lib/TaskEither.js' -import * as T from 'fp-ts/lib/Task.js' -import { pipe } from 'fp-ts/lib/function.js' +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as T from "fp-ts/lib/Task.js"; +import { pipe } from "fp-ts/lib/function.js"; -import { TokenName } from '@marlowe.io/language-core-v1' -import { mkRuntimeLifecycle } from '@marlowe.io/runtime-lifecycle/overRestAPI' -import { RestAPI } from '@marlowe.io/runtime-rest-client/index.js' -import { Context, SingleAddressWallet, PrivateKeysAsHex } from '@marlowe.io/wallet/nodejs'; -import { assetIdToString } from '@marlowe.io/runtime-core' +import { TokenName } from "@marlowe.io/language-core-v1"; +import { mkRuntimeLifecycle } from "@marlowe.io/runtime-lifecycle/overRestAPI"; +import { RestAPI } from "@marlowe.io/runtime-rest-client/index.js"; +import { + Context, + SingleAddressWallet, + PrivateKeysAsHex, +} from "@marlowe.io/wallet/nodejs"; +import { assetIdToString } from "@marlowe.io/runtime-core"; -const log = (message:string) => console.log(`\t## - ${message}`); -const formatADA = (lovelaces:bigint): String => new Intl.NumberFormat().format((lovelaces / 1_000_000n)).concat(" ₳"); +const log = (message: string) => console.log(`\t## - ${message}`); +const formatADA = (lovelaces: bigint): String => + new Intl.NumberFormat().format(lovelaces / 1_000_000n).concat(" ₳"); -export type ProvisionScheme = - { provider : {adaAmount : bigint} - , swapper : {adaAmount :bigint,tokenAmount : bigint, tokenName : TokenName} - } +export type ProvisionScheme = { + provider: { adaAmount: bigint }; + swapper: { adaAmount: bigint; tokenAmount: bigint; tokenName: TokenName }; +}; -export const provisionAnAdaAndTokenProvider - = (restAPI: RestAPI) => - (walletContext: Context) => - (bankPrivateKey : PrivateKeysAsHex) => - (scheme : ProvisionScheme) => - pipe( TE.Do - // Generating/Initialising Accounts - , T.bind('bank',() => SingleAddressWallet.Initialise (walletContext,bankPrivateKey)) - , T.bind('adaProvider',() => SingleAddressWallet.Random(walletContext)) - , T.bind('tokenProvider',() => SingleAddressWallet.Random(walletContext)) - , TE.fromTask - // Check Banks treasury - , TE.bind('bankBalance',({bank}) => bank.getLovelaces) - , TE.chainFirst(({bankBalance,bank}) => TE.of(pipe( - log(`Bank (${bank.address})`), - () => log(` - ${formatADA(bankBalance)}`)))) - , TE.chainFirst(({bankBalance}) => TE.of(expect(bankBalance).toBeGreaterThan(100_000_000))) - // Provisionning - , TE.chainFirst(({bank,adaProvider,tokenProvider}) => - bank.provision([[adaProvider,scheme.provider.adaAmount], - [tokenProvider,scheme.swapper.adaAmount]])) - , TE.bind('tokenValueMinted',({tokenProvider}) => tokenProvider.mintRandomTokens(scheme.swapper.tokenName,scheme.swapper.tokenAmount)) - // Provisionning Checks - // Ada Provider - , TE.bind('adaProviderBalance',({adaProvider}) => adaProvider.getLovelaces) - , TE.chainFirst(({adaProvider,adaProviderBalance}) => TE.of(pipe( - log( `Ada Provider (${adaProvider.address}`), - () => log(` - ${formatADA(adaProviderBalance)}`)))) - // Token Provider - , TE.bind('tokenProviderADABalance',({tokenProvider}) => tokenProvider.getLovelaces) - , TE.bind('tokenBalance' ,({tokenProvider,tokenValueMinted}) => tokenProvider.tokenBalance(tokenValueMinted.assetId)) - , TE.chainFirst(({tokenProvider,tokenProviderADABalance,tokenValueMinted,tokenBalance}) => TE.of(pipe( - log(`Token Provider (${tokenProvider.address})`), - () => log( ` - ${formatADA(tokenProviderADABalance)}`), - () => log( ` - ${tokenBalance} ${assetIdToString(tokenValueMinted.assetId)}`)))) - , TE.chainFirst(({tokenBalance}) => TE.of(expect(tokenBalance).toBe(scheme.swapper.tokenAmount))) - , TE.map (({adaProvider,tokenProvider,tokenValueMinted}) => - ({ adaProvider:adaProvider - , tokenProvider:tokenProvider - , tokenValueMinted:tokenValueMinted - , restAPI : restAPI - , runtime : mkRuntimeLifecycle(restAPI)}))) +export const provisionAnAdaAndTokenProvider = + (restAPI: RestAPI) => + (walletContext: Context) => + (bankPrivateKey: PrivateKeysAsHex) => + (scheme: ProvisionScheme) => + pipe( + TE.Do, + // Generating/Initialising Accounts + T.bind("bank", () => + SingleAddressWallet.Initialise(walletContext, bankPrivateKey) + ), + T.bind("adaProvider", () => SingleAddressWallet.Random(walletContext)), + T.bind("tokenProvider", () => SingleAddressWallet.Random(walletContext)), + TE.fromTask, + // Check Banks treasury + TE.bind("bankBalance", ({ bank }) => bank.getLovelaces), + TE.chainFirst(({ bankBalance, bank }) => + TE.of( + pipe(log(`Bank (${bank.address})`), () => + log(` - ${formatADA(bankBalance)}`) + ) + ) + ), + TE.chainFirst(({ bankBalance }) => + TE.of(expect(bankBalance).toBeGreaterThan(100_000_000)) + ), + // Provisionning + TE.chainFirst(({ bank, adaProvider, tokenProvider }) => + bank.provision([ + [adaProvider, scheme.provider.adaAmount], + [tokenProvider, scheme.swapper.adaAmount], + ]) + ), + TE.bind("tokenValueMinted", ({ tokenProvider }) => + tokenProvider.mintRandomTokens( + scheme.swapper.tokenName, + scheme.swapper.tokenAmount + ) + ), + // Provisionning Checks + // Ada Provider + TE.bind( + "adaProviderBalance", + ({ adaProvider }) => adaProvider.getLovelaces + ), + TE.chainFirst(({ adaProvider, adaProviderBalance }) => + TE.of( + pipe(log(`Ada Provider (${adaProvider.address}`), () => + log(` - ${formatADA(adaProviderBalance)}`) + ) + ) + ), + // Token Provider + TE.bind( + "tokenProviderADABalance", + ({ tokenProvider }) => tokenProvider.getLovelaces + ), + TE.bind("tokenBalance", ({ tokenProvider, tokenValueMinted }) => + tokenProvider.tokenBalance(tokenValueMinted.assetId) + ), + TE.chainFirst( + ({ + tokenProvider, + tokenProviderADABalance, + tokenValueMinted, + tokenBalance, + }) => + TE.of( + pipe( + log(`Token Provider (${tokenProvider.address})`), + () => log(` - ${formatADA(tokenProviderADABalance)}`), + () => + log( + ` - ${tokenBalance} ${assetIdToString( + tokenValueMinted.assetId + )}` + ) + ) + ) + ), + TE.chainFirst(({ tokenBalance }) => + TE.of(expect(tokenBalance).toBe(scheme.swapper.tokenAmount)) + ), + TE.map(({ adaProvider, tokenProvider, tokenValueMinted }) => ({ + adaProvider: adaProvider, + tokenProvider: tokenProvider, + tokenValueMinted: tokenValueMinted, + restAPI: restAPI, + runtime: mkRuntimeLifecycle(restAPI), + })) + ); - -export const initialiseBankAndverifyProvisionning - = (restAPI: RestAPI) => - (walletContext: Context) => - (bankPrivateKey : PrivateKeysAsHex) => - pipe( TE.Do - , T.bind('bank',() => SingleAddressWallet.Initialise (walletContext,bankPrivateKey)) - , TE.fromTask - // Check Banks treasury - , TE.bind('bankBalance',({bank}) => bank.getLovelaces) - , TE.chainFirst(({bankBalance,bank}) => TE.of(pipe( - log(`Bank (${bank.address})`), - () => log(` - ${formatADA(bankBalance)}`)))) - , TE.chainFirst(({bankBalance}) => TE.of(expect(bankBalance).toBeGreaterThan(100_000_000))) - , TE.map (({bank}) => - ({ bank : bank - , restAPI : restAPI - , runtime : mkRuntimeLifecycle(restAPI)(bank)}))) \ No newline at end of file +export const initialiseBankAndverifyProvisionning = + (restAPI: RestAPI) => + (walletContext: Context) => + (bankPrivateKey: PrivateKeysAsHex) => + pipe( + TE.Do, + T.bind("bank", () => + SingleAddressWallet.Initialise(walletContext, bankPrivateKey) + ), + TE.fromTask, + // Check Banks treasury + TE.bind("bankBalance", ({ bank }) => bank.getLovelaces), + TE.chainFirst(({ bankBalance, bank }) => + TE.of( + pipe(log(`Bank (${bank.address})`), () => + log(` - ${formatADA(bankBalance)}`) + ) + ) + ), + TE.chainFirst(({ bankBalance }) => + TE.of(expect(bankBalance).toBeGreaterThan(100_000_000)) + ), + TE.map(({ bank }) => ({ + bank: bank, + restAPI: restAPI, + runtime: mkRuntimeLifecycle(restAPI)(bank), + })) + ); diff --git a/packages/runtime/lifecycle/test/tx/apply.inputs.spec.e2e.ts b/packages/runtime/lifecycle/test/tx/apply.inputs.spec.e2e.ts index 472ff02f..f0901d79 100644 --- a/packages/runtime/lifecycle/test/tx/apply.inputs.spec.e2e.ts +++ b/packages/runtime/lifecycle/test/tx/apply.inputs.spec.e2e.ts @@ -1,40 +1,55 @@ - -import { pipe } from 'fp-ts/lib/function.js' -import * as TE from 'fp-ts/lib/TaskEither.js' -import * as O from 'fp-ts/lib/Option.js'; -import { addDays } from 'date-fns/fp'; - -import { datetoTimeout, inputNotify } from '@marlowe.io/language-core-v1'; -import { oneNotifyTrue } from '@marlowe.io/language-core-v1/examples' -import { mkRestClient } from '@marlowe.io/runtime-rest-client/index.js'; - -import { getBankPrivateKey, getBlockfrostContext, getMarloweRuntimeUrl } from '../context.js'; -import { initialiseBankAndverifyProvisionning } from '../provisionning.js' -import console from "console" - -global.console = console - -describe('Marlowe Tx Commands', () => { - - it('can Apply Inputs', async () => { - await - pipe( initialiseBankAndverifyProvisionning - (mkRestClient(getMarloweRuntimeUrl())) - (getBlockfrostContext ()) - (getBankPrivateKey()) - , TE.let (`notifyTimeout`, () => pipe(Date.now(),addDays(1),datetoTimeout)) - , TE.bind('result',({restAPI,runtime,bank,notifyTimeout}) => - pipe - ( runtime.contracts.create ({ contract: oneNotifyTrue(notifyTimeout)}) - , TE.chainW ((contractId) => runtime.contracts.applyInputs(contractId) ((next) => ({ inputs : [inputNotify]}))) - , TE.chainW ( contractId => restAPI.contracts.contract.transactions.getHeadersByRange (contractId,O.none)) - , TE.map ((result) => expect(result.headers.length).toBe(1)))) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined()}, - () => {}) - ) () - },100_000) -}) - - - +import { pipe } from "fp-ts/lib/function.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as O from "fp-ts/lib/Option.js"; +import { addDays } from "date-fns/fp"; + +import { datetoTimeout, inputNotify } from "@marlowe.io/language-core-v1"; +import { oneNotifyTrue } from "@marlowe.io/language-core-v1/examples"; +import { mkRestClient } from "@marlowe.io/runtime-rest-client/index.js"; + +import { + getBankPrivateKey, + getBlockfrostContext, + getMarloweRuntimeUrl, +} from "../context.js"; +import { initialiseBankAndverifyProvisionning } from "../provisionning.js"; +import console from "console"; + +global.console = console; + +describe("Marlowe Tx Commands", () => { + it("can Apply Inputs", async () => { + await pipe( + initialiseBankAndverifyProvisionning( + mkRestClient(getMarloweRuntimeUrl()) + )(getBlockfrostContext())(getBankPrivateKey()), + TE.let(`notifyTimeout`, () => + pipe(Date.now(), addDays(1), datetoTimeout) + ), + TE.bind("result", ({ restAPI, runtime, bank, notifyTimeout }) => + pipe( + runtime.contracts.create({ contract: oneNotifyTrue(notifyTimeout) }), + TE.chainW((contractId) => + runtime.contracts.applyInputs(contractId)((next) => ({ + inputs: [inputNotify], + })) + ), + TE.chainW((contractId) => + restAPI.contracts.contract.transactions.getHeadersByRange( + contractId, + O.none + ) + ), + TE.map((result) => expect(result.headers.length).toBe(1)) + ) + ), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + () => {} + ) + )(); + }, 100_000); +}); diff --git a/packages/runtime/lifecycle/test/tx/create.spec.e2e.ts b/packages/runtime/lifecycle/test/tx/create.spec.e2e.ts index aab14ad4..c9a3b149 100644 --- a/packages/runtime/lifecycle/test/tx/create.spec.e2e.ts +++ b/packages/runtime/lifecycle/test/tx/create.spec.e2e.ts @@ -1,36 +1,41 @@ - -import { pipe } from 'fp-ts/lib/function.js' -import * as TE from 'fp-ts/lib/TaskEither.js'; -import * as O from 'fp-ts/lib/Option.js'; - -import { close } from '@marlowe.io/language-core-v1' -import { create } from '@marlowe.io/runtime-lifecycle/tx'; -import { mkRestClient } from '@marlowe.io/runtime-rest-client/index.js'; - -import { initialiseBankAndverifyProvisionning } from '../provisionning.js'; -import { getBankPrivateKey, getBlockfrostContext, getMarloweRuntimeUrl } from '../context.js'; - -import console from "console" -global.console = console - -describe('Marlowe Tx Commands', () => { - - const restClient = mkRestClient(getMarloweRuntimeUrl()) - - it('can create a Marlowe Contract ' , async () => { - await - pipe(initialiseBankAndverifyProvisionning - (restClient) - (getBlockfrostContext()) - (getBankPrivateKey()) - , TE.bindW('contracId', ({ bank }) => create (restClient)(bank)({contract: close})) - , TE.match( - (e) => { - console.dir(e, { depth: null }); - expect(e).not.toBeDefined() - }, - (result) => {console.log("contractID created" ,result.contracId) }))() - - }, 1_000_000) -}) - +import { pipe } from "fp-ts/lib/function.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as O from "fp-ts/lib/Option.js"; + +import { close } from "@marlowe.io/language-core-v1"; +import { create } from "@marlowe.io/runtime-lifecycle/tx"; +import { mkRestClient } from "@marlowe.io/runtime-rest-client/index.js"; + +import { initialiseBankAndverifyProvisionning } from "../provisionning.js"; +import { + getBankPrivateKey, + getBlockfrostContext, + getMarloweRuntimeUrl, +} from "../context.js"; + +import console from "console"; +global.console = console; + +describe("Marlowe Tx Commands", () => { + const restClient = mkRestClient(getMarloweRuntimeUrl()); + + it("can create a Marlowe Contract ", async () => { + await pipe( + initialiseBankAndverifyProvisionning(restClient)(getBlockfrostContext())( + getBankPrivateKey() + ), + TE.bindW("contracId", ({ bank }) => + create(restClient)(bank)({ contract: close }) + ), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + (result) => { + console.log("contractID created", result.contracId); + } + ) + )(); + }, 1_000_000); +}); diff --git a/packages/runtime/lifecycle/test/tx/withdraw.spec.e2e.ts b/packages/runtime/lifecycle/test/tx/withdraw.spec.e2e.ts index 8af3cfc2..34a0ebef 100644 --- a/packages/runtime/lifecycle/test/tx/withdraw.spec.e2e.ts +++ b/packages/runtime/lifecycle/test/tx/withdraw.spec.e2e.ts @@ -1,78 +1,117 @@ -import { pipe } from 'fp-ts/lib/function.js'; -import * as TE from 'fp-ts/lib/TaskEither.js'; -import { addDays } from 'date-fns/fp'; +import { pipe } from "fp-ts/lib/function.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import { addDays } from "date-fns/fp"; -import * as Examples from '@marlowe.io/language-core-v1/examples'; -import { datetoTimeout, adaValue } from '@marlowe.io/language-core-v1'; -import { toInput } from '@marlowe.io/language-core-v1/next'; -import { mkRestClient } from '@marlowe.io/runtime-rest-client/index.js'; +import * as Examples from "@marlowe.io/language-core-v1/examples"; +import { datetoTimeout, adaValue } from "@marlowe.io/language-core-v1"; +import { toInput } from "@marlowe.io/language-core-v1/next"; +import { mkRestClient } from "@marlowe.io/runtime-rest-client/index.js"; -import { getBankPrivateKey, getBlockfrostContext, getMarloweRuntimeUrl } from '../context.js'; -import { provisionAnAdaAndTokenProvider } from '../provisionning.js'; -import console from "console" -import { runtimeTokenToMarloweTokenValue } from '@marlowe.io/runtime-core'; -import { onlyByContractIds } from '@marlowe.io/runtime-lifecycle/api'; +import { + getBankPrivateKey, + getBlockfrostContext, + getMarloweRuntimeUrl, +} from "../context.js"; +import { provisionAnAdaAndTokenProvider } from "../provisionning.js"; +import console from "console"; +import { runtimeTokenToMarloweTokenValue } from "@marlowe.io/runtime-core"; +import { onlyByContractIds } from "@marlowe.io/runtime-lifecycle/api"; -global.console = console +global.console = console; -describe('Payouts', () => { +describe("Payouts", () => { + const restAPI = mkRestClient(getMarloweRuntimeUrl()); + const provisionScheme = { + provider: { adaAmount: 20_000_000n }, + swapper: { adaAmount: 20_000_000n, tokenAmount: 50n, tokenName: "TokenA" }, + }; - const restAPI = mkRestClient(getMarloweRuntimeUrl()) - const provisionScheme = - { provider : { adaAmount : 20_000_000n} - , swapper : { adaAmount :20_000_000n , tokenAmount : 50n, tokenName : "TokenA" }} + const executeSwapWithRequiredWithdrawalTillClosing = pipe( + provisionAnAdaAndTokenProvider(restAPI)(getBlockfrostContext())( + getBankPrivateKey() + )(provisionScheme), + TE.let(`swapRequest`, ({ tokenValueMinted }) => ({ + provider: { + roleName: "Ada provider", + depositTimeout: pipe(Date.now(), addDays(1), datetoTimeout), + value: adaValue(2n), + }, + swapper: { + roleName: "Token provider", + depositTimeout: pipe(Date.now(), addDays(2), datetoTimeout), + value: runtimeTokenToMarloweTokenValue(tokenValueMinted), + }, + })), + TE.let(`swapContract`, ({ swapRequest }) => + Examples.SwapADAToken.mkSwapContract(swapRequest) + ), + TE.bindW( + "contractId", + ({ runtime, adaProvider, tokenProvider, swapRequest, swapContract }) => + pipe( + runtime(adaProvider).contracts.create({ + contract: swapContract, + roles: { + [swapRequest.provider.roleName]: adaProvider.address, + [swapRequest.swapper.roleName]: tokenProvider.address, + }, + }), + TE.chainW((contractId) => + runtime(adaProvider).contracts.applyInputs(contractId)((next) => ({ + inputs: [pipe(next.applicable_inputs.deposits[0], toInput)], + })) + ), + TE.chainW((contractId) => + runtime(tokenProvider).contracts.applyInputs(contractId)( + (next) => ({ + inputs: [pipe(next.applicable_inputs.deposits[0], toInput)], + }) + ) + ) + ) + ) + ); - const executeSwapWithRequiredWithdrawalTillClosing - = pipe( provisionAnAdaAndTokenProvider - (restAPI) - (getBlockfrostContext ()) - (getBankPrivateKey()) - (provisionScheme) - , TE.let (`swapRequest`, ({tokenValueMinted}) => - ({ provider : - { roleName : 'Ada provider' - , depositTimeout : pipe(Date.now(),addDays(1),datetoTimeout) - , value : adaValue(2n)} - , swapper : - { roleName : 'Token provider' - , depositTimeout : pipe(Date.now(),addDays(2),datetoTimeout) - , value : runtimeTokenToMarloweTokenValue(tokenValueMinted)} - })) - , TE.let (`swapContract`, ({swapRequest}) => Examples.SwapADAToken.mkSwapContract(swapRequest)) - , TE.bindW('contractId',({runtime,adaProvider,tokenProvider,swapRequest,swapContract}) => - pipe( runtime(adaProvider).contracts.create - ( { contract: swapContract - , roles: {[swapRequest.provider.roleName] : adaProvider.address - ,[swapRequest.swapper.roleName] : tokenProvider.address}}) - , TE.chainW ((contractId) => - runtime(adaProvider).contracts.applyInputs - (contractId) - ((next) => ({ inputs : [pipe(next.applicable_inputs.deposits[0],toInput)]}))) - , TE.chainW (contractId => - runtime(tokenProvider).contracts.applyInputs - (contractId) - ((next) => ({ inputs : [pipe(next.applicable_inputs.deposits[0],toInput)]})))))) - - it('Payouts can be withdrawn' , async () => { - - await - pipe( executeSwapWithRequiredWithdrawalTillClosing - , TE.bindW('result',({adaProvider,tokenProvider,contractId,runtime}) => - TE.sequenceArray( - [ pipe - ( runtime(adaProvider).payouts.available (onlyByContractIds([contractId])) - , TE.map (payouts => { expect(payouts.length).toBe(1);return payouts.map(payout => payout.payoutId)}) - , TE.chain (payoutIds => runtime(adaProvider).payouts.withdraw(payoutIds))) - , pipe - ( runtime(tokenProvider).payouts.available (onlyByContractIds([contractId])) - , TE.map (payouts => { expect(payouts.length).toBe(1);return payouts.map(payout => payout.payoutId)}) - , TE.chain (payoutIds => runtime(tokenProvider).payouts.withdraw (payoutIds))) - ])) - , TE.match( - (e) => { console.dir(e, { depth: null }); expect(e).not.toBeDefined()}, - () => {} )) () - - - },1_000_000); + it("Payouts can be withdrawn", async () => { + await pipe( + executeSwapWithRequiredWithdrawalTillClosing, + TE.bindW( + "result", + ({ adaProvider, tokenProvider, contractId, runtime }) => + TE.sequenceArray([ + pipe( + runtime(adaProvider).payouts.available( + onlyByContractIds([contractId]) + ), + TE.map((payouts) => { + expect(payouts.length).toBe(1); + return payouts.map((payout) => payout.payoutId); + }), + TE.chain((payoutIds) => + runtime(adaProvider).payouts.withdraw(payoutIds) + ) + ), + pipe( + runtime(tokenProvider).payouts.available( + onlyByContractIds([contractId]) + ), + TE.map((payouts) => { + expect(payouts.length).toBe(1); + return payouts.map((payout) => payout.payoutId); + }), + TE.chain((payoutIds) => + runtime(tokenProvider).payouts.withdraw(payoutIds) + ) + ), + ]) + ), + TE.match( + (e) => { + console.dir(e, { depth: null }); + expect(e).not.toBeDefined(); + }, + () => {} + ) + )(); + }, 1_000_000); }); - diff --git a/packages/token-metadata-client/Readme.md b/packages/token-metadata-client/Readme.md index caa589da..22f9ce1b 100644 --- a/packages/token-metadata-client/Readme.md +++ b/packages/token-metadata-client/Readme.md @@ -1,2 +1,3 @@ # @marlow/token-metadata-client -TODO \ No newline at end of file + +TODO diff --git a/packages/wallet/Readme.md b/packages/wallet/Readme.md index b9c1c7c8..21011aaf 100644 --- a/packages/wallet/Readme.md +++ b/packages/wallet/Readme.md @@ -1,2 +1,3 @@ # @marlowe.io/wallet -TODO \ No newline at end of file + +TODO diff --git a/packages/wallet/src/api.ts b/packages/wallet/src/api.ts index a2a2c791..681fa409 100644 --- a/packages/wallet/src/api.ts +++ b/packages/wallet/src/api.ts @@ -1,38 +1,47 @@ - -import * as T from 'fp-ts/lib/Task.js' -import * as O from 'fp-ts/lib/Option.js' -import { pipe } from 'fp-ts/lib/function.js'; -import * as TE from 'fp-ts/lib/TaskEither.js' - -import { AddressBech32, AddressesAndCollaterals, HexTransactionWitnessSet, MarloweTxCBORHex, Token, TxOutRef } from '@marlowe.io/runtime-core' - - +import * as T from "fp-ts/lib/Task.js"; +import * as O from "fp-ts/lib/Option.js"; +import { pipe } from "fp-ts/lib/function.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; + +import { + AddressBech32, + AddressesAndCollaterals, + HexTransactionWitnessSet, + MarloweTxCBORHex, + Token, + TxOutRef, +} from "@marlowe.io/runtime-core"; // N.B : Network Id returned by CIP30 Interface doesn't provide information on which Testnet Network // the extension in configured. export type CIP30Network = "Mainnet" | "Testnets"; export interface WalletAPI { - waitConfirmation : (txHash : string ) => TE.TaskEither - signTxTheCIP30Way : (tx :MarloweTxCBORHex) => TE.TaskEither - getChangeAddress : T.Task - getUsedAddresses : T.Task - getCollaterals : T.Task - getUTxOs : T.Task - getCIP30Network: T.Task - getTokens : TE.TaskEither - getLovelaces : TE.TaskEither + waitConfirmation: (txHash: string) => TE.TaskEither; + signTxTheCIP30Way: ( + tx: MarloweTxCBORHex + ) => TE.TaskEither; + getChangeAddress: T.Task; + getUsedAddresses: T.Task; + getCollaterals: T.Task; + getUTxOs: T.Task; + getCIP30Network: T.Task; + getTokens: TE.TaskEither; + getLovelaces: TE.TaskEither; } -export const getAddressesAndCollaterals : (walletAPI : WalletAPI) => T.Task = - (walletAPI) => - pipe( T.Do - , T.bind('changeAddress',() => walletAPI.getChangeAddress) - , T.bind('usedAddresses',() => walletAPI.getUsedAddresses) - , T.bind('collateralUTxOs' ,() => walletAPI.getCollaterals) - , T.map (({changeAddress,usedAddresses,collateralUTxOs}) => - ({changeAddress: changeAddress - ,usedAddresses: usedAddresses.length == 0 ? O.none : O.some(usedAddresses) - ,collateralUTxOs: collateralUTxOs.length == 0 ? O.none : O.some(collateralUTxOs)})) - ) - +export const getAddressesAndCollaterals: ( + walletAPI: WalletAPI +) => T.Task = (walletAPI) => + pipe( + T.Do, + T.bind("changeAddress", () => walletAPI.getChangeAddress), + T.bind("usedAddresses", () => walletAPI.getUsedAddresses), + T.bind("collateralUTxOs", () => walletAPI.getCollaterals), + T.map(({ changeAddress, usedAddresses, collateralUTxOs }) => ({ + changeAddress: changeAddress, + usedAddresses: usedAddresses.length == 0 ? O.none : O.some(usedAddresses), + collateralUTxOs: + collateralUTxOs.length == 0 ? O.none : O.some(collateralUTxOs), + })) + ); diff --git a/packages/wallet/src/browser/index.ts b/packages/wallet/src/browser/index.ts index 2635bbd2..87d75050 100644 --- a/packages/wallet/src/browser/index.ts +++ b/packages/wallet/src/browser/index.ts @@ -1,37 +1,62 @@ -import * as T from 'fp-ts/lib/Task.js' -import * as TE from 'fp-ts/lib/TaskEither.js' -import { pipe } from 'fp-ts/lib/function.js'; -import * as A from 'fp-ts/lib/Array.js' - -import { CIP30Network, WalletAPI } from '../api.js'; -import { C,Core } from 'lucid-cardano'; -import { hex, utf8 } from '@47ng/codec' -import { MarloweTxCBORHex, HexTransactionWitnessSet, AddressBech32, TxOutRef, addressBech32, txOutRef, Token, token,lovelaces, assetId, mkPolicyId, unTxOutRef } from '@marlowe.io/runtime-core'; - - -export const getExtensionInstance : (extensionName : string) => T.Task = (extensionName) => - pipe(() => window.cardano[extensionName.toLowerCase()].enable() - ,T.map (extensionCIP30Instance => - ({ waitConfirmation: waitConfirmation(extensionCIP30Instance) - , signTxTheCIP30Way : signMarloweTx(extensionCIP30Instance) - , getChangeAddress : fetchChangeAddress(extensionCIP30Instance) - , getUsedAddresses : fetchUsedAddresses(extensionCIP30Instance) - , getCollaterals : fetchCollaterals(extensionCIP30Instance) - , getUTxOs : fetchUTxOs(extensionCIP30Instance) - , getTokens : fetchTokens(extensionCIP30Instance) - , getLovelaces : fetchLovelaces(extensionCIP30Instance) - , getCIP30Network : fetchCIP30Network(extensionCIP30Instance) - })) ) - - -const waitConfirmation : (extensionCIP30Instance : BroswerExtensionCIP30Api) => (txHash : string ) => TE.TaskEither = -(extensionCIP30Instance) => (txHash) => pipe(() => awaitTx(extensionCIP30Instance,txHash), TE.fromTask) - -function awaitTx(extensionCIP30Instance : BroswerExtensionCIP30Api,txHash: string, checkInterval:number = 3000): Promise { +import * as T from "fp-ts/lib/Task.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import { pipe } from "fp-ts/lib/function.js"; +import * as A from "fp-ts/lib/Array.js"; + +import { CIP30Network, WalletAPI } from "../api.js"; +import { C, Core } from "lucid-cardano"; +import { hex, utf8 } from "@47ng/codec"; +import { + MarloweTxCBORHex, + HexTransactionWitnessSet, + AddressBech32, + TxOutRef, + addressBech32, + txOutRef, + Token, + token, + lovelaces, + assetId, + mkPolicyId, + unTxOutRef, +} from "@marlowe.io/runtime-core"; + +export const getExtensionInstance: ( + extensionName: string +) => T.Task = (extensionName) => + pipe( + () => window.cardano[extensionName.toLowerCase()].enable(), + T.map((extensionCIP30Instance) => ({ + waitConfirmation: waitConfirmation(extensionCIP30Instance), + signTxTheCIP30Way: signMarloweTx(extensionCIP30Instance), + getChangeAddress: fetchChangeAddress(extensionCIP30Instance), + getUsedAddresses: fetchUsedAddresses(extensionCIP30Instance), + getCollaterals: fetchCollaterals(extensionCIP30Instance), + getUTxOs: fetchUTxOs(extensionCIP30Instance), + getTokens: fetchTokens(extensionCIP30Instance), + getLovelaces: fetchLovelaces(extensionCIP30Instance), + getCIP30Network: fetchCIP30Network(extensionCIP30Instance), + })) + ); + +const waitConfirmation: ( + extensionCIP30Instance: BroswerExtensionCIP30Api +) => (txHash: string) => TE.TaskEither = + (extensionCIP30Instance) => (txHash) => + pipe(() => awaitTx(extensionCIP30Instance, txHash), TE.fromTask); + +function awaitTx( + extensionCIP30Instance: BroswerExtensionCIP30Api, + txHash: string, + checkInterval: number = 3000 +): Promise { return new Promise((res) => { const confirmation = setInterval(async () => { - const isConfirmed = (await fetchUTxOs(extensionCIP30Instance)()).filter(txOutRef => unTxOutRef(txOutRef).split("#",2)[0] == txHash ).length > 0 - if (isConfirmed ) { + const isConfirmed = + (await fetchUTxOs(extensionCIP30Instance)()).filter( + (txOutRef) => unTxOutRef(txOutRef).split("#", 2)[0] == txHash + ).length > 0; + if (isConfirmed) { clearInterval(confirmation); await new Promise((res) => setTimeout(() => res(1), 1000)); return res(true); @@ -40,62 +65,92 @@ function awaitTx(extensionCIP30Instance : BroswerExtensionCIP30Api,txHash: strin }); } -const signMarloweTx : (extensionCIP30Instance : BroswerExtensionCIP30Api) => (cborHex :MarloweTxCBORHex) => TE.TaskEither = - (extensionCIP30Instance) => (cborHex) => pipe( () => extensionCIP30Instance.signTx (cborHex,true), TE.fromTask) - - -const fetchChangeAddress : (extensionCIP30Instance : BroswerExtensionCIP30Api) => T.Task = - (extensionCIP30Instance) => - pipe( T.Do - , T.bind('changeAddress',() => pipe(() => extensionCIP30Instance.getChangeAddress ())) - , T.map (({changeAddress}) => deserializeAddress(changeAddress)) - ) - -const fetchUsedAddresses : (extensionCIP30Instance : BroswerExtensionCIP30Api) => T.Task = - (extensionCIP30Instance) => - pipe( T.Do - , T.bind('usedAddresses',() => pipe(() => extensionCIP30Instance.getUsedAddresses ())) - , T.map (({usedAddresses}) => pipe( usedAddresses, A.map(deserializeAddress))) - ) - -const fetchCIP30Network : (extensionCIP30Instance : BroswerExtensionCIP30Api) => T.Task = - (extensionCIP30Instance) => - pipe( T.Do - , T.bind('networkId' ,() => pipe(() => extensionCIP30Instance.getNetworkId())) - , T.map (({networkId}) => networkId == 1 ? "Mainnet" : "Testnets") - ) - - -const fetchUTxOs : (extensionCIP30Instance : BroswerExtensionCIP30Api) => T.Task = - (extensionCIP30Instance) => - pipe( T.Do - , T.bind('uxtxos' ,() => pipe(() => extensionCIP30Instance.getUtxos())) - , T.map (({uxtxos}) => uxtxos == undefined ? [] : pipe( uxtxos, A.map(deserializeCollateral))) - ) -const fetchCollaterals : (extensionCIP30Instance : BroswerExtensionCIP30Api) => T.Task = - (extensionCIP30Instance) => - pipe( T.Do - , T.bind('collaterals' ,() => pipe(() => extensionCIP30Instance.experimental.getCollateral())) - , T.map (({collaterals}) => collaterals == undefined ? [] : pipe( collaterals, A.map(deserializeCollateral))) - ) - -const deserializeAddress : (addressHex:string) => AddressBech32 = - (addressHex) => - pipe(C.Address.from_bytes(hex.decode(addressHex),).to_bech32(undefined) - ,addressBech32) - - -const deserializeCollateral : (collateral:string) => TxOutRef - = (collateral) => - pipe( C.TransactionUnspentOutput.from_bytes(hex.decode(collateral)) - , utxo => pipe(utxo.input().to_json(), JSON.parse, x => txOutRef (x.transaction_id + '#' + x.index))) +const signMarloweTx: ( + extensionCIP30Instance: BroswerExtensionCIP30Api +) => ( + cborHex: MarloweTxCBORHex +) => TE.TaskEither = + (extensionCIP30Instance) => (cborHex) => + pipe(() => extensionCIP30Instance.signTx(cborHex, true), TE.fromTask); + +const fetchChangeAddress: ( + extensionCIP30Instance: BroswerExtensionCIP30Api +) => T.Task = (extensionCIP30Instance) => + pipe( + T.Do, + T.bind("changeAddress", () => + pipe(() => extensionCIP30Instance.getChangeAddress()) + ), + T.map(({ changeAddress }) => deserializeAddress(changeAddress)) + ); + +const fetchUsedAddresses: ( + extensionCIP30Instance: BroswerExtensionCIP30Api +) => T.Task = (extensionCIP30Instance) => + pipe( + T.Do, + T.bind("usedAddresses", () => + pipe(() => extensionCIP30Instance.getUsedAddresses()) + ), + T.map(({ usedAddresses }) => pipe(usedAddresses, A.map(deserializeAddress))) + ); + +const fetchCIP30Network: ( + extensionCIP30Instance: BroswerExtensionCIP30Api +) => T.Task = (extensionCIP30Instance) => + pipe( + T.Do, + T.bind("networkId", () => + pipe(() => extensionCIP30Instance.getNetworkId()) + ), + T.map(({ networkId }) => (networkId == 1 ? "Mainnet" : "Testnets")) + ); + +const fetchUTxOs: ( + extensionCIP30Instance: BroswerExtensionCIP30Api +) => T.Task = (extensionCIP30Instance) => + pipe( + T.Do, + T.bind("uxtxos", () => pipe(() => extensionCIP30Instance.getUtxos())), + T.map(({ uxtxos }) => + uxtxos == undefined ? [] : pipe(uxtxos, A.map(deserializeCollateral)) + ) + ); +const fetchCollaterals: ( + extensionCIP30Instance: BroswerExtensionCIP30Api +) => T.Task = (extensionCIP30Instance) => + pipe( + T.Do, + T.bind("collaterals", () => + pipe(() => extensionCIP30Instance.experimental.getCollateral()) + ), + T.map(({ collaterals }) => + collaterals == undefined + ? [] + : pipe(collaterals, A.map(deserializeCollateral)) + ) + ); + +const deserializeAddress: (addressHex: string) => AddressBech32 = ( + addressHex +) => + pipe( + C.Address.from_bytes(hex.decode(addressHex)).to_bech32(undefined), + addressBech32 + ); + +const deserializeCollateral: (collateral: string) => TxOutRef = (collateral) => + pipe(C.TransactionUnspentOutput.from_bytes(hex.decode(collateral)), (utxo) => + pipe(utxo.input().to_json(), JSON.parse, (x) => + txOutRef(x.transaction_id + "#" + x.index) + ) + ); type DataSignature = { - signature: string; - key: string; + signature: string; + key: string; }; - type Cardano = { [key: string]: { name: string; @@ -106,35 +161,37 @@ type Cardano = { }; type BroswerExtensionCIP30Api = { - experimental: ExperimentalFeatures; - getBalance(): Promise; - getChangeAddress(): Promise; - getNetworkId(): Promise; - getRewardAddresses(): Promise; - getUnusedAddresses(): Promise; - getUsedAddresses(): Promise; - getUtxos(): Promise; - signData(address: string, payload: string): Promise; - signTx(tx: string, partialSign: boolean): Promise; - submitTx(tx: string): Promise; - }; + experimental: ExperimentalFeatures; + getBalance(): Promise; + getChangeAddress(): Promise; + getNetworkId(): Promise; + getRewardAddresses(): Promise; + getUnusedAddresses(): Promise; + getUsedAddresses(): Promise; + getUtxos(): Promise; + signData(address: string, payload: string): Promise; + signTx(tx: string, partialSign: boolean): Promise; + submitTx(tx: string): Promise; +}; type ExperimentalFeatures = { - getCollateral(): Promise; - }; - + getCollateral(): Promise; +}; -const fetchTokens : (extensionCIP30Instance : BroswerExtensionCIP30Api) => TE.TaskEither - = (extensionCIP30Instance) => - pipe - ( () => extensionCIP30Instance.getBalance() - , T.map((balances) => pipe(balances,deserializeValue,valueToTokens)) - , TE.fromTask) +const fetchTokens: ( + extensionCIP30Instance: BroswerExtensionCIP30Api +) => TE.TaskEither = (extensionCIP30Instance) => + pipe( + () => extensionCIP30Instance.getBalance(), + T.map((balances) => pipe(balances, deserializeValue, valueToTokens)), + TE.fromTask + ); -const deserializeValue = (value: string) => C.Value.from_bytes(hex.decode(value)); +const deserializeValue = (value: string) => + C.Value.from_bytes(hex.decode(value)); const valueToTokens = (value: Core.Value) => { - const tokenValues: Token[] = [ lovelaces(valueToLovelaces(value))] + const tokenValues: Token[] = [lovelaces(valueToLovelaces(value))]; const multiAsset = value.multiasset(); if (multiAsset !== undefined) { @@ -146,14 +203,15 @@ const valueToTokens = (value: Core.Value) => { const policyAssetNames = policyAssets.keys(); for (let j = 0; j < policyAssetNames.len(); j += 1) { const assetName = policyAssetNames.get(j); - const quantity = policyAssets.get(assetName) ?? C.BigNum.from_str('0'); + const quantity = + policyAssets.get(assetName) ?? C.BigNum.from_str("0"); tokenValues.push( - token - (BigInt(quantity.to_str()).valueOf()) - (assetId - (mkPolicyId(policyId.to_hex())) - (utf8.decode(assetName.to_bytes()).substring(1) // N.H : investigate why 1 aditional character is returned - ))); + token(BigInt(quantity.to_str()).valueOf())( + assetId(mkPolicyId(policyId.to_hex()))( + utf8.decode(assetName.to_bytes()).substring(1) // N.H : investigate why 1 aditional character is returned + ) + ) + ); } } } @@ -162,13 +220,14 @@ const valueToTokens = (value: Core.Value) => { return tokenValues; }; -const fetchLovelaces : (extensionCIP30Instance : BroswerExtensionCIP30Api) => TE.TaskEither - = (extensionCIP30Instance) => - pipe - ( () => extensionCIP30Instance.getBalance() - , T.map((balances) => pipe(balances,deserializeValue,valueToLovelaces)) - , TE.fromTask) - -const valueToLovelaces = (value: Core.Value) => BigInt(value.coin().to_str()).valueOf() - - \ No newline at end of file +const fetchLovelaces: ( + extensionCIP30Instance: BroswerExtensionCIP30Api +) => TE.TaskEither = (extensionCIP30Instance) => + pipe( + () => extensionCIP30Instance.getBalance(), + T.map((balances) => pipe(balances, deserializeValue, valueToLovelaces)), + TE.fromTask + ); + +const valueToLovelaces = (value: Core.Value) => + BigInt(value.coin().to_str()).valueOf(); diff --git a/packages/wallet/src/nodejs/index.ts b/packages/wallet/src/nodejs/index.ts index 91218483..3d397f33 100644 --- a/packages/wallet/src/nodejs/index.ts +++ b/packages/wallet/src/nodejs/index.ts @@ -1,210 +1,307 @@ -import * as API from '@blockfrost/blockfrost-js' -import { Blockfrost, Lucid, C, Network, PrivateKey, PolicyId, getAddressDetails, toUnit, fromText, NativeScript, Tx , TxSigned, TxComplete, Script, fromHex, toHex, Core, fromUnit, Unit } from 'lucid-cardano'; -import * as A from 'fp-ts/lib/Array.js'; -import { pipe } from 'fp-ts/lib/function.js'; -import * as O from 'fp-ts/lib/Option.js' -import * as TE from 'fp-ts/lib/TaskEither.js' -import * as T from 'fp-ts/lib/Task.js' - -import { AddressBech32, TxOutRef, addressBech32, unAddressBech32, MarloweTxCBORHex, HexTransactionWitnessSet, Token, lovelaces, token, assetId, mkPolicyId, unPolicyId, AssetId } from '@marlowe.io/runtime-core'; -import { WalletAPI, CIP30Network } from '../api.js'; -import * as Codec from '@47ng/codec' - -const log = (message:string) => console.log(`\t## - ${message}`); +import * as API from "@blockfrost/blockfrost-js"; +import { + Blockfrost, + Lucid, + C, + Network, + PrivateKey, + PolicyId, + getAddressDetails, + toUnit, + fromText, + NativeScript, + Tx, + TxSigned, + TxComplete, + Script, + fromHex, + toHex, + Core, + fromUnit, + Unit, +} from "lucid-cardano"; +import * as A from "fp-ts/lib/Array.js"; +import { pipe } from "fp-ts/lib/function.js"; +import * as O from "fp-ts/lib/Option.js"; +import * as TE from "fp-ts/lib/TaskEither.js"; +import * as T from "fp-ts/lib/Task.js"; + +import { + AddressBech32, + TxOutRef, + addressBech32, + unAddressBech32, + MarloweTxCBORHex, + HexTransactionWitnessSet, + Token, + lovelaces, + token, + assetId, + mkPolicyId, + unPolicyId, + AssetId, +} from "@marlowe.io/runtime-core"; +import { WalletAPI, CIP30Network } from "../api.js"; +import * as Codec from "@47ng/codec"; + +const log = (message: string) => console.log(`\t## - ${message}`); export const foo = 42; -export type PrivateKeysAsHex = string +export type PrivateKeysAsHex = string; export type Address = string; export class Context { - projectId:string; - network:Network; - blockfrostUrl:string - - public constructor (projectId:string, blockfrostUrl:string,network:Network, ) { - this.projectId = projectId; - this.network = network; - this.blockfrostUrl = blockfrostUrl; - } + projectId: string; + network: Network; + blockfrostUrl: string; + + public constructor( + projectId: string, + blockfrostUrl: string, + network: Network + ) { + this.projectId = projectId; + this.network = network; + this.blockfrostUrl = blockfrostUrl; + } } -export const getPrivateKeyFromHexString = (privateKeyHex:string) : PrivateKey => C.PrivateKey.from_bytes(Buffer.from(privateKeyHex, 'hex')).to_bech32() +export const getPrivateKeyFromHexString = (privateKeyHex: string): PrivateKey => + C.PrivateKey.from_bytes(Buffer.from(privateKeyHex, "hex")).to_bech32(); export class SingleAddressWallet implements WalletAPI { - private privateKeyBech32: string; - private context:Context; - private lucid : Lucid; - private blockfrostApi: API.BlockFrostAPI; - - public address : AddressBech32; - getChangeAddress : T.Task - getUsedAddresses : T.Task - getCollaterals : T.Task - - private constructor (context:Context,privateKeyBech32:PrivateKey) { - this.privateKeyBech32 = privateKeyBech32; - this.context = context; - this.blockfrostApi = new API.BlockFrostAPI({projectId: context.projectId}); - } - - public static Initialise ( context:Context, privateKeyBech32: string) : T.Task { - const account = new SingleAddressWallet(context,privateKeyBech32); - return (() => account.initialise().then(() => account)); - } - - public static Random ( context:Context) : T.Task { - const privateKey = C.PrivateKey.generate_ed25519().to_bech32(); - const account = new SingleAddressWallet(context,privateKey); - return (() => account.initialise().then(() => account)); - } - - private async initialise () { - this.lucid = await Lucid.new(new Blockfrost(this.context.blockfrostUrl, this.context.projectId),this.context.network); - this.lucid.selectWalletFromPrivateKey(this.privateKeyBech32); - this.address = addressBech32(await this.lucid.wallet.address ()); - this.getChangeAddress = T.of (this.address) - this.getUsedAddresses = T.of ([this.address]) - this.getCollaterals = T.of ([]) - } - - public getCIP30Network : T.Task - = () => - { if (this.lucid.network === "Mainnet") { return Promise.resolve("Mainnet")} - else {return Promise.resolve("Testnets")}} - - public getTokens: TE.TaskEither - = pipe( TE.tryCatch( - () => this.blockfrostApi.addresses(unAddressBech32(this.address)), - (reason) => new Error(`Error while retrieving assetBalance : ${reason}`)) - , TE.map( (content) => pipe(content.amount??[] - , A.map((tokenBlockfrost) => tokenBlockfrost.unit === "lovelace" ? - lovelaces(BigInt(tokenBlockfrost.quantity)) - : token - (BigInt(tokenBlockfrost.quantity).valueOf()) - (assetId - (mkPolicyId(fromUnit(tokenBlockfrost.unit).policyId)) - (getAssetName(tokenBlockfrost.unit))) )))) - - - public getLovelaces : TE.TaskEither - = pipe( TE.tryCatch( - () => this.blockfrostApi.addresses(unAddressBech32(this.address)), - (reason) => new Error(`Error while retrieving assetBalance : ${reason}`)) - , TE.map( (content) => pipe(content.amount??[] - , A.filter((amount) => amount.unit === "lovelace") - , A.map((amount) => BigInt(amount.quantity)) - , A.head - , O.getOrElse(() => 0n)))) - - - public tokenBalance : (assetId : AssetId) => TE.TaskEither - = (assetId) => - pipe(TE.tryCatch( - () => this.blockfrostApi.addresses(unAddressBech32(this.address)), - (reason) => new Error(`Error while retrieving assetBalance : ${reason}`)) - , TE.map( (content) => pipe(content.amount??[] - , A.filter((amount) => amount.unit === toUnit(unPolicyId(assetId.policyId), fromText(assetId.assetName))) - , A.map((amount) => BigInt(amount.quantity)) - , A.head - , O.getOrElse(() => 0n)))) - - - public provision : (provisionning: [SingleAddressWallet,bigint][]) => TE.TaskEither = (provisionning) => - pipe ( provisionning - , A.reduce ( this.lucid.newTx() - , (tx:Tx, account: [SingleAddressWallet,bigint]) => tx.payToAddress(unAddressBech32(account[0].address), { lovelace:account[1]})) - , build - , TE.chain(this.signSubmitAndWaitConfirmation)) - - public randomPolicyId() : [Script,PolicyId] { - const { paymentCredential } = getAddressDetails(unAddressBech32(this.address)); - const before = this.lucid.currentSlot() + (5 * 60) - const json : NativeScript = { - type: "all", - scripts: [ - { - type: "before", - slot: before.valueOf(), - }, - { type: "sig", keyHash: paymentCredential?.hash! } - ], - }; - const script = this.lucid.utils.nativeScriptFromJson(json); - const policyId = this.lucid.utils.mintingPolicyToId(script); - return [script,policyId]; + private privateKeyBech32: string; + private context: Context; + private lucid: Lucid; + private blockfrostApi: API.BlockFrostAPI; + + public address: AddressBech32; + getChangeAddress: T.Task; + getUsedAddresses: T.Task; + getCollaterals: T.Task; + + private constructor(context: Context, privateKeyBech32: PrivateKey) { + this.privateKeyBech32 = privateKeyBech32; + this.context = context; + this.blockfrostApi = new API.BlockFrostAPI({ + projectId: context.projectId, + }); + } + + public static Initialise( + context: Context, + privateKeyBech32: string + ): T.Task { + const account = new SingleAddressWallet(context, privateKeyBech32); + return () => account.initialise().then(() => account); + } + + public static Random(context: Context): T.Task { + const privateKey = C.PrivateKey.generate_ed25519().to_bech32(); + const account = new SingleAddressWallet(context, privateKey); + return () => account.initialise().then(() => account); + } + + private async initialise() { + this.lucid = await Lucid.new( + new Blockfrost(this.context.blockfrostUrl, this.context.projectId), + this.context.network + ); + this.lucid.selectWalletFromPrivateKey(this.privateKeyBech32); + this.address = addressBech32(await this.lucid.wallet.address()); + this.getChangeAddress = T.of(this.address); + this.getUsedAddresses = T.of([this.address]); + this.getCollaterals = T.of([]); + } + + public getCIP30Network: T.Task = () => { + if (this.lucid.network === "Mainnet") { + return Promise.resolve("Mainnet"); + } else { + return Promise.resolve("Testnets"); } - - public mintRandomTokens(assetName:string, amount: bigint) : TE.TaskEither { - const policyRefs = this.randomPolicyId (); - const [mintingPolicy,policyId] = policyRefs - return pipe( this.lucid.newTx() - .mintAssets({[toUnit(policyId, fromText(assetName))]: amount.valueOf()}) - .validTo(Date.now() + 100000) - .attachMintingPolicy(mintingPolicy) - , build - , TE.chain(this.signSubmitAndWaitConfirmation) - , TE.map(() => - ( token - (amount) - (assetId - (mkPolicyId(policyRefs[1])) - (assetName))) - )) - } - - - - public signTxTheCIP30Way : (cborHex :MarloweTxCBORHex) => TE.TaskEither - = (cborHex) => - pipe ( this.fromTxCBOR(cborHex) - , this.signTx - , TE.map((txSigned) => toHex(txSigned.to_bytes()))) - - private fromTxCBOR (cbor : string) : Core.Transaction { - return C.Transaction.from_bytes(fromHex(cbor)) - } - private signTx : (tx : Core.Transaction) => TE.TaskEither - = (tx) => - TE.tryCatch( - () => this.lucid.wallet.signTx(tx), - (reason) => new Error(`Error while signing : ${reason}`)); - - public sign : (txBuilt : TxComplete ) => TE.TaskEither - = (txBuilt) => - TE.tryCatch( - () => txBuilt.sign().complete(), - (reason) => new Error(`Error while signing : ${reason}`)); - - - public submit : (signedTx : TxSigned ) => TE.TaskEither - = (signedTx) => - TE.tryCatch( - () => signedTx.submit(), - (reason) => new Error(`Error while submitting : ${reason}`)); - - public waitConfirmation : (txHash : string ) => TE.TaskEither - = (txHash) => - TE.tryCatch( - () => this.lucid.awaitTx(txHash), - (reason) => new Error(`Error while submitting : ${reason}`)); - - public signSubmitAndWaitConfirmation : (txBuilt : TxComplete) => TE.TaskEither - = (txBuilt) => - pipe(this.sign(txBuilt) - ,TE.chain(this.submit) - ,TE.chainFirst((txHash) => TE.of(log(`<> Tx ${txHash} submitted.`))) - ,TE.chain(this.waitConfirmation)) - - public getUTxOs: T.Task = T.of([]) + }; + + public getTokens: TE.TaskEither = pipe( + TE.tryCatch( + () => this.blockfrostApi.addresses(unAddressBech32(this.address)), + (reason) => new Error(`Error while retrieving assetBalance : ${reason}`) + ), + TE.map((content) => + pipe( + content.amount ?? [], + A.map((tokenBlockfrost) => + tokenBlockfrost.unit === "lovelace" + ? lovelaces(BigInt(tokenBlockfrost.quantity)) + : token(BigInt(tokenBlockfrost.quantity).valueOf())( + assetId(mkPolicyId(fromUnit(tokenBlockfrost.unit).policyId))( + getAssetName(tokenBlockfrost.unit) + ) + ) + ) + ) + ) + ); + + public getLovelaces: TE.TaskEither = pipe( + TE.tryCatch( + () => this.blockfrostApi.addresses(unAddressBech32(this.address)), + (reason) => new Error(`Error while retrieving assetBalance : ${reason}`) + ), + TE.map((content) => + pipe( + content.amount ?? [], + A.filter((amount) => amount.unit === "lovelace"), + A.map((amount) => BigInt(amount.quantity)), + A.head, + O.getOrElse(() => 0n) + ) + ) + ); + + public tokenBalance: (assetId: AssetId) => TE.TaskEither = ( + assetId + ) => + pipe( + TE.tryCatch( + () => this.blockfrostApi.addresses(unAddressBech32(this.address)), + (reason) => new Error(`Error while retrieving assetBalance : ${reason}`) + ), + TE.map((content) => + pipe( + content.amount ?? [], + A.filter( + (amount) => + amount.unit === + toUnit(unPolicyId(assetId.policyId), fromText(assetId.assetName)) + ), + A.map((amount) => BigInt(amount.quantity)), + A.head, + O.getOrElse(() => 0n) + ) + ) + ); + + public provision: ( + provisionning: [SingleAddressWallet, bigint][] + ) => TE.TaskEither = (provisionning) => + pipe( + provisionning, + A.reduce( + this.lucid.newTx(), + (tx: Tx, account: [SingleAddressWallet, bigint]) => + tx.payToAddress(unAddressBech32(account[0].address), { + lovelace: account[1], + }) + ), + build, + TE.chain(this.signSubmitAndWaitConfirmation) + ); + + public randomPolicyId(): [Script, PolicyId] { + const { paymentCredential } = getAddressDetails( + unAddressBech32(this.address) + ); + const before = this.lucid.currentSlot() + 5 * 60; + const json: NativeScript = { + type: "all", + scripts: [ + { + type: "before", + slot: before.valueOf(), + }, + { type: "sig", keyHash: paymentCredential?.hash! }, + ], + }; + const script = this.lucid.utils.nativeScriptFromJson(json); + const policyId = this.lucid.utils.mintingPolicyToId(script); + return [script, policyId]; + } + + public mintRandomTokens( + assetName: string, + amount: bigint + ): TE.TaskEither { + const policyRefs = this.randomPolicyId(); + const [mintingPolicy, policyId] = policyRefs; + return pipe( + this.lucid + .newTx() + .mintAssets({ + [toUnit(policyId, fromText(assetName))]: amount.valueOf(), + }) + .validTo(Date.now() + 100000) + .attachMintingPolicy(mintingPolicy), + build, + TE.chain(this.signSubmitAndWaitConfirmation), + TE.map(() => token(amount)(assetId(mkPolicyId(policyRefs[1]))(assetName))) + ); + } + + public signTxTheCIP30Way: ( + cborHex: MarloweTxCBORHex + ) => TE.TaskEither = (cborHex) => + pipe( + this.fromTxCBOR(cborHex), + this.signTx, + TE.map((txSigned) => toHex(txSigned.to_bytes())) + ); + + private fromTxCBOR(cbor: string): Core.Transaction { + return C.Transaction.from_bytes(fromHex(cbor)); + } + private signTx: ( + tx: Core.Transaction + ) => TE.TaskEither = (tx) => + TE.tryCatch( + () => this.lucid.wallet.signTx(tx), + (reason) => new Error(`Error while signing : ${reason}`) + ); + + public sign: (txBuilt: TxComplete) => TE.TaskEither = ( + txBuilt + ) => + TE.tryCatch( + () => txBuilt.sign().complete(), + (reason) => new Error(`Error while signing : ${reason}`) + ); + + public submit: (signedTx: TxSigned) => TE.TaskEither = ( + signedTx + ) => + TE.tryCatch( + () => signedTx.submit(), + (reason) => new Error(`Error while submitting : ${reason}`) + ); + + public waitConfirmation: (txHash: string) => TE.TaskEither = ( + txHash + ) => + TE.tryCatch( + () => this.lucid.awaitTx(txHash), + (reason) => new Error(`Error while submitting : ${reason}`) + ); + + public signSubmitAndWaitConfirmation: ( + txBuilt: TxComplete + ) => TE.TaskEither = (txBuilt) => + pipe( + this.sign(txBuilt), + TE.chain(this.submit), + TE.chainFirst((txHash) => TE.of(log(`<> Tx ${txHash} submitted.`))), + TE.chain(this.waitConfirmation) + ); + + public getUTxOs: T.Task = T.of([]); } -const build : (tx : Tx ) => TE.TaskEither - = (tx) => TE.tryCatch( - () => tx.complete(), - (reason) => new Error(`Error while building Tx : ${reason}`)); - +const build: (tx: Tx) => TE.TaskEither = (tx) => + TE.tryCatch( + () => tx.complete(), + (reason) => new Error(`Error while building Tx : ${reason}`) + ); -const getAssetName : (unit : Unit) => string = (unit) => { - const assetName = fromUnit(unit).assetName - return assetName ? Codec.hexToUTF8(assetName) : '' -} \ No newline at end of file +const getAssetName: (unit: Unit) => string = (unit) => { + const assetName = fromUnit(unit).assetName; + return assetName ? Codec.hexToUTF8(assetName) : ""; +}; diff --git a/packages/wallet/src/tsconfig.json b/packages/wallet/src/tsconfig.json index 970a56b9..cf5ea0e1 100644 --- a/packages/wallet/src/tsconfig.json +++ b/packages/wallet/src/tsconfig.json @@ -9,6 +9,6 @@ }, "references": [ { "path": "../../runtime/core/src" }, - { "path": "../../language/core/v1/src" }, + { "path": "../../language/core/v1/src" } ] } diff --git a/pocs/AvailableInterfaces.html b/pocs/AvailableInterfaces.html index 0fa6a350..cbbae23e 100644 --- a/pocs/AvailableInterfaces.html +++ b/pocs/AvailableInterfaces.html @@ -1,16 +1,15 @@ - - - - Load Modules example - - - - - - \ No newline at end of file + + + + Load Modules example + + + + + diff --git a/pocs/Readme.md b/pocs/Readme.md index 95d9c7dd..f31a6721 100644 --- a/pocs/Readme.md +++ b/pocs/Readme.md @@ -2,19 +2,21 @@ These pocs demonstrate how to run the different librairies within a simple html page (low-code platform alike environment ). - -## How to run - +## How to run ### Using Chrome on Linux #### Prerequisites - - Cardano Extension (Nami or Eternl) installed on Chrome - - A Wallet imported in the Cardano Extension installed + +- Cardano Extension (Nami or Eternl) installed on Chrome +- A Wallet imported in the Cardano Extension installed #### Flow + - at the root of the project : + ```bash npx http-server --port 1337 -c-1 -o ./ ``` -- Click on one of the availble pocs in the dedicated `pocs` folder \ No newline at end of file + +- Click on one of the availble pocs in the dedicated `pocs` folder diff --git a/pocs/runtimeCIP30Flow.html b/pocs/runtimeCIP30Flow.html index 1ed11664..d6be4694 100644 --- a/pocs/runtimeCIP30Flow.html +++ b/pocs/runtimeCIP30Flow.html @@ -1,63 +1,76 @@ - - - - withdraw POC - - -
+ + + + withdraw POC + + +
- - - - \ No newline at end of file + + + diff --git a/tsconfig-base.json b/tsconfig-base.json index 73dd8ae3..f0504121 100644 --- a/tsconfig-base.json +++ b/tsconfig-base.json @@ -1,26 +1,26 @@ { - "compilerOptions": { - "allowJs": true, - "allowSyntheticDefaultImports": true, - "declaration": true, - "esModuleInterop": true, - "inlineSourceMap": false, - "lib": ["es2020","dom"], - "target": "ES2020", - "module": "ES2020", - "listEmittedFiles": false, - "listFiles": false, - "moduleResolution": "Node16", - "noFallthroughCasesInSwitch": true, - "pretty": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "strict": true, - "traceResolution": false, - "strictPropertyInitialization":false, - "types": ["node"], - "composite": true - }, - "compileOnSave": false, - "exclude": ["node_modules", "dist"] + "compilerOptions": { + "allowJs": true, + "allowSyntheticDefaultImports": true, + "declaration": true, + "esModuleInterop": true, + "inlineSourceMap": false, + "lib": ["es2020", "dom"], + "target": "ES2020", + "module": "ES2020", + "listEmittedFiles": false, + "listFiles": false, + "moduleResolution": "Node16", + "noFallthroughCasesInSwitch": true, + "pretty": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "traceResolution": false, + "strictPropertyInitialization": false, + "types": ["node"], + "composite": true + }, + "compileOnSave": false, + "exclude": ["node_modules", "dist"] } diff --git a/tsconfig.json b/tsconfig.json index d7e55ccf..b72d120b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,4 +9,4 @@ { "path": "./packages/runtime/lifecycle/src" }, { "path": "./packages/token-metadata-client/src" } ] -} \ No newline at end of file +}