diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b4fa0358f934..09391da69d5b 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -146,7 +146,7 @@ jobs: run: | (set -e; for I in linera-*; do echo $I; cargo rdme --check --no-fail-on-warnings -w $I; done) cd examples - (set -e; for I in fungible social crowd-funding; do echo $I; cargo rdme --check --no-fail-on-warnings -w $I; done) + (set -e; for I in fungible social crowd-funding amm counter meta-counter matching-engine; do echo $I; cargo rdme --check --no-fail-on-warnings -w $I; done) - name: Run Wasm application lints run: | cd examples diff --git a/examples/amm/README.md b/examples/amm/README.md index 07ca52d160af..c557084fb208 100644 --- a/examples/amm/README.md +++ b/examples/amm/README.md @@ -2,28 +2,28 @@ # Automated Market Maker (AMM) Example Application -This example implements an Automated Market Maker (AMM) which demonstrates DeFi capabilities of the +This example implements an Automated Market Maker (AMM) which demonstrates DeFi capabilities of the Linera protocol. Prerequisite for the AMM application is the `fungible` application, as we will be adding/removing liquidity and also performing a swap. -# How it works +# How it works It supports the following operations. -- Swap: For a given input token and an input amount, it swaps that token amount for an -amount of the other token calculated based on the current AMM ratio. Note: The `Swap` operations +- Swap: For a given input token and an input amount, it swaps that token amount for an +amount of the other token calculated based on the current AMM ratio. Note: The `Swap` operations need to be performed from a remote chain. -- Add Liquidity: This operation allows adding liquidity to the AMM. Given a maximum -`token0` and `token1` amount that you're willing to add, it adds liquidity such that you'll be -adding at most `max_token0_amount` of `token0` and `max_token1_amount` of `token1`. The amounts -will be calculated based on the current AMM ratio. The owner, in this case, refers to the user +- Add Liquidity: This operation allows adding liquidity to the AMM. Given a maximum +`token0` and `token1` amount that you're willing to add, it adds liquidity such that you'll be +adding at most `max_token0_amount` of `token0` and `max_token1_amount` of `token1`. The amounts +will be calculated based on the current AMM ratio. The owner, in this case, refers to the user adding liquidity, which currently can only be a chain owner. -- Remove Liquidity: This withdraws tokens from the AMM. Given the index of the token you'd -like to remove (can be 0 or 1), and an amount of that token that you'd like to remove, it calculates -how much of the other token will also be removed based on the current AMM ratio. Then it removes -the amounts from both tokens as a removal of liquidity. The owner, in this context, is the user +- Remove Liquidity: This withdraws tokens from the AMM. Given the index of the token you'd +like to remove (can be 0 or 1), and an amount of that token that you'd like to remove, it calculates +how much of the other token will also be removed based on the current AMM ratio. Then it removes +the amounts from both tokens as a removal of liquidity. The owner, in this context, is the user removing liquidity, which currently can only be a chain owner. # Usage @@ -115,7 +115,7 @@ mutation{ ``` We can only perform `Swap` from a remote chain i.e. other than the chain on which `AMM` is deployed to, -we can do it from GraphiQL by perfoming the `requestApplication` mutation so that we can perform the +we can do it from GraphiQL by perfoming the `requestApplication` mutation so that we can perform the `Swap` operation from the chain. ```json diff --git a/examples/amm/src/lib.rs b/examples/amm/src/lib.rs index 30a493500346..cdf1ff80185d 100644 --- a/examples/amm/src/lib.rs +++ b/examples/amm/src/lib.rs @@ -1,6 +1,171 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +/*! +# Automated Market Maker (AMM) Example Application + +This example implements an Automated Market Maker (AMM) which demonstrates DeFi capabilities of the +Linera protocol. Prerequisite for the AMM application is the `fungible` application, as we will +be adding/removing liquidity and also performing a swap. + +# How it works + +It supports the following operations. + +- Swap: For a given input token and an input amount, it swaps that token amount for an +amount of the other token calculated based on the current AMM ratio. Note: The `Swap` operations +need to be performed from a remote chain. + +- Add Liquidity: This operation allows adding liquidity to the AMM. Given a maximum +`token0` and `token1` amount that you're willing to add, it adds liquidity such that you'll be +adding at most `max_token0_amount` of `token0` and `max_token1_amount` of `token1`. The amounts +will be calculated based on the current AMM ratio. The owner, in this case, refers to the user +adding liquidity, which currently can only be a chain owner. + +- Remove Liquidity: This withdraws tokens from the AMM. Given the index of the token you'd +like to remove (can be 0 or 1), and an amount of that token that you'd like to remove, it calculates +how much of the other token will also be removed based on the current AMM ratio. Then it removes +the amounts from both tokens as a removal of liquidity. The owner, in this context, is the user +removing liquidity, which currently can only be a chain owner. + +# Usage + +## Setting Up + +Before getting started, make sure that the binary tools `linera*` corresponding to +your version of `linera-sdk` are in your PATH. For scripting purposes, we also assume +that the BASH function `linera_spawn_and_read_wallet_variables` is defined. + +From the root of Linera repository, this can be achieved as follows: + +```bash +export PATH="$PWD/target/debug:$PATH" +source /dev/stdin <<<"$(linera net helper 2>/dev/null)" +``` + +To start the local Linera network: + +```bash +linera_spawn_and_read_wallet_variables linera net up --testing-prng-seed 37 +``` + +We use the test-only CLI option `--testing-prng-seed` to make keys deterministic and simplify our +explanation. + +```bash +OWNER_1=e814a7bdae091daf4a110ef5340396998e538c47c6e7d101027a225523985316 +OWNER_2=453690095cdfe6dbde7fc577e56bb838a7ee7920a72512d4a87748b4e151ed61 +CHAIN_1=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 +CHAIN_2=e54bdb17d41d5dbe16418f96b70e44546ccd63e6f3733ae3c192043548998ff3 +``` + +Now we have to publish and create the fungible applications. The flag `--wait-for-outgoing-messages` waits until a quorum of validators has confirmed that all sent cross-chain messages have been delivered. + +```bash +(cd examples/fungible && cargo build --release) + +FUN1_APP_ID=$(linera --wait-for-outgoing-messages \ + publish-and-create examples/target/wasm32-unknown-unknown/release/fungible_{contract,service}.wasm \ + --json-argument "{ \"accounts\": { + \"User:$OWNER_1\": \"100.\", + \"User:$OWNER_2\": \"150.\" + } }" \ + --json-parameters "{ \"ticker_symbol\": \"FUN1\" }" \ +) + +FUN2_APP_ID=$(linera --wait-for-outgoing-messages \ + publish-and-create examples/target/wasm32-unknown-unknown/release/fungible_{contract,service}.wasm \ + --json-argument "{ \"accounts\": { + \"User:$OWNER_1\": \"100.\", + \"User:$OWNER_2\": \"150.\" + } }" \ + --json-parameters "{ \"ticker_symbol\": \"FUN2\" }" \ +) + +(cd examples/amm && cargo build --release) +AMM_APPLICATION_ID=$(linera --wait-for-outgoing-messages publish-and-create examples/target/wasm32-unknown-unknown/release/amm_{contract,service}.wasm --json-parameters "{\"tokens\":["\"$FUN1_APP_ID\"","\"$FUN2_APP_ID\""]}") +``` + +## Using the AMM Application + +First, a node service for the current wallet has to be started: + +```bash +PORT=8080 +linera service --port $PORT & +``` + +### Using GraphiQL + +Before performing any operation we need to provide liquidity to it, so we will use the `AddLiquidity` operation, +navigate to `http://localhost:8080/chains/$CHAIN_1/applications/$AMM_APPLICATION_ID`. + +To perform `AddLiquidity` operation: + +```json +mutation{ + operation( + operation: { + AddLiquidity: { + owner:"User:e814a7bdae091daf4a110ef5340396998e538c47c6e7d101027a225523985316", + max_token0_amount: "50", + max_token1_amount: "40", + } + } + ) +} +``` + +We can only perform `Swap` from a remote chain i.e. other than the chain on which `AMM` is deployed to, +we can do it from GraphiQL by perfoming the `requestApplication` mutation so that we can perform the +`Swap` operation from the chain. + +```json +mutation { + requestApplication ( + chainId:"e54bdb17d41d5dbe16418f96b70e44546ccd63e6f3733ae3c192043548998ff3", + applicationId: "AMM_APPLICATION_ID", + targetChainId: "e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65" + ) +} +``` +Note: The above mutation has to be performed from `http://localhost:8080`. + +Now to perform `Swap` operation, naviage to `http://localhost:8080/chains/$CHAIN_2/applications/$AMM_APPLICATION_ID` and +perform the following mutation: + +```json +mutation{ + operation( + operation: { + Swap: { + owner:"User:453690095cdfe6dbde7fc577e56bb838a7ee7920a72512d4a87748b4e151ed61", + input_token_idx: 1, + input_amount: "1", + } + } + ) +} +``` + +We can also perform the `RemoveLiquidity` operation, navigate to `http://localhost:8080/chains/$CHAIN_1/applications/$AMM_APPLICATION_ID` and +perform the following mutation: + +```json +mutation{ + operation( + operation: { + RemoveLiquidity: { + owner:"User:453690095cdfe6dbde7fc577e56bb838a7ee7920a72512d4a87748b4e151ed61", + token_to_remove_idx: 1, + token_to_remove_amount: "1", + } + } + ) +} +``` +*/ + use std::convert::Infallible; use async_graphql::{scalar, Request, Response}; diff --git a/examples/counter/README.md b/examples/counter/README.md index dfd7610e9641..47cdd002b7d2 100644 --- a/examples/counter/README.md +++ b/examples/counter/README.md @@ -2,12 +2,12 @@ # Counter Example Application -This example application implements a simple counter contract, it is initialized with an +This example application implements a simple counter contract, it is initialized with an unsigned integer that can be increased by the `increment` operation. # How It Works -It is a very basic Linera application, which is initialized by a `u64` which can be incremented +It is a very basic Linera application, which is initialized by a `u64` which can be incremented by a `u64`. For example if the contract was initialized with 1, querying the contract would give us 1. Now if we want to diff --git a/examples/counter/src/lib.rs b/examples/counter/src/lib.rs index ce2619b1746e..c61c240302b7 100644 --- a/examples/counter/src/lib.rs +++ b/examples/counter/src/lib.rs @@ -1,6 +1,115 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +/*! +# Counter Example Application + +This example application implements a simple counter contract, it is initialized with an +unsigned integer that can be increased by the `increment` operation. + +# How It Works + +It is a very basic Linera application, which is initialized by a `u64` which can be incremented +by a `u64`. + +For example if the contract was initialized with 1, querying the contract would give us 1. Now if we want to +`increment` it by 3, we will have to perform an operation with the parameter being 3. Now querying the +application would give us 4 (1+3 = 4). + +# Usage + +## Setting Up + +Before getting started, make sure that the binary tools `linera*` corresponding to +your version of `linera-sdk` are in your PATH. For scripting purposes, we also assume +that the BASH function `linera_spawn_and_read_wallet_variables` is defined. + +From the root of Linera repository, this can be achieved as follows: + +```bash +export PATH="$PWD/target/debug:$PATH" +source /dev/stdin <<<"$(linera net helper 2>/dev/null)" +``` + +To start the local Linera network: + +```bash +linera_spawn_and_read_wallet_variables linera net up --testing-prng-seed 37 +``` + +We use the test-only CLI option `--testing-prng-seed` to make keys deterministic and simplify our +explanation. + +```bash +CHAIN_1=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 +OWNER_1=e814a7bdae091daf4a110ef5340396998e538c47c6e7d101027a225523985316 +``` + +Now, compile the `counter` application WebAssembly binaries, publish and create an application instance. + +```bash +(cd examples/counter && cargo build --release) + +APPLICATION_ID=$(linera publish-and-create \ + examples/target/wasm32-unknown-unknown/release/counter_{contract,service}.wasm \ + --json-argument "1") +``` + +We have saved the `APPLICATION_ID` as it will be useful later. + +## Using the Counter Application + +First, a node service for the current wallet has to be started: + +```bash +PORT=8080 +linera service --port $PORT & +``` + +### Using GraphiQL + +- Navigate to `http://localhost:8080/chains/$CHAIN_1/applications/$APPLICATION_ID`. +- To get the current value of `counter`, run the query: +```json + query{ + value + } +``` +- To increase the value of the counter by 3, perform the `increment` operation. +```json + mutation Increment{ + increment(value: 3) + } +``` +- Running the query again would yield `4`. + + +### Using web frontend + +Installing and starting the web server: + +```bash +cd examples/counter/web-frontend +npm install + +# Start the server but not open the web page right away. +BROWSER=none npm start & +``` + +Web UIs for specific accounts can be opened by navigating URLs of the form +`http://localhost:3000/$CHAIN_1?app=$APPLICATION_ID&owner=$OWNER_1&port=$PORT` where +- the path is the ID of the chain where the account is located. +- the `app` argument is the token application ID obtained when creating the token. +- `owner` is the address of the chosen user account (owner must be have permissions to create blocks in the given chain). +- `port` is the port of the wallet service (the wallet must know the secret key of `owner`). + +The following command will print the URL of the web UI: + +```bash +echo "http://localhost:3000/$CHAIN_1?app=$APPLICATION_ID&owner=$OWNER_1&port=$PORT" +``` +*/ + use async_graphql::{Request, Response}; use linera_sdk::base::{ContractAbi, ServiceAbi}; diff --git a/examples/matching-engine/README.md b/examples/matching-engine/README.md index 7d7a46f69ded..cf18392ae562 100644 --- a/examples/matching-engine/README.md +++ b/examples/matching-engine/README.md @@ -124,10 +124,10 @@ mutation ExecuteOrder { amount: "1", nature: Bid, price: { - price:5 + price:5 } } - } + } ) } ``` diff --git a/examples/matching-engine/src/lib.rs b/examples/matching-engine/src/lib.rs index eb21273b48bf..e7595d6aee04 100644 --- a/examples/matching-engine/src/lib.rs +++ b/examples/matching-engine/src/lib.rs @@ -1,6 +1,152 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +/*! +# Matching Engine Example Application + +This sample application demonstrates a matching engine, showcasing the DeFi capabilities +on the Linera protocol. + +The matching engine trades between two tokens `token_0` & `token_1`. We can refer to +the `fungible` application example on how to create two token applications. + +An order can be of two types: + +- Bid: For buying token 1 and paying in token 0, these are ordered in from the highest + bid (most preferable) to the lowest price. +- Ask: For selling token 1, to be paid in token 0, these are ordered from the lowest + (most preferable) to the highest price. + +An `OrderId` is used to uniquely identify an order and enables the following functionality: + +- Modify: Allows to modify the order. +- Cancel: Cancelling an order. + +When inserting an order it goes through the following steps: + +- Transfer of tokens from the `fungible` application to the `matching engine` application through a cross-application +call so that it can be paid to the counterparty. + +- The engine selects the matching price levels for the inserted order. It then proceeds + to clear these levels, executing trades and ensuring that at the end of the process, + the best bid has a higher price than the best ask. This involves adjusting the orders in the market + and potentially creating a series of transfer orders for the required tokens. If, after + the level clearing, the order is completely filled, it is not inserted. Otherwise, + it becomes a liquidity order in the matching engine, providing depth to the market + and potentially being matched with future orders. + +When an order is created from a remote chain, it transfers the tokens of the same owner +from the remote chain to the chain of the matching engine, and a `ExecuteOrder` message is sent with the order details. + +# Usage + +## Setting Up + +Before getting started, make sure that the binary tools `linera*` corresponding to +your version of `linera-sdk` are in your PATH. For scripting purposes, we also assume +that the BASH function `linera_spawn_and_read_wallet_variables` is defined. + +From the root of Linera repository, this can be achieved as follows: + +```bash +export PATH="$PWD/target/debug:$PATH" +source /dev/stdin <<<"$(linera net helper 2>/dev/null)" +``` + +To start the local Linera network: + +```bash +linera_spawn_and_read_wallet_variables linera net up --testing-prng-seed 37 +``` + +We use the test-only CLI option `--testing-prng-seed` to make keys deterministic and simplify our +explanation. + +```bash +OWNER_1=e814a7bdae091daf4a110ef5340396998e538c47c6e7d101027a225523985316 +OWNER_2=453690095cdfe6dbde7fc577e56bb838a7ee7920a72512d4a87748b4e151ed61 +CHAIN_1=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 +CHAIN_2=e54bdb17d41d5dbe16418f96b70e44546ccd63e6f3733ae3c192043548998ff3 +``` + +Publish and create two `fungible` application whose `application_id` will be used as a +parameter while creating the `matching engine` example. The flag `--wait-for-outgoing-messages` waits until a quorum of validators has confirmed that all sent cross-chain messages have been delivered. + +```bash +(cd examples/fungible && cargo build --release) + +FUN1_APP_ID=$(linera --wait-for-outgoing-messages \ + publish-and-create examples/target/wasm32-unknown-unknown/release/fungible_{contract,service}.wasm \ + --json-argument "{ \"accounts\": { + \"User:$OWNER_1\": \"100.\", + \"User:$OWNER_2\": \"150.\" + } }" \ + --json-parameters "{ \"ticker_symbol\": \"FUN1\" }" \ +) + +FUN2_APP_ID=$(linera --wait-for-outgoing-messages \ + publish-and-create examples/target/wasm32-unknown-unknown/release/fungible_{contract,service}.wasm \ + --json-argument "{ \"accounts\": { + \"User:$OWNER_1\": \"100.\", + \"User:$OWNER_2\": \"150.\" + } }" \ + --json-parameters "{ \"ticker_symbol\": \"FUN2\" }" \ +) + +``` + +Now we have to publish and deploy the Matching Engine application: + +```bash +(cd examples/matching-engine && cargo build --release) +MATCHING_ENGINE=$(linera --wait-for-outgoing-messages publish-and-create examples/target/wasm32-unknown-unknown/release/matching_engine_{contract,service}.wasm --json-parameters "{\"tokens\":["\"$FUN1_APP_ID\"","\"$FUN1_APP_ID\""]}") +``` + +## Using the Matching Engine Application + +First, a node service for the current wallet has to be started: + +```bash +PORT=8080 +linera service --port $PORT & +``` + +### Using GraphiQL + +Navigate to `http://localhost:8080/chains/$CHAIN_1/applications/$MATCHING_ENGINE`. + +To create a `Bid` order nature: + +```json +mutation ExecuteOrder { + executeOrder( + order:{ + Insert : { + owner: "User:e814a7bdae091daf4a110ef5340396998e538c47c6e7d101027a225523985316", + amount: "1", + nature: Bid, + price: { + price:5 + } + } + } + ) +} +``` + +To query about the bid price: + +```json +query{ + bids { + keys{ + price + } + } +} +``` +*/ + use async_graphql::{scalar, InputObject, Request, Response, SimpleObject}; use fungible::{AccountOwner, FungibleTokenAbi}; use linera_sdk::{ diff --git a/examples/meta-counter/README.md b/examples/meta-counter/README.md index dc31352f00f7..590f7b53712c 100644 --- a/examples/meta-counter/README.md +++ b/examples/meta-counter/README.md @@ -2,8 +2,8 @@ # Meta-Counter Example Application -This application demonstrates how `cross_application_call` works in Linera. -Our counter example +This application demonstrates how `cross_application_call` works in Linera. +Our counter example has an `handle_application_call` implemented to handle cross-application calls. To use this application one must publish and create the `counter` application on the local Linera network. @@ -11,7 +11,7 @@ one must publish and create the `counter` application on the local Linera networ It requires the application id of the counter example as a parameter. -To perform the `increment` operation it sends a message along with the value to be added. +To perform the `increment` operation it sends a message along with the value to be added. On receiving the cross-chain message it makes a cross-application call to the counter application whose application id we already provided at the time of creation. @@ -65,7 +65,7 @@ META_COUNTER_ID=$(linera --wait-for-outgoing-messages publish-and-create \ --json-argument="null" --json-parameters '"'"$APPLICATION_ID"'"' --required-application-ids $APPLICATION_ID) ``` -## Using the Counter Application +## Using the Meta Counter Application First, a node service for the current wallet has to be started: @@ -79,13 +79,13 @@ linera service --port $PORT & - Navigate to `http://localhost:8080/chains/$CHAIN_1/applications/$META_COUNTER_ID`. - To get the current value of `counter`, run the query: ```json - query{ + query { value } ``` - To increase the value of the counter by 3, perform the `increment` operation: ```json - mutation Increment{ + mutation Increment { increment(value: 3) } ``` diff --git a/examples/meta-counter/src/lib.rs b/examples/meta-counter/src/lib.rs index 288c6221538f..5a32ea851401 100644 --- a/examples/meta-counter/src/lib.rs +++ b/examples/meta-counter/src/lib.rs @@ -1,6 +1,101 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +/*! +# Meta-Counter Example Application + +This application demonstrates how `cross_application_call` works in Linera. +Our counter example +has an `handle_application_call` implemented to handle cross-application calls. To use this application +one must publish and create the `counter` application on the local Linera network. + +# How It Works + +It requires the application id of the counter example as a parameter. + +To perform the `increment` operation it sends a message along with the value to be added. +On receiving the cross-chain message it makes a cross-application call to the counter application +whose application id we already provided at the time of creation. + +When the counter application recieves a cross-application call it increments the value by the specified +amount. + +# Usage + +## Setting Up + +Before getting started, make sure that the binary tools `linera*` corresponding to +your version of `linera-sdk` are in your PATH. For scripting purposes, we also assume +that the BASH function `linera_spawn_and_read_wallet_variables` is defined. + +From the root of Linera repository, this can be achieved as follows: + +```bash +export PATH="$PWD/target/debug:$PATH" +source /dev/stdin <<<"$(linera net helper 2>/dev/null)" +``` + +To start the local Linera network: + +```bash +linera_spawn_and_read_wallet_variables linera net up --testing-prng-seed 37 +``` + +We use the test-only CLI option `--testing-prng-seed` to make keys deterministic and simplify our +explanation. + +```bash +CHAIN_1=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 +OWNER_1=e814a7bdae091daf4a110ef5340396998e538c47c6e7d101027a225523985316 +``` + +Now, publish and create the `counter` application. The flag `--wait-for-outgoing-messages` waits until a quorum of validators has confirmed that all sent cross-chain messages have been delivered. + +```bash +(cd examples/counter && cargo build --release) + +APPLICATION_ID=$(linera --wait-for-outgoing-messages publish-and-create examples/target/wasm32-unknown-unknown/release/counter_{contract,service}.wasm \ + --json-argument "1") +``` + +Now, compile the `meta-counter` application WebAssembly binaries, publish and create an application instance. + +```bash +(cd examples/meta-counter && cargo build --release) +META_COUNTER_ID=$(linera --wait-for-outgoing-messages publish-and-create \ + examples/target/wasm32-unknown-unknown/release/meta_counter_{contract,service}.wasm \ + --json-argument="null" --json-parameters '"'"$APPLICATION_ID"'"' --required-application-ids $APPLICATION_ID) +``` + +## Using the Meta Counter Application + +First, a node service for the current wallet has to be started: + +```bash +PORT=8080 +linera service --port $PORT & +``` + +### Using GraphiQL + +- Navigate to `http://localhost:8080/chains/$CHAIN_1/applications/$META_COUNTER_ID`. +- To get the current value of `counter`, run the query: +```json + query { + value + } +``` +- To increase the value of the counter by 3, perform the `increment` operation: +```json + mutation Increment { + increment(value: 3) + } +``` +- Running the query again would yield `4`. + +Now, if we check from `counter` application we will also get `4` because eventually we modified the state. +*/ + use async_graphql::{Request, Response}; use linera_sdk::base::{ApplicationId, ChainId, ContractAbi, ServiceAbi};