diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 26e29cff013..47f9e6fa556 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -332,13 +332,6 @@ jobs: - name: Check for outdated README.md run: | (set -e; for I in linera-*; do if [ -d "$I" ]; then echo $I; cargo rdme --check --no-fail-on-warnings -w $I; fi; done) - (set -e; cd examples; for dir in */; do - if [ -f "${dir}README.md" ] && grep -q "" "${dir}README.md"; then - dir_name="${dir%/}" - echo "${dir_name}" - cargo rdme --check --no-fail-on-warnings -w "${dir_name}" - fi - done) lint-wasm-applications: runs-on: ubuntu-latest diff --git a/examples/amm/README.md b/examples/amm/README.md index a939a898e24..dca6ad2926a 100644 --- a/examples/amm/README.md +++ b/examples/amm/README.md @@ -1,12 +1,10 @@ - - # 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 +## How it works It supports the following operations. All operations need to be executed remotely. @@ -25,9 +23,9 @@ It supports the following operations. All operations need to be executed remotel 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 +## Usage -## Setting Up +### 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 @@ -86,7 +84,7 @@ AMM_APPLICATION_ID=$(linera --wait-for-outgoing-messages \ --required-application-ids $FUN1_APP_ID $FUN2_APP_ID) ``` -## Using the AMM Application +### Using the AMM Application First, a node service for the current wallet has to be started: @@ -95,7 +93,7 @@ PORT=8080 linera service --port $PORT & ``` -### Using GraphiQL +#### Using GraphiQL Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. @@ -246,7 +244,7 @@ mutation { } ``` -### Atomic Swaps +#### Atomic Swaps In general, if you send tokens to a chain owned by someone else, you rely on them for asset availability: If they don't handle your messages, you don't have access to @@ -323,5 +321,3 @@ query { } } ``` - - diff --git a/examples/amm/src/lib.rs b/examples/amm/src/lib.rs index 9a155f5e970..7116b0a6745 100644 --- a/examples/amm/src/lib.rs +++ b/examples/amm/src/lib.rs @@ -1,333 +1,7 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -#![allow(rustdoc::invalid_codeblock_attributes)] // Using '=' in the documentation. - -/*! -# 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. All operations need to be executed remotely. - -- 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. - -- 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=d2115775b5b3c5c1ed3c1516319a7e850c75d0786a74b39f5250cf9decc88124 -OWNER_2=a477cb966190661c0dfbe50602616a78a48d2bef6cb5288d49deb3e05585d579 -CHAIN_1=673ce04da4b8ed773ee7cd5828a2083775bea4130498b847c5b34b2ed913b07f -CHAIN_2=69705f85ac4c9fef6c02b4d83426aaaf05154c645ec1c61665f8e450f0468bc0 -CHAIN_AMM=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 -OWNER_AMM=7136460f0c87ae46f966f898d494c4b40c4ae8c527f4d1c0b1fa0f7cff91d20f -``` - -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 --target wasm32-unknown-unknown) - -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_AMM\": \"100.\" - } }" \ - --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_AMM\": \"100.\" - } }" \ - --json-parameters "{ \"ticker_symbol\": \"FUN2\" }" \ -) - -(cd examples/amm && cargo build --release --target wasm32-unknown-unknown) -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\""]}" \ - --required-application-ids $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 - -Type each of these in the GraphiQL interface and substitute the env variables with their actual -values that we've defined above. - -To properly setup the tokens in the proper chains, we need to do some transfer operations: - -- Transfer 50 FUN1 from `$OWNER_AMM` in `$CHAIN_AMM` to `$OWNER_1` in `$CHAIN_1`, so they're in the proper chain. - Run `echo "http://localhost:8080/chains/$CHAIN_AMM/applications/$FUN1_APP_ID"` to print the URL - of the GraphiQL interface for the FUN1 app. Navigate to that URL and enter: - -```gql,uri=http://localhost:8080/chains/$CHAIN_AMM/applications/$FUN1_APP_ID -mutation { - transfer( - owner: "User:$OWNER_AMM", - amount: "50.", - targetAccount: { - chainId: "$CHAIN_1", - owner: "User:$OWNER_1", - } - ) -} -``` - -- Transfer 50 FUN1 from `$OWNER_AMM` in `$CHAIN_AMM` to `$OWNER_2` in `$CHAIN_2`, so they're in the proper chain: - -```gql,uri=http://localhost:8080/chains/$CHAIN_AMM/applications/$FUN1_APP_ID -mutation { - transfer( - owner: "User:$OWNER_AMM", - amount: "50.", - targetAccount: { - chainId: "$CHAIN_2", - owner: "User:$OWNER_2", - } - ) -} -``` - -- Transfer 50 FUN2 from `$OWNER_AMM` in `$CHAIN_AMM` to `$OWNER_1` in `$CHAIN_1`, so they're in the proper chain. - Since this is the other token, FUN2, we need to go to its own GraphiQL interface: - `echo "http://localhost:8080/chains/$CHAIN_AMM/applications/$FUN2_APP_ID"`. - -```gql,uri=http://localhost:8080/chains/$CHAIN_AMM/applications/$FUN2_APP_ID -mutation { - transfer( - owner: "User:$OWNER_AMM", - amount: "50.", - targetAccount: { - chainId: "$CHAIN_1", - owner: "User:$OWNER_1", - } - ) -} -``` - -- Transfer 50 FUN2 from `$OWNER_AMM` in `$CHAIN_AMM` to `$OWNER_2` in `$CHAIN_2`, so they're in the proper chain: - -```gql,uri=http://localhost:8080/chains/$CHAIN_AMM/applications/$FUN2_APP_ID -mutation { - transfer( - owner: "User:$OWNER_AMM", - amount: "50.", - targetAccount: { - chainId: "$CHAIN_2", - owner: "User:$OWNER_2", - } - ) -} -``` - -All operations can only be from a remote chain i.e. other than the chain on which `AMM` is deployed to. -We can do it from GraphiQL by performing the `requestApplication` mutation so that we can perform the -operation from the chain. - -```gql,uri=http://localhost:8080 -mutation { - requestApplication ( - chainId:"$CHAIN_1", - applicationId: "$AMM_APPLICATION_ID", - targetChainId: "$CHAIN_AMM" - ) -} -``` - -Note: The above mutation has to be performed from `http://localhost:8080`. - -Before performing any operation we need to provide liquidity to it, so we will use the `AddLiquidity` operation, -navigate to the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_1/applications/$AMM_APPLICATION_ID"`. - -To perform the `AddLiquidity` operation: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$AMM_APPLICATION_ID -mutation { - addLiquidity( - owner: "User:$OWNER_1", - maxToken0Amount: "50", - maxToken1Amount: "50", - ) -} -``` - -```gql,uri=http://localhost:8080 -mutation { - requestApplication ( - chainId:"$CHAIN_2", - applicationId: "$AMM_APPLICATION_ID", - targetChainId: "$CHAIN_AMM" - ) -} -``` - -Note: The above mutation has to be performed from `http://localhost:8080`. - -To perform the `Swap` operation, navigate to the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_2/applications/$AMM_APPLICATION_ID"` and -perform the following mutation: - -```gql,uri=http://localhost:8080/chains/$CHAIN_2/applications/$AMM_APPLICATION_ID -mutation { - swap( - owner: "User:$OWNER_2", - inputTokenIdx: 1, - inputAmount: "1", - ) -} -``` - -To perform the `RemoveLiquidity` operation, navigate to the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_1/applications/$AMM_APPLICATION_ID"` and -perform the following mutation: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$AMM_APPLICATION_ID -mutation { - removeLiquidity( - owner: "User:$OWNER_1", - tokenToRemoveIdx: 1, - tokenToRemoveAmount: "1", - ) -} -``` - -To perform the `RemoveAllAddedLiquidity` operation, navigate to the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_1/applications/$AMM_APPLICATION_ID"` and -perform the following mutation: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$AMM_APPLICATION_ID -mutation { - removeAllAddedLiquidity( - owner: "User:$OWNER_1", - ) -} -``` - -### Atomic Swaps - -In general, if you send tokens to a chain owned by someone else, you rely on them -for asset availability: If they don't handle your messages, you don't have access to -your tokens. - -Fortunately, Linera provides a solution based on temporary chains: -If the number of parties who want to swap tokens is limited, we can make them all chain -owners, allow only AMM operations on the chain, and allow only the AMM to close the chain. -In addition, we make an AMM operation per block mandatory, so owners cannot spam the chain -with empty blocks. - -```bash -PUB_KEY_AMM=fcf518d56455283ace2bbc11c71e684eb58af81bc98b96a18129e825ce24ea84 -PUB_KEY_2=ca909dcf60df014c166be17eb4a9f6e2f9383314a57510206a54cd841ade455e - -kill %% && sleep 1 # Kill the service so we can use CLI commands for chain 1. - -linera --wait-for-outgoing-messages change-ownership \ - --owner-public-keys $PUB_KEY_AMM $PUB_KEY_2 - -linera --wait-for-outgoing-messages change-application-permissions \ - --execute-operations $AMM_APPLICATION_ID \ - --mandatory-applications $AMM_APPLICATION_ID \ - --close-chain $AMM_APPLICATION_ID - -linera service --port $PORT & -``` - -First, let's add some liquidity again to the AMM. Navigate to the URL you get by running -`echo "http://localhost:8080/chains/$CHAIN_1/applications/$AMM_APPLICATION_ID"` and perform the following mutation: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$AMM_APPLICATION_ID -mutation { - addLiquidity( - owner: "User:$OWNER_1", - maxToken0Amount: "40", - maxToken1Amount: "40", - ) -} -``` - -The only way to close the chain is via the application. Navigate to the URL you get by running -`echo "http://localhost:8080/chains/$CHAIN_AMM/applications/$AMM_APPLICATION_ID"` and perform the following mutation: - -```gql,uri=http://localhost:8080/chains/$CHAIN_AMM/applications/$AMM_APPLICATION_ID -mutation { closeChain } -``` - -Owner 1 should now get back their tokens, and have around 49 FUN1 left and 51 FUN2 left. To check that, navigate -to the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_1/applications/$FUN1_APP_ID"`, and perform the following mutation: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$FUN1_APP_ID -query { - accounts { - entry( - key: "User:$OWNER_1" - ) { - value - } - } -} -``` - -Then navigate to the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_1/applications/$FUN2_APP_ID"`, and perform the following mutation: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$FUN2_APP_ID -query { - accounts { - entry( - key: "User:$OWNER_1" - ) { - value - } - } -} -``` -*/ +/*! The ABI for the Automated Market Maker (AMM) Example Application */ use async_graphql::{scalar, Request, Response}; use linera_sdk::{ diff --git a/examples/counter/README.md b/examples/counter/README.md index cb6f8425273..c63a24f98a7 100644 --- a/examples/counter/README.md +++ b/examples/counter/README.md @@ -1,11 +1,9 @@ - - # 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 +## How It Works It is a very basic Linera application, which is initialized by a `u64` which can be incremented by a `u64`. @@ -14,9 +12,9 @@ For example if the contract was initialized with 1, querying the contract would `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 +## Usage -## Setting Up +### 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 @@ -55,7 +53,7 @@ APPLICATION_ID=$(linera publish-and-create \ We have saved the `APPLICATION_ID` as it will be useful later. -## Using the Counter Application +### Using the Counter Application First, a node service for the current wallet has to be started: @@ -64,7 +62,7 @@ PORT=8080 linera service --port $PORT & ``` -### Using GraphiQL +#### Using GraphiQL Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. @@ -84,7 +82,7 @@ mutation Increment { - Running the query again would yield `4`. -### Using web frontend +#### Using web frontend Installing and starting the web server: @@ -108,5 +106,3 @@ 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" ``` - - diff --git a/examples/counter/src/lib.rs b/examples/counter/src/lib.rs index f4e417f4dd7..4442f671e9e 100644 --- a/examples/counter/src/lib.rs +++ b/examples/counter/src/lib.rs @@ -1,118 +1,7 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -#![allow(rustdoc::invalid_codeblock_attributes)] // Using '=' in the documentation. - -/*! -# 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=7136460f0c87ae46f966f898d494c4b40c4ae8c527f4d1c0b1fa0f7cff91d20f -``` - -Now, compile the `counter` application WebAssembly binaries, publish and create an application instance. - -```bash -(cd examples/counter && cargo build --release --target wasm32-unknown-unknown) - -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 - -Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. - -- Navigate to the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_1/applications/$APPLICATION_ID"`. -- To get the current value of `counter`, run the query: -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APPLICATION_ID -query { - value -} -``` -- To increase the value of the counter by 3, perform the `increment` operation. -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APPLICATION_ID -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 --no-save - -# Start the server but do 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 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" -``` -*/ +/*! ABI of the Counter Example Application */ use async_graphql::{Request, Response}; use linera_sdk::base::{ContractAbi, ServiceAbi}; diff --git a/examples/crowd-funding/README.md b/examples/crowd-funding/README.md index e2f16d24147..414409b197c 100644 --- a/examples/crowd-funding/README.md +++ b/examples/crowd-funding/README.md @@ -1,5 +1,3 @@ - - # Crowd-funding Example Application This example application implements crowd-funding campaigns using fungible tokens in @@ -10,7 +8,7 @@ Once an application is built and its bytecode published on a Linera chain, the published bytecode can be used to create different instances. Each instance or crowd-funding represents a different campaign. -# How It Works +## How It Works The chain that created the campaign is called the "campaign chain". It is owned by the creator (and beneficiary) of the campaign. @@ -20,7 +18,7 @@ their own chain(s). If enough tokens are pledged before the campaign expires, th _successful_ and the creator can receive all the funds, including ones exceeding the funding target. Otherwise, the campaign is _unsuccessful_ and contributors should be refunded. -# Caveat +## Caveat Currently, only the owner of the campaign can create blocks that contain the `Cancel` operation. In the future, campaign chains will not be single-owner chains and should @@ -30,9 +28,15 @@ appropriate (even without the owner's cooperation). Optionally, contributors may also be able to create a block to accept a new epoch (i.e. a change of validators). -# Usage + + +## Usage -## Setting Up +### Setting Up The WebAssembly binaries for the bytecode can be built and published using [steps from the book](https://linera-io.github.io/linera-documentation/getting_started/first_app.html), @@ -98,7 +102,7 @@ default chain of each wallet and call them `$OWNER_0` and `$OWNER_1`. Remember t chain IDs as `$CHAIN_0` (the chain where we just published the application) and `$CHAIN_1` (some user chain in wallet 2). -## Creating tokens +### Creating tokens Compile the Wasm binaries for the two applications `fungible` and `crowd-funding`, publish them as applications, and give them initial states. This initial state is where the tokens @@ -121,7 +125,7 @@ sleep 8 We will remember the application ID for the newly created token as `$APP_ID_0`. -## Creating a crowd-funding campaign +### Creating a crowd-funding campaign Similarly, we're going to create a crowd-funding campaign on the default chain. We have to specify our fungible application as a dependency and a parameter: @@ -139,7 +143,7 @@ APP_ID_1=$(linera --with-wallet 0 \ sleep 5 ``` -## Interacting with the campaign +### Interacting with the campaign First, a node service has to be started for each wallet, using two different ports: @@ -258,5 +262,3 @@ query { accounts { entry(key: "User:$OWNER_0") { value } } } ``` - - diff --git a/examples/crowd-funding/src/lib.rs b/examples/crowd-funding/src/lib.rs index e292488affc..5d74777c20d 100644 --- a/examples/crowd-funding/src/lib.rs +++ b/examples/crowd-funding/src/lib.rs @@ -1,272 +1,7 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -// Using '=' in the documentation. -#![allow(rustdoc::invalid_codeblock_attributes)] -// TODO the following documentation involves `sleep`ing to avoid some race conditions. See: -// - https://github.com/linera-io/linera-protocol/issues/1176 -// - https://github.com/linera-io/linera-protocol/issues/1177 - -/*! -# Crowd-funding Example Application - -This example application implements crowd-funding campaigns using fungible tokens in -the `fungible` application. This demonstrates how to compose applications together and -how to instantiate applications where one chain has a special role. - -Once an application is built and its bytecode published on a Linera chain, the -published bytecode can be used to create different instances. Each instance or crowd-funding -represents a different campaign. - -# How It Works - -The chain that created the campaign is called the "campaign chain". It is owned by the -creator (and beneficiary) of the campaign. - -The goal of a crowd-funding campaign is to let people pledge any number of tokens from -their own chain(s). If enough tokens are pledged before the campaign expires, the campaign is -_successful_ and the creator can receive all the funds, including ones exceeding the funding -target. Otherwise, the campaign is _unsuccessful_ and contributors should be refunded. - -# Caveat - -Currently, only the owner of the campaign can create blocks that contain the `Cancel` -operation. In the future, campaign chains will not be single-owner chains and should -instead allow contributors (users with a pledge) to cancel the campaign if -appropriate (even without the owner's cooperation). - -Optionally, contributors may also be able to create a block to accept a new epoch -(i.e. a change of validators). - -# Usage - -## Setting Up - -The WebAssembly binaries for the bytecode can be built and published using [steps from the -book](https://linera-io.github.io/linera-documentation/getting_started/first_app.html), -summarized below. - -Set up the path and the helper function. - -```bash -export PATH=$PWD/target/debug:$PATH -source /dev/stdin <<<"$(linera net helper 2>/dev/null)" -``` - -Using the helper function defined by `linera net helper`, set up a local network with two -wallets, and define variables holding their wallet paths (`$LINERA_WALLET_0`, -`$LINERA_WALLET_1`) and storage paths (`$LINERA_STORAGE_0`, `$LINERA_STORAGE_1`). These -variables are named according to a convention that we can access using `--with-wallet $n` -to use the variable `LINERA_WALLET_$n` and `LINERA_STORAGE_$n`; e.g. -`linera --with-wallet 0` is equivalent to -`linera --wallet "$LINERA_WALLET_0" --storage "$LINERA_STORAGE_0"`. - -```bash -linera_spawn_and_read_wallet_variables \ - linera net up \ - --extra-wallets 1 \ - --testing-prng-seed 37 -``` - -We use the `--testing-prng-seed` argument to ensure that the chain and owner IDs are -predictable. - -```bash -CHAIN_0=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 -OWNER_0=7136460f0c87ae46f966f898d494c4b40c4ae8c527f4d1c0b1fa0f7cff91d20f -CHAIN_1=1db1936dad0717597a7743a8353c9c0191c14c3a129b258e9743aec2b4f05d03 -OWNER_1=b4f8586041a07323bd4f4ed2d758bf1b9a977eabfd4c00e2f12d08a0899485fd -``` - -Alternatively, the command below can be used to list the chains created for the test as -known by each wallet: - -```bash -linera --with-wallet 0 wallet show -linera --with-wallet 1 wallet show -``` - -A table will be shown with the chains registered in the wallet and their meta-data: - -```text,ignore -╭──────────────────────────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────────────────╮ -│ Chain Id ┆ Latest Block │ -╞══════════════════════════════════════════════════════════════════╪══════════════════════════════════════════════════════════════════════════════════════╡ -│ 1db1936dad0717597a7743a8353c9c0191c14c3a129b258e9743aec2b4f05d03 ┆ Public Key: 84eddaaafce7fb923c3b2494b3d25e54e910490a726ad9b3a2228d3fb18f9874 │ -│ ┆ Owner: b4f8586041a07323bd4f4ed2d758bf1b9a977eabfd4c00e2f12d08a0899485fd │ -│ ┆ Block Hash: - │ -│ ┆ Timestamp: 2023-06-28 09:53:51.167301 │ -│ ┆ Next Block Height: 0 │ -╰──────────────────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────────────────╯ -``` - -The default chain of each wallet should be highlighted in green. Each chain has an -`Owner` field, and that is what is used for the account. Let's pick the owners of the -default chain of each wallet and call them `$OWNER_0` and `$OWNER_1`. Remember the corresponding -chain IDs as `$CHAIN_0` (the chain where we just published the application) and `$CHAIN_1` -(some user chain in wallet 2). - -## Creating tokens - -Compile the Wasm binaries for the two applications `fungible` and `crowd-funding`, publish -them as applications, and give them initial states. This initial state is where the tokens -are minted. After the token is created, no additional tokens can be minted and added to -the application. The initial state is a JSON string that specifies the accounts that start -with tokens. - -Create a fungible token application where two accounts start with the minted tokens, one -with 100 of them and another with 200 of them: - -```bash -APP_ID_0=$(linera --with-wallet 0 project publish-and-create \ - examples/fungible \ - --json-argument '{ "accounts": { "User:'$OWNER_0'": "100", "User:'$OWNER_1'": "200" } }' \ - --json-parameters "{ \"ticker_symbol\": \"FUN\" }") - -# Wait for it to fully complete -sleep 8 -``` - -We will remember the application ID for the newly created token as `$APP_ID_0`. - -## Creating a crowd-funding campaign - -Similarly, we're going to create a crowd-funding campaign on the default chain. We have -to specify our fungible application as a dependency and a parameter: - -```bash -APP_ID_1=$(linera --with-wallet 0 \ - project publish-and-create \ - examples/crowd-funding \ - crowd_funding \ - --required-application-ids $APP_ID_0 \ - --json-argument '{ "owner": "User:'$OWNER_0'", "deadline": 4102473600000000, "target": "100." }' \ - --json-parameters '"'"$APP_ID_0"'"') - -# Wait for it to fully complete -sleep 5 -``` - -## Interacting with the campaign - -First, a node service has to be started for each wallet, using two different ports: - -```bash -linera --with-wallet 0 service --port 8080 & - -# Wait for it to fully complete -sleep 2 - -linera --with-wallet 1 service --port 8081 & - -# Wait for it to fully complete -sleep 2 -``` - -Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. - -Point your browser to http://localhost:8080, and enter the query: - -```gql,uri=http://localhost:8080 -query { applications( - chainId: "$CHAIN_0" -) { id link } } -``` - -The response will have two entries, one for each application. - -If you do the same with the other chain ID in http://localhost:8081, the node service for the -other wallet, it will have no entries at all, because the applications haven't been registered -there yet. Request `crowd-funding` from the other chain. As an application ID, use `$APP_ID_1`: - -```gql,uri=http://localhost:8081 -mutation { requestApplication( - chainId: "$CHAIN_1" - applicationId: "$APP_ID_1" -) } -``` - -If you enter the `applications` query again, both entries will appear in the second wallet as -well now. `$APP_ID_0` has been registered, too, because it is a dependency of the other -application. - -On both http://localhost:8080 and http://localhost:8081, you recognize the crowd-funding -application by its ID. The entry also has a field `link`. If you open that in a new tab, you -see the GraphQL API for that application on that chain. - -Let's pledge 30 tokens by the campaign creator themself. -For `$OWNER_0` on 8080, run `echo "http://localhost:8080/chains/$CHAIN_0/applications/$APP_ID_1"` to get the URL, open it -and run the following query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_0/applications/$APP_ID_1 -mutation { pledge( - owner:"User:$OWNER_0", - amount:"30." -) } -``` - -This will make the owner show up if we list everyone who has made a pledge so far: - -```gql,uri=http://localhost:8080/chains/$CHAIN_0/applications/$APP_ID_1 -query { pledges { keys } } -``` - -To also have `$OWNER_1` make a pledge, they first need to claim their tokens. Those are still -on the other chain, where the application was created. To get the link on 8081 -for the fungible application, run `echo "http://localhost:8081/chains/$CHAIN_1/applications/$APP_ID_0"`, -open it and run the following query: - -```gql,uri=http://localhost:8081/chains/$CHAIN_1/applications/$APP_ID_0 -mutation { claim( - sourceAccount: { - owner: "User:$OWNER_1", - chainId: "$CHAIN_0" - }, - amount: "200.", - targetAccount: { - owner: "User:$OWNER_1", - chainId: "$CHAIN_1" - } -) } -``` - -You can check that the 200 tokens have arrived: - -```gql,uri=http://localhost:8081/chains/$CHAIN_1/applications/$APP_ID_0 -query { - accounts { entry(key: "User:$OWNER_1") { value } } -} -``` - -Now, also on 8081, you can open the link for the crowd-funding -application you get when you run `echo "http://localhost:8081/chains/$CHAIN_1/applications/$APP_ID_1"` -and run: - -```gql,uri=http://localhost:8081/chains/$CHAIN_1/applications/$APP_ID_1 -mutation { pledge( - owner:"User:$OWNER_1", - amount:"80." -) } -``` - -This pledges another 80 tokens. With 110 pledged in total, we have now reached the campaign -goal. Now the campaign owner (on 8080) can collect the funds: - -```gql,uri=http://localhost:8080/chains/$CHAIN_0/applications/$APP_ID_1 -mutation { collect } -``` - -Get the fungible application on -8080 URL by running `echo "http://localhost:8080/chains/$CHAIN_0/applications/$APP_ID_0"`, -then check that we have received 110 tokens, in addition to the -70 that we had left after pledging 30 by running the following query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_0/applications/$APP_ID_0 -query { - accounts { entry(key: "User:$OWNER_0") { value } } -} -``` -*/ +/*! ABI of the Crowd-funding Example Application */ use async_graphql::{Request, Response, SimpleObject}; use linera_sdk::{ diff --git a/examples/fungible/README.md b/examples/fungible/README.md index c2183d39a15..2ba314933d2 100644 --- a/examples/fungible/README.md +++ b/examples/fungible/README.md @@ -1,5 +1,3 @@ - - # Fungible Token Example Application This example application implements fungible tokens. This demonstrates in particular @@ -9,7 +7,7 @@ Once this application is built and its bytecode published on a Linera chain, the published bytecode can be used to create multiple application instances, where each instance represents a different fungible token. -# How It Works +## How It Works Individual chains have a set of accounts, where each account has an owner and a balance. The same owner can have accounts on multiple chains, with a different balance on each chain. This @@ -25,9 +23,9 @@ Tokens can be transferred from an account to different destinations, such as: - the same account on another chain, - other accounts on other chains. -# Usage +## Usage -## Setting Up +### Setting Up The WebAssembly binaries for the bytecode can be built and published using [steps from the book](https://linera-io.github.io/linera-documentation/getting_started/first_app.html), @@ -71,7 +69,7 @@ BYTECODE_ID=$(linera publish-bytecode \ Here, we stored the new bytecode ID in a variable `BYTECODE_ID` to be reused it later. -## Creating a Token +### Creating a Token In order to use the published bytecode to create a token application, the initial state must be specified. This initial state is where the tokens are minted. After the token is created, no @@ -112,7 +110,7 @@ APP_ID=$(linera create-application $BYTECODE_ID \ This will store the application ID in a new variable `APP_ID`. -## Using the Token Application +### Using the Token Application Before using the token, a source and target address should be selected. The source address should ideally be on the default chain (used to create the token) and one of the accounts chosen @@ -125,7 +123,7 @@ PORT=8080 linera service --port $PORT & ``` -### Using GraphiQL +#### Using GraphiQL Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. @@ -201,7 +199,7 @@ query { } ``` -### Using web frontend +#### Using web frontend Installing and starting the web server: @@ -231,5 +229,3 @@ echo "http://localhost:3000/$CHAIN_1?app=$APP_ID&owner=$OWNER_2&port=$PORT" OWNER_2 doesn't have the applications loaded initially. Using the first page to transfer tokens from OWNER_1 to OWNER_2 at CHAIN_2 will instantly update the UI of the second page. - - diff --git a/examples/fungible/src/lib.rs b/examples/fungible/src/lib.rs index a2be3424e40..9af56b2b664 100644 --- a/examples/fungible/src/lib.rs +++ b/examples/fungible/src/lib.rs @@ -1,241 +1,7 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -#![allow(rustdoc::invalid_codeblock_attributes)] // Using '=' in the documentation. - -/*! -# Fungible Token Example Application - -This example application implements fungible tokens. This demonstrates in particular -cross-chain messages and how applications are instantiated and auto-deployed. - -Once this application is built and its bytecode published on a Linera chain, the -published bytecode can be used to create multiple application instances, where each -instance represents a different fungible token. - -# How It Works - -Individual chains have a set of accounts, where each account has an owner and a balance. The -same owner can have accounts on multiple chains, with a different balance on each chain. This -means that an account's balance is sharded across one or more chains. - -There are two operations: `Transfer` and `Claim`. `Transfer` sends tokens from an account on the -chain where the operation is executed, while `Claim` sends a message from the current chain to -another chain in order to transfer tokens from that remote chain. - -Tokens can be transferred from an account to different destinations, such as: - -- other accounts on the same chain, -- the same account on another chain, -- other accounts on other chains. - -# Usage - -## Setting Up - -The WebAssembly binaries for the bytecode can be built and published using [steps from the -book](https://linera-io.github.io/linera-documentation/getting_started/first_app.html), -summarized below. - -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)" -``` - -You may also use `cargo install linera-service` and append the output of -`linera net helper` to your `~/.bash_profile`. - -Now, we are ready to set up a local network with an initial wallet owning several initial -chains. In a new BASH shell, enter: - -```bash -linera_spawn_and_read_wallet_variables linera net up --testing-prng-seed 37 -``` - -A new test network is now running and the environment variables `LINERA_WALLET` and -`LINERA_STORAGE` are now defined for the duration of the shell session. We used the -test-only CLI option `--testing-prng-seed` to make keys deterministic and simplify our -presentation. - -Now, compile the `fungible` application WebAssembly binaries, and publish them as an application -bytecode: - -```bash -(cd examples/fungible && cargo build --release --target wasm32-unknown-unknown) - -BYTECODE_ID=$(linera publish-bytecode \ - examples/target/wasm32-unknown-unknown/release/fungible_{contract,service}.wasm) -``` - -Here, we stored the new bytecode ID in a variable `BYTECODE_ID` to be reused it later. - -## Creating a Token - -In order to use the published bytecode to create a token application, the initial state must be -specified. This initial state is where the tokens are minted. After the token is created, no -additional tokens can be minted and added to the application. The initial state is a JSON string -that specifies the accounts that start with tokens. - -In order to select the accounts to have initial tokens, the command below can be used to list -the chains created for the test in the default wallet: - -```bash -linera wallet show -``` - -A table will be shown with the chains registered in the wallet and their meta-data. The default -chain should be highlighted in green. Each chain has an `Owner` field, and that is what is used -for the account. - -Let's define some variables corresponding to these values. (Note that owner addresses -would not be predictable without `--testing-prng-seed` above.) - -```bash -CHAIN_1=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 # default chain for the wallet -OWNER_1=7136460f0c87ae46f966f898d494c4b40c4ae8c527f4d1c0b1fa0f7cff91d20f # owner of chain 1 -CHAIN_2=256e1dbc00482ddd619c293cc0df94d366afe7980022bb22d99e33036fd465dd # another chain in the wallet -OWNER_2=598d18f67709fe76ed6a36b75a7c9889012d30b896800dfd027ee10e1afd49a3 # owner of chain 2 -``` - -The example below creates a token application on the default chain CHAIN_1 and gives the owner 100 tokens: - -```bash -APP_ID=$(linera create-application $BYTECODE_ID \ - --json-argument "{ \"accounts\": { - \"User:$OWNER_1\": \"100.\" - } }" \ - --json-parameters "{ \"ticker_symbol\": \"FUN\" }" \ -) -``` - -This will store the application ID in a new variable `APP_ID`. - -## Using the Token Application - -Before using the token, a source and target address should be selected. The source address -should ideally be on the default chain (used to create the token) and one of the accounts chosen -for the initial state, because it will already have some initial tokens to send. - -First, a node service for the current wallet has to be started: - -```bash -PORT=8080 -linera service --port $PORT & -``` - -### Using GraphiQL - -Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. - -- Navigate to the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID"`. -- To get the current balance of user $OWNER_1, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - accounts { - entry( - key: "User:$OWNER_1" - ) { - value - } - } -} -``` - -- To get the current balance of user $OWNER_2, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - accounts { - entry( - key: "User:$OWNER_2" - ) { - value - } - } -} -``` - -- To transfer 50 tokens from $OWNER_1 to $OWNER_2 - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -mutation { - transfer( - owner: "User:$OWNER_1", - amount: "50.", - targetAccount: { - chainId: "$CHAIN_1", - owner: "User:$OWNER_2" - } - ) -} -``` - -- To get the new balance of user $OWNER_1, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - accounts { - entry( - key: "User:$OWNER_1" - ) { - value - } - } -} -``` - -- To get the new balance of user $OWNER_2, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - accounts { - entry( - key: "User:$OWNER_2" - ) { - value - } - } -} -``` - -### Using web frontend - -Installing and starting the web server: - -```bash -cd examples/fungible/web-frontend -npm install --no-save - -# 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?app=$APP_ID&owner=$OWNER&port=$PORT` where - -- the path is the ID of the chain where the account is located. -- the argument `app` is the token application ID obtained when creating the token. -- `owner` is the address of the chosen user account (owner must 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`). - -In this example, two web pages for OWNER_1 and OWNER_2 can be opened by navigating these URLs: - -```bash -echo "http://localhost:3000/$CHAIN_1?app=$APP_ID&owner=$OWNER_1&port=$PORT" -echo "http://localhost:3000/$CHAIN_1?app=$APP_ID&owner=$OWNER_2&port=$PORT" -``` - -OWNER_2 doesn't have the applications loaded initially. Using the first page to -transfer tokens from OWNER_1 to OWNER_2 at CHAIN_2 will instantly update the UI of the -second page. -*/ +/* ABI of the Fungible Token Example Application */ pub use linera_sdk::abis::fungible::*; use linera_sdk::base::{AccountOwner, Amount}; diff --git a/examples/gen-nft/README.md b/examples/gen-nft/README.md index 844b196e2d4..a9173acefc7 100644 --- a/examples/gen-nft/README.md +++ b/examples/gen-nft/README.md @@ -1,5 +1,3 @@ - - # Generative NFT Example Application This example application implements generative non-fungible tokens (NFTs). It is based on the @@ -24,9 +22,9 @@ the Linera blockchain ecosystem. For more details on the application's contract and how it manages multiple different NFTs, see the [NFT example](../non-fungible/README.md#how-it-works). -# Usage +## Usage -## Setting Up +### Setting Up Most of this can be referred to the [fungible app README](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#setting-up), except for at the end when compiling and publishing the bytecode, what you'll need to do will be slightly different. @@ -48,7 +46,7 @@ BYTECODE_ID=$(linera publish-bytecode \ Here, we stored the new bytecode ID in a variable `BYTECODE_ID` to be reused later. -## Creating an NFT +### Creating an NFT Unlike fungible tokens, each NFT is unique and identified by a unique token ID. Also unlike fungible tokens, when creating the NFT application you don't need to specify an initial state or parameters. NFTs will be minted later. @@ -71,7 +69,7 @@ APP_ID=$(linera create-application $BYTECODE_ID) This will store the application ID in a new variable `APP_ID`. -## Using the NFT Application +### Using the NFT Application Operations such as minting NFTs, transferring NFTs, and claiming NFTs from other chains follow a similar approach to fungible tokens, with adjustments for the unique nature of NFTs. @@ -82,7 +80,7 @@ PORT=8080 linera service --port $PORT & ``` -### Using GraphiQL +#### Using GraphiQL Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. @@ -149,7 +147,7 @@ mutation { } ``` -### Using Web Frontend +#### Using Web Frontend Installing and starting the web server: @@ -167,5 +165,3 @@ echo "http://localhost:3000/$CHAIN_1?app=$APP_ID&owner=$OWNER_2&port=$PORT" ``` For the final part, refer to [Fungible Token Example Application - Using web frontend](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#using-web-frontend). - - diff --git a/examples/gen-nft/src/lib.rs b/examples/gen-nft/src/lib.rs index 61fe8440e57..f19c912500b 100644 --- a/examples/gen-nft/src/lib.rs +++ b/examples/gen-nft/src/lib.rs @@ -1,177 +1,7 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -#![allow(rustdoc::invalid_codeblock_attributes)] // Using '=' in the documentation. - -/*! -# Generative NFT Example Application - -This example application implements generative non-fungible tokens (NFTs). It is based on the -[Non-Fungible Token Example Application](../non-fungible), with the difference being that instead -of representing the token payload as an arbitrary sequence of bytes, it is represented as a string -generated by a large-language model. - -The main purpose of this application is to show how to run an artificial intelligence model in the -application service, allowing it to generate strings used as the contents of non-fungible tokens. -The application service runs on the client (usually inside the wallet), which means it executes -off-chain. In this example, it is used to prepare the mint operation by running the AI model to -generate the token contents from a user provided prompt. The resulting operation can then be placed -by the wallet in a block proposal, minting the token on-chain. - -This application's contract is mostly identical to the one from the [NFT Example -application](../non-fungible). The only difference is the change of the token payload to be a text -string instead of an arbitrary sequence of bytes. Like the NFT example application, this also shows -cross-chain messages, demonstrating how NFTs can be minted, transferred, and claimed across -different chains, emphasizing the instantiation and auto-deployment of application instances within -the Linera blockchain ecosystem. - -For more details on the application's contract and how it manages multiple different NFTs, see the -[NFT example](../non-fungible/README.md#how-it-works). - -# Usage - -## Setting Up - -Most of this can be referred to the [fungible app README](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#setting-up), except for at the end when compiling and publishing the bytecode, what you'll need to do will be slightly different. - -```bash -export PATH="$PWD/target/debug:$PATH" -source /dev/stdin <<<"$(linera net helper 2>/dev/null)" - -linera_spawn_and_read_wallet_variables linera net up --testing-prng-seed 37 -``` - -Compile the `non-fungible` application WebAssembly binaries, and publish them as an application bytecode: - -```bash -(cd examples/gen-nft && cargo build --release --target wasm32-unknown-unknown) - -BYTECODE_ID=$(linera publish-bytecode \ - examples/target/wasm32-unknown-unknown/release/gen_nft_{contract,service}.wasm) -``` - -Here, we stored the new bytecode ID in a variable `BYTECODE_ID` to be reused later. - -## Creating an NFT - -Unlike fungible tokens, each NFT is unique and identified by a unique token ID. Also unlike fungible tokens, when creating the NFT application you don't need to specify an initial state or parameters. NFTs will be minted later. - -Refer to the [fungible app README](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#creating-a-token) to figure out how to list the chains created for the test in the default wallet, as well as defining some variables corresponding to these values. - -```bash -linera wallet show - -CHAIN_1=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 # default chain for the wallet -OWNER_1=7136460f0c87ae46f966f898d494c4b40c4ae8c527f4d1c0b1fa0f7cff91d20f # owner of chain 1 -CHAIN_2=256e1dbc00482ddd619c293cc0df94d366afe7980022bb22d99e33036fd465dd # another chain in the wallet -OWNER_2=598d18f67709fe76ed6a36b75a7c9889012d30b896800dfd027ee10e1afd49a3 # owner of chain 2 -``` - -To create the NFT application, run the command below: - -```bash -APP_ID=$(linera create-application $BYTECODE_ID) -``` - -This will store the application ID in a new variable `APP_ID`. - -## Using the NFT Application - -Operations such as minting NFTs, transferring NFTs, and claiming NFTs from other chains follow a similar approach to fungible tokens, with adjustments for the unique nature of NFTs. - -First, a node service for the current wallet has to be started: - -```bash -PORT=8080 -linera service --port $PORT & -``` - -### Using GraphiQL - -Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. - -- Navigate to the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID"`. -- To mint an NFT, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -mutation { - mint( - minter: "User:$OWNER_1", - prompt: "Hello!" - ) -} -``` - -- To check that it's assigned to the owner, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - ownedNfts(owner: "User:$OWNER_1") -} -``` - -Set the `QUERY_RESULT` variable to have the result returned by the previous query, and `TOKEN_ID` will be properly set for you. -Alternatively you can set the `TOKEN_ID` variable to the `tokenId` value returned by the previous query yourself. - -```bash -TOKEN_ID=$(echo "$QUERY_RESULT" | jq -r '.ownedNfts[].tokenId') -``` - -- To check that it's there, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - nft(tokenId: "$TOKEN_ID") { - tokenId, - owner, - prompt, - minter, - } -} -``` - -- To check everything that it's there, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - nfts -} -``` - -- To transfer the NFT to user `$OWNER_2`, still on chain `$CHAIN_1`, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -mutation { - transfer( - sourceOwner: "User:$OWNER_1", - tokenId: "$TOKEN_ID", - targetAccount: { - chainId: "$CHAIN_1", - owner: "User:$OWNER_2" - } - ) -} -``` - -### Using Web Frontend - -Installing and starting the web server: - -```bash -cd examples/gen-nft/web-frontend -npm install --no-save - -# Start the server but not open the web page right away. -BROWSER=none npm start & -``` - -```bash -echo "http://localhost:3000/$CHAIN_1?app=$APP_ID&owner=$OWNER_1&port=$PORT" -echo "http://localhost:3000/$CHAIN_1?app=$APP_ID&owner=$OWNER_2&port=$PORT" -``` - -For the final part, refer to [Fungible Token Example Application - Using web frontend](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#using-web-frontend). -*/ +/*! ABI of the Generative NFT Example Application */ use std::fmt::{Display, Formatter}; diff --git a/examples/hex-game/README.md b/examples/hex-game/README.md index c50f311a0ee..14815dd68cb 100644 --- a/examples/hex-game/README.md +++ b/examples/hex-game/README.md @@ -1,6 +1,4 @@ - - -# Hex +# Hex Game Hex is a game where player `One` tries to connect the left and right sides of the board and player `Two` tries to connect top to bottom. The board is rhombic and has a configurable side length `s`. @@ -20,9 +18,9 @@ This implementation shows how to write a game that is played on a shared tempora Users make turns by submitting operations to the chain, not by sending messages, so a player does not have to wait for any other chain owner to accept any message. -# Usage +## Usage -## Setting up +### Setting up Make sure you have the `linera` binary in your `PATH`, and that it is compatible with your `linera-sdk` version. @@ -49,7 +47,7 @@ explanation. CHAIN_1=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 ``` -## Creating the Game Chain +### Creating the Game Chain We open a new chain owned by both `$OWNER_1` and `$OWNER_2`, create the application on it, and start the node service. @@ -130,7 +128,7 @@ linera -w1 service --port 8081 & sleep 1 ``` -## Playing the Game +### Playing the Game Now the first player can make a move by navigating to the URL you get by running `echo "http://localhost:8080/chains/$HEX_CHAIN/applications/$APP_ID"`: @@ -143,5 +141,3 @@ And the second player player at the URL you get by running `echo "http://localho ```gql,uri=http://localhost:8081/chains/$HEX_CHAIN/applications/$APP_ID mutation { makeMove(x: 4, y: 5) } ``` - - diff --git a/examples/hex-game/src/lib.rs b/examples/hex-game/src/lib.rs index d042b2f2d8b..61d3a537e71 100644 --- a/examples/hex-game/src/lib.rs +++ b/examples/hex-game/src/lib.rs @@ -1,153 +1,7 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -#![allow(rustdoc::invalid_codeblock_attributes)] // Using '=' in the documentation. - -/*! -# Hex - -Hex is a game where player `One` tries to connect the left and right sides of the board and player -`Two` tries to connect top to bottom. The board is rhombic and has a configurable side length `s`. -It consists of `s * s` hexagonal cells, indexed like this: - -```ignore -(0, 0) (1, 0) (2, 0) - - (0, 1) (1, 1) (2, 1) - - (0, 2) (1, 2) (2, 2) -``` - -The players alternate placing a stone in their color on an empty cell until one of them wins. - -This implementation shows how to write a game that is played on a shared temporary chain: -Users make turns by submitting operations to the chain, not by sending messages, so a player -does not have to wait for any other chain owner to accept any message. - -# Usage - -## Setting up - -Make sure you have the `linera` binary in your `PATH`, and that it is compatible with your -`linera-sdk` version. - -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 and create two wallets: - -```bash -linera_spawn_and_read_wallet_variables linera net up --testing-prng-seed 37 --extra-wallets 1 -``` - -We use the test-only CLI option `--testing-prng-seed` to make keys deterministic and simplify our -explanation. - -```bash -CHAIN_1=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 -``` - -## Creating the Game Chain - -We open a new chain owned by both `$OWNER_1` and `$OWNER_2`, create the application on it, and -start the node service. - -```bash -APP_ID=$(linera -w0 --wait-for-outgoing-messages \ - project publish-and-create examples/hex-game hex_game $CHAIN_1 \ - --json-argument "{ - \"startTime\": 600000000, - \"increment\": 600000000, - \"blockDelay\": 100000000 - }") - -PUB_KEY_1=$(linera -w0 keygen) -PUB_KEY_2=$(linera -w1 keygen) - -linera -w0 service --port 8080 & -sleep 1 -``` - -Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. - -The `start` mutation starts a new game. We specify the two players using their new public keys, -on the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID"`: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -mutation { - start( - players: [ - "$PUB_KEY_1", - "$PUB_KEY_2" - ], - boardSize: 11, - feeBudget: "1" - ) -} -``` - -The app's main chain keeps track of the games in progress, by public key: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - gameChains { - keys(count: 3) - } -} -``` - -It contains the temporary chain's ID, and the ID of the message that created it: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - gameChains { - entry(key: "$PUB_KEY_1") { - value { - messageId chainId - } - } - } -} -``` - -Set the `QUERY_RESULT` variable to have the result returned by the previous query, and `HEX_CHAIN` and `MESSAGE_ID` will be properly set for you. -Alternatively you can set the variables to the `chainId` and `messageId` values, respectively, returned by the previous query yourself. -Using the message ID, we can assign the new chain to the key in each wallet: - -```bash -kill %% && sleep 1 # Kill the service so we can use CLI commands for wallet 0. - -HEX_CHAIN=$(echo "$QUERY_RESULT" | jq -r '.gameChains.entry.value[0].chainId') -MESSAGE_ID=$(echo "$QUERY_RESULT" | jq -r '.gameChains.entry.value[0].messageId') - -linera -w0 assign --key $PUB_KEY_1 --message-id $MESSAGE_ID -linera -w1 assign --key $PUB_KEY_2 --message-id $MESSAGE_ID - -linera -w0 service --port 8080 & -linera -w1 service --port 8081 & -sleep 1 -``` - -## Playing the Game - -Now the first player can make a move by navigating to the URL you get by running `echo "http://localhost:8080/chains/$HEX_CHAIN/applications/$APP_ID"`: - -```gql,uri=http://localhost:8080/chains/$HEX_CHAIN/applications/$APP_ID -mutation { makeMove(x: 4, y: 4) } -``` - -And the second player player at the URL you get by running `echo "http://localhost:8080/chains/$HEX_CHAIN/applications/$APP_ID"`: - -```gql,uri=http://localhost:8081/chains/$HEX_CHAIN/applications/$APP_ID -mutation { makeMove(x: 4, y: 5) } -``` -*/ +/*! ABI of the Hex game */ use std::iter; diff --git a/examples/llm/README.md b/examples/llm/README.md index c2935e2369f..b89feb6acc3 100644 --- a/examples/llm/README.md +++ b/examples/llm/README.md @@ -1,5 +1,3 @@ - - # LLM Example Application This example application runs a large language model in an application's service. @@ -17,7 +15,7 @@ CAVEAT: ([#2160](https://github.com/linera-io/linera-protocol/issues/2160)). -# How It Works +## How It Works Models and tokenizers are served locally using a local Python server. They are expected at `model.bin` and `tokenizer.json`. @@ -29,7 +27,7 @@ When the first prompt is submitted, the application's service uses the `fetch_ur system API to fetch the model and tokenizer. Subsequently, the model bytes are converted to the GGUF format where it can be used for inference. -# Usage +## Usage We're assuming that a local wallet is set up and connected to a running test network (local or otherwise). @@ -42,7 +40,7 @@ CHAIN=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 See the file `linera-protocol/examples/fungible/README.md` or the [online developer manual](https://linera.dev) for instructions. -## Using the LLM Application +### Using the LLM Application First, deploy the application: ```bash @@ -73,5 +71,3 @@ Finally, navigate to `localhost:3000` to interact with the Linera ChatBot. ```bash echo "http://localhost:3000/$CHAIN?app=$APP_ID&port=$PORT" ``` - - diff --git a/examples/llm/src/lib.rs b/examples/llm/src/lib.rs index 7510c00c159..d47e4f12fe8 100644 --- a/examples/llm/src/lib.rs +++ b/examples/llm/src/lib.rs @@ -1,81 +1,7 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -/*! -# LLM Example Application - -This example application runs a large language model in an application's service. - -The model used by Linera Stories is a 40M parameter TinyLlama by A. Karpathy. Find out more here: -. - -CAVEAT: - -* Running larger LLMs with acceptable performance will likely require hardware acceleration ([#1931](https://github.com/linera-io/linera-protocol/issues/1931)). - -* The service currently is restarted when the wallet receives a new block for the chain where the - application is running from. That means it fetches the model again, which is inefficient. The - service should be allowed to continue executing in that case - ([#2160](https://github.com/linera-io/linera-protocol/issues/2160)). - - -# How It Works - -Models and tokenizers are served locally using a local Python server. They are expected -at `model.bin` and `tokenizer.json`. - -The application's service exposes a single GraphQL field called `prompt` which takes a prompt -as input and returns a response. - -When the first prompt is submitted, the application's service uses the `fetch_url` -system API to fetch the model and tokenizer. Subsequently, the model bytes are converted -to the GGUF format where it can be used for inference. - -# Usage - -We're assuming that a local wallet is set up and connected to a running test network -(local or otherwise). - -If you use `linera net up`, the value of the default chain ID is: -```bash -CHAIN=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 -``` - -See the file `linera-protocol/examples/fungible/README.md` or the [online developer -manual](https://linera.dev) for instructions. - -## Using the LLM Application - -First, deploy the application: -```bash -cd examples -APP_ID=$(linera project publish-and-create llm) -``` - -Then, a node service for the current wallet has to be started: - -```bash -PORT=8080 -linera --long-lived-services service --port $PORT & - ``` - -The experimental option `--long-lived-services` is used for performance, to avoid -reloading the model between queries. - -Next, navigate to `llm/web-frontend` and install the requisite `npm` -dependencies: - -```bash -cd llm/web-frontend -npm install --no-save -BROWSER=none npm start -``` - -Finally, navigate to `localhost:3000` to interact with the Linera ChatBot. -```bash -echo "http://localhost:3000/$CHAIN?app=$APP_ID&port=$PORT" -``` -*/ +/*! ABI of the LLM Example Application */ 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 9bd4782cda4..dbd76e9a062 100644 --- a/examples/matching-engine/README.md +++ b/examples/matching-engine/README.md @@ -1,5 +1,3 @@ - - # Matching Engine Example Application This sample application demonstrates a matching engine, showcasing the DeFi capabilities @@ -36,9 +34,9 @@ When inserting an order it goes through the following steps: 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 +## Usage -## Setting Up +### 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 @@ -111,7 +109,7 @@ linera --wait-for-outgoing-messages request-application \ --requester-chain-id $CHAIN_2 $MATCHING_ENGINE ``` -## Using the Matching Engine Application +### Using the Matching Engine Application First, a node service for the current wallet has to be started: @@ -120,7 +118,7 @@ PORT=8080 linera service --port $PORT & ``` -### Using GraphiQL +#### Using GraphiQL Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. @@ -157,7 +155,7 @@ query { } ``` -### Atomic Swaps +#### Atomic Swaps In general, if you send tokens to a chain owned by someone else, you rely on them for asset availability: If they don't handle your messages, you don't have access to @@ -256,5 +254,3 @@ query { } } ``` - - diff --git a/examples/matching-engine/src/lib.rs b/examples/matching-engine/src/lib.rs index 72e854316d4..306553dd576 100644 --- a/examples/matching-engine/src/lib.rs +++ b/examples/matching-engine/src/lib.rs @@ -1,266 +1,7 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -#![allow(rustdoc::invalid_codeblock_attributes)] // Using '=' in the documentation. - -/*! -# 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=7136460f0c87ae46f966f898d494c4b40c4ae8c527f4d1c0b1fa0f7cff91d20f -OWNER_2=a477cb966190661c0dfbe50602616a78a48d2bef6cb5288d49deb3e05585d579 -OWNER_3=d2115775b5b3c5c1ed3c1516319a7e850c75d0786a74b39f5250cf9decc88124 -CHAIN_1=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 -CHAIN_2=69705f85ac4c9fef6c02b4d83426aaaf05154c645ec1c61665f8e450f0468bc0 -PUB_KEY_1=fcf518d56455283ace2bbc11c71e684eb58af81bc98b96a18129e825ce24ea84 -PUB_KEY_2=ca909dcf60df014c166be17eb4a9f6e2f9383314a57510206a54cd841ade455e -``` - -Publish and create two `fungible` applications whose IDs will be used as a -parameter for the `matching-engine` 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 -FUN1_APP_ID=$(linera --wait-for-outgoing-messages \ - project publish-and-create examples/fungible \ - --json-argument "{ \"accounts\": { - \"User:$OWNER_1\": \"100.\", - \"User:$OWNER_2\": \"150.\" - } }" \ - --json-parameters "{ \"ticker_symbol\": \"FUN1\" }" \ -) - -FUN2_APP_ID=$(linera --wait-for-outgoing-messages \ - project publish-and-create examples/fungible \ - --json-argument "{ \"accounts\": { - \"User:$OWNER_1\": \"100.\", - \"User:$OWNER_2\": \"150.\" - } }" \ - --json-parameters "{ \"ticker_symbol\": \"FUN2\" }" \ -) -``` - -Now we publish and deploy the Matching Engine application: - -```bash -MATCHING_ENGINE=$(linera --wait-for-outgoing-messages \ - project publish-and-create examples/matching-engine \ - --json-parameters "{\"tokens\":["\"$FUN1_APP_ID\"","\"$FUN2_APP_ID\""]}" \ - --required-application-ids $FUN1_APP_ID $FUN2_APP_ID) -``` - -And make sure chain 2 also has it: - -```bash -linera --wait-for-outgoing-messages request-application \ - --requester-chain-id $CHAIN_2 $MATCHING_ENGINE -``` - -## 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 - -Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. - -Navigate to the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_1/applications/$MATCHING_ENGINE"`: - -To create a `Bid` order as owner 1, offering to buy 1 FUN1 for 5 FUN2: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$MATCHING_ENGINE -mutation { - executeOrder( - order: { - Insert : { - owner: "User:$OWNER_1", - amount: "1", - nature: Bid, - price: { - price:5 - } - } - } - ) -} -``` - -To query about the bid price: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$MATCHING_ENGINE -query { - bids { - keys { - price - } - } -} -``` - -### Atomic Swaps - -In general, if you send tokens to a chain owned by someone else, you rely on them -for asset availability: If they don't handle your messages, you don't have access to -your tokens. - -Fortunately, Linera provides a solution based on temporary chains: -If the number of parties who want to swap tokens is limited, we can make them all chain -owners, allow only Matching Engine operations on the chain, and allow only the Matching -Engine to close the chain. - -```bash -kill %% && sleep 1 # Kill the service so we can use CLI commands for chain 1. - -linera --wait-for-outgoing-messages change-ownership \ - --owner-public-keys $PUB_KEY_1 $PUB_KEY_2 - -linera --wait-for-outgoing-messages change-application-permissions \ - --execute-operations $MATCHING_ENGINE \ - --close-chain $MATCHING_ENGINE - -linera service --port $PORT & -``` - -First, owner 2 should claim their tokens. Navigate to the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_2/applications/$FUN1_APP_ID"`: - -```gql,uri=http://localhost:8080/chains/$CHAIN_2/applications/$FUN1_APP_ID -mutation { - claim( - sourceAccount: { - chainId: "$CHAIN_1", - owner: "User:$OWNER_2", - } - amount: "100.", - targetAccount: { - chainId: "$CHAIN_2", - owner: "User:$OWNER_3" - } - ) -} -``` - -And to the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_2/applications/$FUN2_APP_ID"`: - -```gql,uri=http://localhost:8080/chains/$CHAIN_2/applications/$FUN2_APP_ID -mutation { - claim( - sourceAccount: { - chainId: "$CHAIN_1", - owner: "User:$OWNER_2", - } - amount: "150.", - targetAccount: { - chainId: "$CHAIN_2", - owner: "User:$OWNER_2" - } - ) -} -``` - -Owner 2 offers to buy 2 FUN1 for 10 FUN2. This gets partially filled, and they buy 1 FUN1 -for 5 FUN2 from owner 1. This leaves 5 FUN2 of owner 2 on chain 1. On the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_2/applications/$MATCHING_ENGINE"`: - -```gql,uri=http://localhost:8080/chains/$CHAIN_2/applications/$MATCHING_ENGINE -mutation { - executeOrder( - order: { - Insert : { - owner: "User:$OWNER_2", - amount: "2", - nature: Ask, - price: { - price:5 - } - } - } - ) -} -``` - -The only way to close the chain is via the application now. On the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_1/applications/$MATCHING_ENGINE"`: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$MATCHING_ENGINE -mutation { closeChain } -``` - -Owner 2 should now get back their tokens, and have 145 FUN2 left. On the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_2/applications/$FUN2_APP_ID"` - -```gql,uri=http://localhost:8080/chains/$CHAIN_2/applications/$FUN2_APP_ID -query { - accounts { - entry( - key: "User:$OWNER_2" - ) { - value - } - } -} -``` -*/ +/*! ABI of the Matching Engine Example Application */ use async_graphql::{scalar, InputObject, Request, Response, SimpleObject}; use fungible::FungibleTokenAbi; diff --git a/examples/meta-counter/README.md b/examples/meta-counter/README.md index 5a5ee4bd569..e67f47d14d5 100644 --- a/examples/meta-counter/README.md +++ b/examples/meta-counter/README.md @@ -1,7 +1,4 @@ - - # Meta-Counter Example Application This application is only used for testing cross-application calls and oracles. - diff --git a/examples/meta-counter/src/lib.rs b/examples/meta-counter/src/lib.rs index e96e40e13d2..c7fe341baca 100644 --- a/examples/meta-counter/src/lib.rs +++ b/examples/meta-counter/src/lib.rs @@ -1,11 +1,7 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -/*! -# Meta-Counter Example Application - -This application is only used for testing cross-application calls and oracles. -*/ +/*! ABI of the Meta-Counter Example Application */ use async_graphql::{Request, Response}; use linera_sdk::base::{ChainId, ContractAbi, ServiceAbi}; diff --git a/examples/native-fungible/README.md b/examples/native-fungible/README.md index 030614c698a..3f3a05eb422 100644 --- a/examples/native-fungible/README.md +++ b/examples/native-fungible/README.md @@ -1,17 +1,15 @@ - - # Native Fungible Token Example Application This app is very similar to the [Fungible Token Example Application](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#fungible-token-example-application). The difference is that this is a native token that will use system API calls for operations. The general aspects of how it works can be referred to the linked README. Bash commands will always be included here for testing purposes. -# How It Works +## How It Works Refer to [Fungible Token Example Application - How It Works](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#how-it-works). -# Usage +## Usage -## Setting Up +### Setting Up Most of this can also be referred to the [fungible app README](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#setting-up), except for at the end when compiling and publishing the bytecode, what you'll need to do will be slightly different. @@ -34,7 +32,7 @@ BYTECODE_ID="$(linera publish-bytecode \ Here, we stored the new bytecode ID in a variable `BYTECODE_ID` to be reused it later. -## Creating a Token +### Creating a Token Most of this can also be referred to the [fungible app README](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#creating-a-token), except for at the end when creating the application, you always need to pass `NAT` as the `ticker_symbol` because the Native Fungible App has it hardcoded to that. @@ -57,7 +55,7 @@ APP_ID=$(linera create-application $BYTECODE_ID \ ) ``` -## Using the Token Application +### Using the Token Application Refer to [Fungible Token Example Application - Using the Token Application](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#using-the-token-application). @@ -66,7 +64,7 @@ PORT=8080 linera service --port $PORT & ``` -### Using GraphiQL +#### Using GraphiQL Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. @@ -142,7 +140,7 @@ query { } ``` -### Using web frontend +#### Using web frontend Refer to [Fungible Token Example Application - Using web frontend](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#using-web-frontend). @@ -158,5 +156,3 @@ BROWSER=none npm start & echo "http://localhost:3000/$CHAIN_1?app=$APP_ID&owner=$OWNER_1&port=$PORT" echo "http://localhost:3000/$CHAIN_1?app=$APP_ID&owner=$OWNER_2&port=$PORT" ``` - - diff --git a/examples/native-fungible/src/lib.rs b/examples/native-fungible/src/lib.rs index a86f54b3feb..7bc1646c137 100644 --- a/examples/native-fungible/src/lib.rs +++ b/examples/native-fungible/src/lib.rs @@ -1,168 +1,7 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -#![allow(rustdoc::invalid_codeblock_attributes)] // Using '=' in the documentation. - -/*! -# Native Fungible Token Example Application - -This app is very similar to the [Fungible Token Example Application](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#fungible-token-example-application). The difference is that this is a native token that will use system API calls for operations. -The general aspects of how it works can be referred to the linked README. Bash commands will always be included here for testing purposes. - -# How It Works - -Refer to [Fungible Token Example Application - How It Works](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#how-it-works). - -# Usage - -## Setting Up - -Most of this can also be referred to the [fungible app README](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#setting-up), except for at the end when compiling and publishing the bytecode, what you'll need to do will be slightly different. - -```bash -export PATH="$PWD/target/debug:$PATH" -source /dev/stdin <<<"$(linera net helper 2>/dev/null)" - -linera_spawn_and_read_wallet_variables linera net up --testing-prng-seed 37 -``` - -Compile the `native-fungible` application WebAssembly binaries, and publish them as an application -bytecode: - -```bash -(cd examples/native-fungible && cargo build --release --target wasm32-unknown-unknown) - -BYTECODE_ID="$(linera publish-bytecode \ - examples/target/wasm32-unknown-unknown/release/native_fungible_{contract,service}.wasm)" -``` - -Here, we stored the new bytecode ID in a variable `BYTECODE_ID` to be reused it later. - -## Creating a Token - -Most of this can also be referred to the [fungible app README](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#creating-a-token), except for at the end when creating the application, you always need to pass `NAT` as the `ticker_symbol` because the Native Fungible App has it hardcoded to that. - -```bash -linera wallet show -CHAIN_1=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 # default chain for the wallet -OWNER_1=7136460f0c87ae46f966f898d494c4b40c4ae8c527f4d1c0b1fa0f7cff91d20f # owner of chain 1 -CHAIN_2=256e1dbc00482ddd619c293cc0df94d366afe7980022bb22d99e33036fd465dd # another chain in the wallet -OWNER_2=598d18f67709fe76ed6a36b75a7c9889012d30b896800dfd027ee10e1afd49a3 # owner of chain 2 -``` - -The app can't mint new native tokens, so the initial balance is taken from the chain balance. - -```bash -APP_ID=$(linera create-application $BYTECODE_ID \ - --json-argument "{ \"accounts\": { - \"User:$OWNER_1\": \"100.\" - } }" \ - --json-parameters "{ \"ticker_symbol\": \"NAT\" }" \ -) -``` - -## Using the Token Application - -Refer to [Fungible Token Example Application - Using the Token Application](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#using-the-token-application). - -```bash -PORT=8080 -linera service --port $PORT & -``` - -### Using GraphiQL - -Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. - -- Navigate to the URL you get by running `echo "http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID"`. -- To get the current balance of user $OWNER_1, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - accounts { - entry( - key: "User:$OWNER_1" - ) { - value - } - } -} -``` - -- To get the current balance of user $OWNER_2, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - accounts { - entry( - key: "User:$OWNER_2" - ) { - value - } - } -} -``` - -- To transfer 50 tokens from $OWNER_1 to $OWNER_2 - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -mutation { - transfer( - owner: "User:$OWNER_1", - amount: "50.", - targetAccount: { - chainId: "$CHAIN_1", - owner: "User:$OWNER_2" - } - ) -} -``` - -- To get the new balance of user $OWNER_1, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - accounts { - entry( - key: "User:$OWNER_1" - ) { - value - } - } -} -``` - -- To get the new balance of user $OWNER_2, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - accounts { - entry( - key: "User:$OWNER_2" - ) { - value - } - } -} -``` - -### Using web frontend - -Refer to [Fungible Token Example Application - Using web frontend](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#using-web-frontend). - -```bash -cd examples/fungible/web-frontend -npm install --no-save - -# Start the server but not open the web page right away. -BROWSER=none npm start & -``` - -```bash -echo "http://localhost:3000/$CHAIN_1?app=$APP_ID&owner=$OWNER_1&port=$PORT" -echo "http://localhost:3000/$CHAIN_1?app=$APP_ID&owner=$OWNER_2&port=$PORT" -``` -*/ +/*! ABI of the Native Fungible Token Example Application */ use async_graphql::SimpleObject; use linera_sdk::base::{AccountOwner, Amount}; diff --git a/examples/non-fungible/README.md b/examples/non-fungible/README.md index 3904a092c92..7f2cf38a313 100644 --- a/examples/non-fungible/README.md +++ b/examples/non-fungible/README.md @@ -1,5 +1,3 @@ - - # Non-Fungible Token Example Application This example application implements non-fungible tokens (NFTs), showcasing the creation and management of unique digital assets. It highlights cross-chain messages, demonstrating how NFTs can be minted, transferred, and claimed across different chains, emphasizing the instantiation and auto-deployment of applications within the Linera blockchain ecosystem. @@ -8,7 +6,7 @@ Once this application's bytecode is published on a Linera chain, that applicatio Some portions of this are very similar to the `fungible` README, and we'll refer to it throughout. Bash commands will always be included here for testing purposes. -# How It Works +## How It Works Each chain maintains a subset of NFTs, represented as unique token identifiers. NFT ownership is tracked across one or multiple chains, allowing for rich, cross-chain interactions. @@ -24,9 +22,9 @@ NFTs can be transferred to various destinations, including: - The same account on a different chain. - Other accounts on different chains. -# Usage +## Usage -## Setting Up +### Setting Up Most of this can be referred to the [fungible app README](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#setting-up), except for at the end when compiling and publishing the bytecode, what you'll need to do will be slightly different. @@ -48,7 +46,7 @@ BYTECODE_ID=$(linera publish-bytecode \ Here, we stored the new bytecode ID in a variable `BYTECODE_ID` to be reused later. -## Creating an NFT +### Creating an NFT Unlike fungible tokens, each NFT is unique and identified by a unique token ID. Also unlike fungible tokens, when creating the NFT application you don't need to specify an initial state or parameters. NFTs will be minted later. @@ -71,7 +69,7 @@ APP_ID=$(linera create-application $BYTECODE_ID) This will store the application ID in a new variable `APP_ID`. -## Using the NFT Application +### Using the NFT Application Operations such as minting NFTs, transferring NFTs, and claiming NFTs from other chains follow a similar approach to fungible tokens, with adjustments for the unique nature of NFTs. @@ -82,7 +80,7 @@ PORT=8080 linera service --port $PORT & ``` -### Using GraphiQL +#### Using GraphiQL Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. @@ -170,7 +168,7 @@ mutation { } ``` -### Using Web Frontend +#### Using Web Frontend Installing and starting the web server: @@ -188,5 +186,3 @@ echo "http://localhost:3000/$CHAIN_1?app=$APP_ID&owner=$OWNER_2&port=$PORT" ``` For the final part, refer to [Fungible Token Example Application - Using web frontend](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#using-web-frontend). - - diff --git a/examples/non-fungible/src/lib.rs b/examples/non-fungible/src/lib.rs index ad513a0cf7a..d660b9f08b5 100644 --- a/examples/non-fungible/src/lib.rs +++ b/examples/non-fungible/src/lib.rs @@ -1,198 +1,7 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -#![allow(rustdoc::invalid_codeblock_attributes)] // Using '=' in the documentation. - -/*! -# Non-Fungible Token Example Application - -This example application implements non-fungible tokens (NFTs), showcasing the creation and management of unique digital assets. It highlights cross-chain messages, demonstrating how NFTs can be minted, transferred, and claimed across different chains, emphasizing the instantiation and auto-deployment of applications within the Linera blockchain ecosystem. - -Once this application's bytecode is published on a Linera chain, that application will contain the registry of the different NFTs. - -Some portions of this are very similar to the `fungible` README, and we'll refer to it throughout. Bash commands will always be included here for testing purposes. - -# How It Works - -Each chain maintains a subset of NFTs, represented as unique token identifiers. NFT ownership is tracked across one or multiple chains, allowing for rich, cross-chain interactions. - -The application supports three primary operations: `Mint`, `Transfer`, and `Claim`. - -`Mint` creates a new NFT within the application, assigning it to the minter. -`Transfer` changes the ownership of an NFT from one account to another, either within the same chain or across chains. -`Claim` sends a cross-chain message to transfer ownership of an NFT from a remote chain to the current chain. - -NFTs can be transferred to various destinations, including: - -- Other accounts on the same chain. -- The same account on a different chain. -- Other accounts on different chains. - -# Usage - -## Setting Up - -Most of this can be referred to the [fungible app README](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#setting-up), except for at the end when compiling and publishing the bytecode, what you'll need to do will be slightly different. - -```bash -export PATH="$PWD/target/debug:$PATH" -source /dev/stdin <<<"$(linera net helper 2>/dev/null)" - -linera_spawn_and_read_wallet_variables linera net up --testing-prng-seed 37 -``` - -Compile the `non-fungible` application WebAssembly binaries, and publish them as an application bytecode: - -```bash -(cd examples/non-fungible && cargo build --release --target wasm32-unknown-unknown) - -BYTECODE_ID=$(linera publish-bytecode \ - examples/target/wasm32-unknown-unknown/release/non_fungible_{contract,service}.wasm) -``` - -Here, we stored the new bytecode ID in a variable `BYTECODE_ID` to be reused later. - -## Creating an NFT - -Unlike fungible tokens, each NFT is unique and identified by a unique token ID. Also unlike fungible tokens, when creating the NFT application you don't need to specify an initial state or parameters. NFTs will be minted later. - -Refer to the [fungible app README](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#creating-a-token) to figure out how to list the chains created for the test in the default wallet, as well as defining some variables corresponding to these values. - -```bash -linera wallet show - -CHAIN_1=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 # default chain for the wallet -OWNER_1=7136460f0c87ae46f966f898d494c4b40c4ae8c527f4d1c0b1fa0f7cff91d20f # owner of chain 1 -CHAIN_2=256e1dbc00482ddd619c293cc0df94d366afe7980022bb22d99e33036fd465dd # another chain in the wallet -OWNER_2=598d18f67709fe76ed6a36b75a7c9889012d30b896800dfd027ee10e1afd49a3 # owner of chain 2 -``` - -To create the NFT application, run the command below: - -```bash -APP_ID=$(linera create-application $BYTECODE_ID) -``` - -This will store the application ID in a new variable `APP_ID`. - -## Using the NFT Application - -Operations such as minting NFTs, transferring NFTs, and claiming NFTs from other chains follow a similar approach to fungible tokens, with adjustments for the unique nature of NFTs. - -First, a node service for the current wallet has to be started: - -```bash -PORT=8080 -linera service --port $PORT & -``` - -### Using GraphiQL - -Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. - -- Navigate to `http://localhost:8080/`. -- To publish a blob, run the mutation: - -```gql,uri=http://localhost:8080/ -mutation { - publishDataBlob( - chainId: "$CHAIN_1", - bytes: [1, 2, 3, 4] - ) -} -``` - -Set the `QUERY_RESULT` variable to have the result returned by the previous query, and `BLOB_HASH` will be properly set for you. -Alternatively you can set the `BLOB_HASH` variable to the hash returned by the previous query yourself. - -```bash -BLOB_HASH=$(echo "$QUERY_RESULT" | jq -r '.publishDataBlob') -``` - -- Run `echo "http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID"` to print the URL to navigate to. -- To mint an NFT, run the mutation: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -mutation { - mint( - minter: "User:$OWNER_1", - name: "nft1", - blobHash: "$BLOB_HASH", - ) -} -``` - -- To check that it's assigned to the owner, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - ownedNfts(owner: "User:$OWNER_1") -} -``` - -Set the `QUERY_RESULT` variable to have the result returned by the previous query, and `TOKEN_ID` will be properly set for you. -Alternatively you can set the `TOKEN_ID` variable to the `tokenId` value returned by the previous query yourself. - -```bash -TOKEN_ID=$(echo "$QUERY_RESULT" | jq -r '.ownedNfts[].tokenId') -``` - -- To check that it's there, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - nft(tokenId: "$TOKEN_ID") { - tokenId, - owner, - name, - minter, - payload - } -} -``` - -- To check everything that it's there, run the query: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -query { - nfts -} -``` - -- To transfer the NFT to user `$OWNER_2`, still on chain `$CHAIN_1`, run the mutation: - -```gql,uri=http://localhost:8080/chains/$CHAIN_1/applications/$APP_ID -mutation { - transfer( - sourceOwner: "User:$OWNER_1", - tokenId: "$TOKEN_ID", - targetAccount: { - chainId: "$CHAIN_1", - owner: "User:$OWNER_2" - } - ) -} -``` - -### Using Web Frontend - -Installing and starting the web server: - -```bash -cd examples/non-fungible/web-frontend -npm install --no-save - -# Start the server but not open the web page right away. -BROWSER=none npm start & -``` - -```bash -echo "http://localhost:3000/$CHAIN_1?app=$APP_ID&owner=$OWNER_1&port=$PORT" -echo "http://localhost:3000/$CHAIN_1?app=$APP_ID&owner=$OWNER_2&port=$PORT" -``` - -For the final part, refer to [Fungible Token Example Application - Using web frontend](https://github.com/linera-io/linera-protocol/blob/main/examples/fungible/README.md#using-web-frontend). -*/ +/*! ABI of the Non-Fungible Token Example Application */ use std::fmt::{Display, Formatter}; diff --git a/examples/social/README.md b/examples/social/README.md index df455b2d750..b4dfea96633 100644 --- a/examples/social/README.md +++ b/examples/social/README.md @@ -1,5 +1,3 @@ - - # A Social Media Example Application This example illustrates how to use channels for cross-chain messages. @@ -24,6 +22,12 @@ message variants that are created when these operations are handled. The first t sent directly to the chain we want to subscribe to or unsubscribe from. The latter goes to the channel. + + ## Usage Set up the path and the helper function. @@ -187,5 +191,3 @@ query { } } ``` - - diff --git a/examples/social/src/lib.rs b/examples/social/src/lib.rs index 557fd0b98e4..502fab75d5e 100644 --- a/examples/social/src/lib.rs +++ b/examples/social/src/lib.rs @@ -1,202 +1,7 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 -#![allow(rustdoc::invalid_codeblock_attributes)] -// Using '=' in the documentation. - -// TODO the following documentation involves `sleep`ing to avoid some race conditions. See: -// - https://github.com/linera-io/linera-protocol/issues/1176 -// - https://github.com/linera-io/linera-protocol/issues/1177 - -/*! -# A Social Media Example Application - -This example illustrates how to use channels for cross-chain messages. - -For simplicity, each microchain represents one user—its owner. They can subscribe to other -users and make text posts that get sent to their subscribers. - -## How it Works - -The application's state on every microchain contains a set of posts created by this chain -owner, and a set of posts received from other chains that it has subscribed to. The -received posts are indexed by timestamp, sender and index. - -There are `Subscribe` and `Unsubscribe` operations: If a chain owner includes these in a -new block, they can subscribe to or unsubscribe from another chain. - -There is also a `Post` operation: It creates a new post and sends it to a channel, so that -it reaches all subscribers. - -There are corresponding `Subscribe`, `Unsubscribe` and `Posts` cross-chain -message variants that are created when these operations are handled. The first two are -sent directly to the chain we want to subscribe to or unsubscribe from. The latter goes -to the channel. - -## Usage - -Set up the path and the helper function. - -```bash -PATH=$PWD/target/debug:$PATH -source /dev/stdin <<<"$(linera net helper 2>/dev/null)" -``` - -Then, using the helper function defined by `linera net helper`, set up a local network -with two wallets and define variables holding their wallet paths (`$LINERA_WALLET_0`, -`$LINERA_WALLET_1`) and storage paths (`$LINERA_STORAGE_0`, `$LINERA_STORAGE_1`). - -```bash -linera_spawn_and_read_wallet_variables \ - linera net up \ - --extra-wallets 1 -``` - -Compile the `social` example and create an application with it: - -```bash -APP_ID=$(linera --with-wallet 0 project publish-and-create examples/social) -``` - -This will output the new application ID, e.g.: - -```ignore -e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65010000000000000000000000e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65030000000000000000000000 -``` - -With the `wallet show` command you can find the ID of the application creator's chain: - -```bash -linera --with-wallet 0 wallet show - -CHAIN_1=1db1936dad0717597a7743a8353c9c0191c14c3a129b258e9743aec2b4f05d03 -CHAIN_2=e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 -``` - -```ignore -e476187f6ddfeb9d588c7b45d3df334d5501d6499b3f9ad5595cae86cce16a65 -``` - -Now start a node service for each wallet, using two different ports: - -```bash -linera --with-wallet 0 service --port 8080 & - -# Wait for it to complete -sleep 2 - -linera --with-wallet 1 service --port 8081 & - -# Wait for it to complete -sleep 2 -``` - -Type each of these in the GraphiQL interface and substitute the env variables with their actual values that we've defined above. - -Point your browser to http://localhost:8081. This is the wallet that didn't create the -application, so we have to request it from the creator chain. As the chain ID specify the -one of the chain where it isn't registered yet: - -```gql,uri=http://localhost:8081 -mutation { - requestApplication( - chainId: "$CHAIN_1", - applicationId: "$APP_ID" - ) -} -``` - -Now in both http://localhost:8080 and http://localhost:8081, this should list the -application and provide a link to its GraphQL API. Remember to use each wallet's chain ID: - -```gql,uri=http://localhost:8081 -query { - applications( - chainId: "$CHAIN_1" - ) { - id - link - } -} -``` - -Open both URLs under the entry `link`. Now you can use the application on each chain. -For the 8081 tab, you can run `echo "http://localhost:8081/chains/$CHAIN_1/applications/$APP_ID"` -to print the URL to navigate to, then subscribe to the other chain using the following query: - -```gql,uri=http://localhost:8081/chains/$CHAIN_1/applications/$APP_ID -mutation { - subscribe( - chainId: "$CHAIN_2" - ) -} -``` - -Run `echo "http://localhost:8080/chains/$CHAIN_2/applications/$APP_ID"` to print the URL to navigate to, then make a post: - -```gql,uri=http://localhost:8080/chains/$CHAIN_2/applications/$APP_ID -mutation { - post( - text: "Linera Social is the new Mastodon!" - imageUrl: "https://linera.org/img/logo.svg" # optional - ) -} -``` - -Since 8081 is a subscriber. Let's see if it received any posts: # You can see the post on running the [web-frontend](./web-frontend/), or follow the steps below. - -```gql,uri=http://localhost:8081/chains/$CHAIN_1/applications/$APP_ID -query { receivedPosts { keys { timestamp author index } } } -``` - -This should now list one entry, with timestamp, author and an index. If we view that -entry, we can see the posted text as well as other values: - -```gql -query { - receivedPosts { - entry(key: { timestamp: 1705504131018960, author: "$CHAIN_2", index: 0 }) { - value { - key { - timestamp - author - index - } - text - imageUrl - comments { - text - chainId - } - likes - } - } - } -} -``` - -```json -{ - "data": { - "receivedPosts": { - "entry": { - "value": { - "key": { - "timestamp": 1705504131018960, - "author": "$CHAIN_2", - "index": 0 - }, - "text": "Linera Social is the new Mastodon!", - "imageUrl": "https://linera.org/img/logo.svg", - "comments": [], - "likes": 0 - } - } - } - } -} -``` -*/ +/*! ABI of the Social Media Example Application */ use async_graphql::{InputObject, Request, Response, SimpleObject}; use linera_sdk::{