Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Go to the Endless Release.
Download the appropriate zip file for your Ubuntu version.
Unzip the downloaded file.
Move the extracted Endless binary file, ie: endless into your preferred folder.
Open a terminal and navigate to your preferred folder.
Make endless an executable by running chmod +x endless.
Verify that this installed version works by running endless --help.
You should see instructions for how to use all CLI commands. These can be helpful in the future when you are trying to understand how to use specific commands.
(Optional) It can be helpful to add the Endless CLI to a folder in your PATH, or to add it to your PATH directly. The steps to add a folder to your PATH are shell dependent.
You can run echo $SHELL to print the default shell for your machine, then google specific steps to add a folder to your PATH for that shell.
The Endless command line interface (CLI) is a tool to help you compile and test Move contracts. It can also help you quickly play with Endless features on-chain.
For more advanced users, the CLI can also be used to run a private Endless network (to help test code locally) and can be helpful managing a network node.
Install the Endless CLI
Setup CLI configuration
Explore a use case:
Working With Move Contracts
Trying Things On-Chain
Running a Local Network
Managing a Network Node
Windows
Linux
Go to the Endless Release.
Download the appropriate zip file, ie: endless-cli-Windows-x86_64.zip.
Unzip the downloaded file.
Move the extracted Endless binary file, ie: endless.exe into your preferred folder.
Right click, then copy the path to the executable.
Ex. C:\Users\<username>\Downloads\endless.exe.
Open PowerShell via the Start Menu.
Verify the installation by running the help command.
Ex. C:\Users\<username>\Downloads\endless.exe --help.
The Endless command line interface (CLI) is a tool to help you compile and test Move contracts and quickly play with Endless features on-chain.
You can explore each of the use-cases here:
Working with Move Contracts
Trying things on-chain
Running a local Endless network
Managing a network node
The CLI can be a convenient tool for quickly looking up on-chain data and sending transactions from your accounts.
The most common way to specify what accounts you want to interact with is through profiles. You can create a new profile on the cli by running the following command:
endless init --profile <your-profile-name>If any command takes an account, you can pass in the name of a profile instead. If a command implicitly uses the default profile, it will usually have an optional parameter to use a specified profile instead which you can find by running endless <your-command> --help.
With that, the three main things you can use the CLI to do on-chain include:
Looking Up On-Chain Account Info
Creating test accounts and sending transactions
Securely interacting on-chain via a Hardware Ledger
In general, to make a new account on-chain, you will need to generate keys and then fund the account. On test networks, you can fund a new account by asking a "faucet" account with test Endless tokens to send them to your account.
Using the CLI, you can generate and fund a test account using:
Once you have a funded account you can send coins between accounts with the transfer command like this:
You should see a result like:
This can be useful for manual testing of Move contracts or just to try seeing how the chain works in practice.
Download the endless-cli-AliCloud3-x86_64.zip file and unzip the downloaded file.
Move the extracted Endless binary file, ie: endless into your preferred folder.
Open a terminal and navigate to your preferred folder.
Make endless an executable by running chmod +x endless.
Verify that this installed version works by running endless --help.
You should see instructions for how to use all CLI commands. These can be helpful in the future when you are trying to understand how to use specific commands.
(Optional) It can be helpful to add the Endless CLI to a folder in your PATH, or to add it to your PATH directly. The steps to add a folder to your PATH are shell dependent.
You can run echo $SHELL to print the default shell for your machine, then google specific steps to add a folder to your PATH for that shell.
Go to the Endless Release.
Download the appropriate zip file for your Ubuntu version.
Unzip the downloaded file.
Move the extracted Endless binary file, ie: endless into your preferred folder.
Open a terminal and navigate to your preferred folder.
Make endless an executable by running chmod +x endless.
Verify that this installed version works by running endless --help.
You should see instructions for how to use all CLI commands. These can be helpful in the future when you are trying to understand how to use specific commands.
(Optional) It can be helpful to add the Endless CLI to a folder in your PATH, or to add it to your PATH directly. The steps to add a folder to your PATH are shell dependent.
You can run echo $SHELL to print the default shell for your machine, then google specific steps to add a folder to your PATH for that shell.
Note however that addresses are different than keys.
endless init --profile <your-profile-name>endless account transfer --account superuser --amount 100gas_unit_price:100
gas_used:10
balance_changes:[]
sender:GinLHfukKufLYJ757NfyCLpeDvjeNjLPQwc7waco3o7b
success:true
version:26629
vm_status:Executed successfully
transaction_hash:3n9pVx1mW6cPdgXVCwj7kuRPYLfR4pbjRKtUZFNK6hC5If you are running a validator node or validator full node (VFN), you can use the CLI to interact with your node.
Specifically, you can use the CLI to:
Manage staking pools you own.
Vote on proposals.
Beyond that, you can run this help command to see more specialized commands the CLI can do relating to operating your node:
endless node --helpIf you are using the CLI to try things out on-chain, you will need to configure the network and credentials you want the CLI to use.
This makes using the CLI easier and more secure as you will not be forced to repeatedly copy addresses or private keys.
:::caution If you still need to install the CLI, follow these steps. :::
Run endless init and follow the instructions in the command line.
To use default settings, you can provide no input and just press "Enter". For example:
Later, if you want to update these settings, you can do so by running endless init again.
The rest of these configuration steps are optional / quality of life. To continue to use the CLI for your specific use case, follow the usage guide here.
For testing more complicated scenarios, you will often want multiple accounts on-chain. One way to do this is to create a named configuration which we call a profile.
To create a profile, run endless init --profile <name_of_profile>. The configuration you generate will be usable when calling CLI commands as replacements for arguments.
For example:
One quality of life feature you can enable is shell auto-completions.
Determine which shell you are using (you can run echo $SHELL if you are unsure).
Look up where configuration files for shell completions go for that shell (it varies from shell to shell). The supported shells are [bash, zsh, fish, PowerShell, elvish].
Run the following command with your specific shell and the output file for completions using your shell:
Example command for :
By default, the CLI will look for a configuration in .endless/config.yaml in each workspace directory. If you would like to use a shared configuration for all workspaces, you can follow these steps:
Create a folder in your home directory called .endless (so it has the path ~/.endless).
Create a yaml file inside .endless called global_config.yaml.
Run the command:
You should see:
If you’re interested in a specific type of account data, you can specify that with the --query parameter. The supported queries are:
balance - to see the current balance and a list of deposit and withdrawal events.
modules - see the Move contracts that are published on this account.
resources - this is what the default command does with no query specified.
Here’s an example of what calling with the --query modules parameter looks like:
endless account list --account <your-profile-name-or-account-address>[
0x1::account::Account:
authentication_key:[0xb9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb]
guid_creation_num:0
num_signatures_required:1
sequence_number:0
]endless init
Configuring for profile default
Choose network from [devnet, testnet, mainnet, local, custom | defaults to devnet]
No network given, using devnet...
Enter your private key as a hex literal (0x...) [Current: None | No input: Generate new key (or keep one if present)]
No key given, generating key...
Account 0xa2146cf381c6eb4bc82c6c4b78ee02ab63ab8f6825456e143ceb5e929a4c7c2d doesn't exist, creating it and funding it with 100000000 Veins
Account 0xa2146cf381c6eb4bc82c6c4b78ee02ab63ab8f6825456e143ceb5e929a4c7c2d funded successfully
---
Endless CLI is now set up for account 0xa2146cf381c6eb4bc82c6c4b78ee02ab63ab8f6825456e143ceb5e929a4c7c2d as profile default! Run `endless --help` for more information about commands
Successendless init --profile bob
...
...
Endless CLI is now set up for account 0x51024fd5e73c45de085b4c4f1d676273cd40578505364657df1ce14efbeba138 as profile bob!endless config generate-shell-completions --shell <YOUR_SHELL_HERE> --output-file <OUTPUT_DESTINATION_FOR_YOUR_SHELL>endless config generate-shell-completions --shell zsh --output-file ~/.oh-my-zsh/completions/_endlessendless config set-global-config --config-type globalconfig_type:Global
default_prompt_response:Promptendless account list --query modules --json
{
"Result": [
{
"bytecode": "0xa11ceb0b050000000b01000a020a12031c2504410405452d0772da0108cc0240068c030a0a9603150cab03650d90040400000101010201030104000506000006080004070700020e0401060100080001000009020300010f0404000410060100031107000002120709010602130a030106050806080105010802020c0a02000103040508020802070801010a0201060c010800010b0301090002070b030109000900074d657373616765056572726f72056576656e74067369676e657206737472696e67124d6573736167654368616e67654576656e740d4d657373616765486f6c64657206537472696e670b6765745f6d6573736167650b7365745f6d6573736167650c66726f6d5f6d6573736167650a746f5f6d657373616765076d657373616765156d6573736167655f6368616e67655f6576656e74730b4576656e7448616e646c65096e6f745f666f756e6404757466380a616464726573735f6f66106e65775f6576656e745f68616e646c650a656d69745f6576656e74b9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb0000000000000000000000000000000000000000000000000000000000000001030800000000000000000002020a08020b08020102020c08020d0b030108000001000101030b0a002901030607001102270b002b0110001402010104010105240b0111030c040e0011040c020a02290120030b05120e000b040e00380012012d0105230b022a010c050a051000140c030a050f010b030a04120038010b040b050f0015020100010100",
"abi": {
"address": "0xb9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb",
"name": "Message",
"friends": [],
"exposed_functions": [
{
"name": "get_message",
"visibility": "public",
"is_entry": false,
"generic_type_params": [],
"params": [
"address"
],
"return": [
"0x1::string::String"
]
},
{
"name": "set_message",
"visibility": "public",
"is_entry": true,
"generic_type_params": [],
"params": [
"signer",
"vector<u8>"
],
"return": []
}
],
"structs": [
{
"name": "MessageChangeEvent",
"is_native": false,
"abilities": [
"drop",
"store"
],
"generic_type_params": [],
"fields": [
{
"name": "from_message",
"type": "0x1::string::String"
},
{
"name": "to_message",
"type": "0x1::string::String"
}
]
},
{
"name": "MessageHolder",
"is_native": false,
"abilities": [
"key"
],
"generic_type_params": [],
"fields": [
{
"name": "message",
"type": "0x1::string::String"
},
{
"name": "message_change_events",
"type": "0x1::event::EventHandle<0xb9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb::Message::MessageChangeEvent>"
}
]
}
]
}
}
]
}The endless tool supports bootstrapping new blockchains through what is known as a genesis ceremony. The output of the genesis ceremony is the output of move instructions that prepares a blockchain for online operation. The input consists of:
A set of validators and their configuration
The initial set of Move modules, known as a framework
A unique ChainId (u8) that distinguishes this from other networks
For test chains, there also exists an account that manages the minting of EndlessCoin
The genesis organizer constructs a Layout and distributes it.
The genesis organizer prepares the Endless framework's bytecode and distributes it.
Each participant generates their ValidatorConfiguration and distributes it.
endless-coreThe following sections rely on tools from the Endless source. See Building Endless From Source for setup.
The layout file
The layout file contains:
root_key: an Ed25519 public key for EndlessCoin management.
users: the set of participants
chain_id: the ChainId or a unique integer that distinguishes this deployment from other Endless networks
An example:
From your Endless repository, build the framework and package it:
The framework will be stored within the endless-framework-release directory.
The ValidatorConfiguration file
The ValidatorConfiguration file contains:
account_address: The account that manages this validator. This must be derived from the account_key provided within the ValidatorConfiguration file.
consensus_key: The public key for authenticating consensus messages from the validator
account_key
An example:
To generate this using the endless CLI:
Generate your validator's keys:
Generate your ValidatorConfiguration:
The last command will produce a bob.yaml file that should be distributed to other participants for genesis.blob generation.
genesis.blob and the waypoint can be generated after obtaining the layout file, each of the individual ValidatorConfiguration files, and the framework release. It is important to validate that the ValidatorConfiguration provided in the earlier stage is the same as in the distribution for generating the genesis.blob. If there is a mismatch, inform all participants.
To generate the genesis.blob and waypoint:
Place the layout file in a directory, e.g., genesis.
Place all the ValidatorConfiguration files into the genesis directory.
Ensure that the ValidatorConfiguration files are listed under the set of
endless-nodeUpon generating the genesis.blob and waypoint, place them into your validator and fullnode's configuration directory and begin your validator and fullnode.
Local networks can be helpful when testing your code. They are not connected to any production Endless networks like mainnet, but they are useful for three main reasons:
No rate limits: You can interact with hosted services like the Node API, Indexer API, and faucet with no rate-limits to speed up testing.
genesis.blob from the resulting contributions.The genesis organizer executes the genesis.blob to derive the initial waypoint and distributes it.
Each participant begins their endless-node. The endless-node verifies upon startup that the genesis.blob with the waypoint provided by the genesis organizer.
The blockchain will begin consensus after a quorum of stake is available.
account_addressnetwork_key: The public key for both validator and fullnode network authentication and encryption.
validator_host: The network address where the validator resides. This contains a host and port field. The host should either be a DNS name or an IP address. Currently only IPv4 is supported.
full_node_host: An optional network address where the fullnode resides. This contains a host and port field. The host should either be a DNS name or an IP address. Currently only IPv4 is supported.
stake_amount: The number of coins being staked by this node. This is expected to be 1, if it is different the configuration will be considered invalid.
userslayoutMake a framework directory within the genesiss directory and place the framework release .mv files into the framework directory.
Use the endless CLI to generate genesis and waypoint:
Reproducibility: You can set up specific on-chain scenarios and restart the network from scratch at any point to return to a clean slate.
High availability: The Endless devnet and testnet networks are periodically upgraded, during which time they can be unavailable. Local development networks are also always available even if you have no internet access.
Ensure you have the Endless CLI installed.
Ensure you have Docker installed.
This is exclusively needed for making a production-like environment by running the Indexer API. Many downstream tools such as the Endless SDK depend on the Indexer API.
Docker recommends that you install via Docker Desktop to get automatic updates.
Start Docker.
Run the following command in a new terminal to start the private network:
You should expect to see an output similar to this:
Wait for the final line Setup is complete, you can now use the localnet!
:::caution If you ran into an error, jump to the Common Errors section below. :::
As you can see from the above example output, once the local network is running, you have access to the following services:
Node API: This is a REST API that runs directly on the node. It enables core write functionality such as transaction submission and a limited set of read functionality, such as reading account resources or Move module information.
Transaction Stream Service: This is a gRPC stream of transactions used by the Indexer API. This is only relevant to you if you are developing a custom processor.
If you do not want to run any of these sub-components of a network, there are flags to disable them.
If you are writing a script and would like to wait for the local network to come up with all services, you can make a GET request to http://127.0.0.1:8070. At first this will return http code 503. When it returns 200 it means all the services are ready.
For more information on different flags you can pass when starting your local network, or configuration settings such as changing which port certain services run on, run the help command:
Address Already In Use
This means one of the ports needed by the local network is already in use by another process.
To fix this on Unix systems, you can:
Identify the name and PID of the process by running lsof -i :8080.
Run kill <pid> once you know the PID to free up that port.
Too many open files error
This means there were too many open files on your system. On many Unix systems you can increase the maximum number of open files by adding something like this to your .zshrc:
Docker is not available
To debug this, try the below fixes:
Make sure you have docker installed by running docker --version.
Ensure the Docker daemon is running by running docker info (if this errors saying Cannot connect to the Docker daemon Docker is NOT running)
Make sure the socket for connecting to Docker is present on your machine in the default location. For example, on Unix systems /var/run/docker.sock should exist.
If that file does not exist, open Docker Desktop and enable Settings -> Advanced -> Allow the default Docker socket to be used.
Or, you can find where the Docker socket is by running docker context inspect | grep Host, then symlink that location to the default location by running sudo ln -s /Users/dport/.docker/run/docker.sock /var/run/docker.sock
Now that the network is running, you can use it like you would any other network.
So, you can create a local profile like this:
You can then use that profile for any commands you want to use going forward. For example, if you wanted to publish a Move module like the hello_blockchain package to your local network you could run:
Configuring the TypeScript SDK
If you want to use the local network with the TypeScript SDK, you can use local network URLs when initializing the client object (Endless):
Resetting the local network
Sometimes while developing it is helpful to reset the local network back to its initial state, for example:
You made backwards incompatible changes to a Move module, and you'd like to redeploy it without renaming it or using a new account.
You are building a custom indexer processor and would like to index using a fresh network.
You want to clear all on chain state, e.g. accounts, objects, etc.
To start with a brand new local network, use the --force-restart flag:
It will then prompt you if you really want to restart the chain, to ensure that you do not delete your work by accident.
If you do not want to be prompted, include --assume-yes as well:
root_key: "0xca3579457555c80fc7bb39964eb298c414fd60f81a2f8eedb0244ec07a26e575"
users:
- alice
- bob
chain_id: 8cargo run --package framework
mkdir endless-framework-release
cp endless-framework/releases/artifacts/current/build/**/bytecode_modules/* endless-framework-releaseaccount_address: ccd49f3ea764365ac21e99f029ca63a9b0fbfab1c8d8d5482900e4fa32c5448a
consensus_key: "0xa05b8f41057ac72f9ca99f5e3b1b787930f03ba5e448661f2a1fac98371775ee"
account_key: "0x3d15ab64c8b14c9aab95287fd0eb894aad0b4bd929a5581bcc8225b5688f053b"
network_key: "0x43ce1a4ac031b98bb1ee4a5cd72a4cca0fd72933d64b22cef4f1a61895c2e544"
validator_host:
host: bobs_host
port: 6180
full_node_host:
host: bobs_host
port: 6182
stake_amount: 1cargo run --package endless -- genesis generate-keys --output-dir bobscargo run --package endless -- \\
genesis set-validator-configuration \\
--keys-dir bobs \\
--username bob \\
--validator-host bobs_host:6180 \\
--full-node-host bobs_host:6180 \\
--local-repository-dir .cargo run --package endless -- genesis generate-genesis --local-repository-dir genesisendless node run-local-testnetIdentified node type (Validator) and chain ID (Some(testing)) from node config!
Readiness endpoint: http://0.0.0.0:8070/
Transaction stream is starting, please wait...
Node API is starting, please wait...
Completed generating configuration:
Log file: "/Users/dport/.endless/testnet/validator.log"
Test dir: "/Users/dport/.endless/testnet"
Endless root key path: "/Users/dport/.endless/testnet/mint.key"
Waypoint: 0:a7ee6363f24362a6ab7362558b7f0d2e63be78b19a73d3a8c1f5697f65aa1ac1
ChainId: 223
REST API endpoint: http://0.0.0.0:8080
Metrics endpoint: http://0.0.0.0:9101/metrics
Endlessnet fullnode network endpoint: /ip4/0.0.0.0/tcp/6181
Indexer gRPC node stream endpoint: 0.0.0.0:50051
Endless is running, press ctrl-c to exit
Node API is ready. Endpoint: http://0.0.0.0:8080/
Transaction stream is ready. Endpoint: http://0.0.0.0:50051/
Applying post startup steps...
Setup is complete, you can now use the local testnet!endless node run-local-testnet --helppanicked at 'error binding to 0.0.0.0:8080: error creating server listener: Address already in use (os error 48)panicked at crates/endless/src/node/local_testnet/logging.rs:64:10:
called `Result::unwrap()` on an `Err` value: Os { code: 24, kind: Uncategorized, message: \"Too many open files\" }"""ulimit -n 32768Unexpected error: Failed to apply pre-run steps for Postgres: Docker is not available, confirm it is installed and running. On Linux you may need to use sudoendless init --profile <your-profile-name> --network localendless move publish --profile <your-profile-name> --package-dir /opt/git/endless-core/endless-move/move-examples/hello_blockchain --named-addresses HelloBlockchain=localimport { Endless, EndlessConfig, Network } from "@endless-labs/ts-sdk";
const network = Network.LOCAL;
const config = new EndlessConfig({ network });
const client = new Endless(config);endless node run-local-testnet --force-restartAre you sure you want to delete the existing chain? [yes/no]
> yesendless node run-local-testnet --force-restart --assume-yesThe Endless CLI is mostly used to compile, test, and formally verify Move contracts. If you have not installed the Endless CLI yet, you can do so by following the steps here Install the Endless CLI.
You can jump to sections here:
Compiling Move
Unit Testing Move Contracts
Generating Test Coverage Reports
Publishing Move Contracts
Running Published Contracts
(Optional) Formally Verifying Move Scripts
To see how to chain together Move contracts on-chain using the CLI, you can follow this "CLI Arguments" tutorial.
You can compile a Move package by running:
Based on the settings in your Move.toml file, you may need to pass in additional information to that compile command.
For example, if you look at the , in the Move.toml file it specifies a variable named address called hello_blockchain.
So, to compile this, you will need to pass in the value for hello_blockchain with the --named-addresses parameter.
You can learn more about optional parameters when compiling Move contracts by running endless move compile --help.
The Endless CLI can also be used to compile and run unit tests locally by running:
This command both compiles and runs tests, so it needs all the same optional parameters you use when compiling.
You can learn more about the optional parameters for testing move contracts by running endless move test --help.
Printing Debugging Information
When writing tests, it can be helpful to print out debug information or stack traces. You can do that by using debug::print and debug::print_stack_trace to print information when you use endless move test. See an example of how they are used in .
To see the output of testing ’s package:
Clone .
Navigate to the by running cd crates/endless/debug-move-example.
Run endless move test.
You should see:
For more on how to write unit tests with Move, follow this .
The Endless CLI can be used to analyze and improve the testing of your Move modules. To use this feature:
To see the code coverage of your tests run the following command from your Move package’s directory:
If you would like to focus your coverage down to specific packages, you can do so with the --filter option. To narrow even further to specific Move modules, use the --module parameter.
For more detailed / advanced coverage information (such as your test coverage in the compiled bytecode) you can run endless move coverage . With that command, the CLI will prompt you for more details on what specifically you would like more coverage information about.
You can learn more about optional parameters for test coverage by running endless move test --help and endless move coverage --help.
To publish a Move contract, you will need to run:
Note that when you are publishing on the main network, the credentials you pass into optional parameters like --named-addresses will need to reflect accounts on that network instead of test credentials.
The package will be published to your default profile in the CLI. You can override that to specify which account to publish to using --profile in the command. To generate a new profile for a specific account, use endless init --profile <name_of_profile> and follow the prompts.
Please also note that when publishing Move modules, if multiple modules are in one package, then all modules in that package must use the same account. If they use different accounts, then the publishing will fail at the transaction level.
You can estimate the gas fees associated with publishing your Move contract by using the Gas Profiler.
:::caution By default Move contracts publish their source code. To avoid publishing with source code, publish with the --included-artifacts none argument.
Since the Endless blockchain is inherently open by design, note that even without source access it is possible to regenerate Move source from published Move bytecode. :::
Now that you have published your Move package, you can run it directly from the CLI.
You will first need to construct your function-id by combining:
You can then pass in args by using the --args parameter.
As an example, if you were to have published the to an account with an address b9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb you could run its set_message function via the following command:
Which should result in:
For cases where you want to guarantee that your code works as expected beyond unit testing, you can use the Move Prover to formally verify your Move contract code.
Once you have installed the Move Prover, you can use it from the Endless CLI by running:
To learn how to formally verify your code, please follow the in-depth Move tutorial (step 7 and 8 cover how to use the Move Prover and write formal specifications in the example code).
endless move compile --package-dir <your-package-directory>[addresses]
hello_blockchain = "_"endless move compile \
--package-dir endless-move/move-examples/hello_blockchain/ \
--named-addresses hello_blockchain=superuserendless move test --package-dir <your-package-directory>Running Move unit tests
[debug] 0000000000000000000000000000000000000000000000000000000000000001
Call Stack:
[0] 0000000000000000000000000000000000000000000000000000000000000001::Message::sender_can_set_message
Code:
[4] CallGeneric(0)
[5] MoveLoc(0)
[6] LdConst(0)
> [7] Call(1)
[8] Ret
Locals:
[0] -
[1] 0000000000000000000000000000000000000000000000000000000000000001
Operand Stack:endless move test --coverageendless move publish --package-dir <your-package-directory><the-address-you-published-to>::<module_name>::<function_name>endless move run --function-id 0xb9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb::message::set_message --args string:hello!{
"Result": {
"changes": [
{
"address": "b9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb",
"data": {
"authentication_key": "0xb9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb",
"self_address": "0xb9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb",
"sequence_number": "3"
},
"event": "write_resource",
"resource": "0x1::account::Account"
},
{
"address": "b9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb",
"data": {
"coin": {
"value": "9777"
},
"deposit_events": {
"counter": "1",
"guid": {
"id": {
"addr": "0xb9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb",
"creation_num": "1"
}
}
},
"withdraw_events": {
"counter": "1",
"guid": {
"id": {
"addr": "0xb9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb",
"creation_num": "2"
}
}
}
},
"event": "write_resource",
"resource": "0x1::coin::CoinStore<0x1::endless_coin::EndlessCoin>"
},
{
"address": "b9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb",
"data": {
"counter": "4"
},
"event": "write_resource",
"resource": "0x1::guid::Generator"
},
{
"address": "b9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb",
"data": {
"message": "hello!",
"message_change_events": {
"counter": "0",
"guid": {
"id": {
"addr": "0xb9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb",
"creation_num": "3"
}
}
}
},
"event": "write_resource",
"resource": "0xb9bd2cfa58ca29bce1d7add25fce5c62220604cd0236fe3f90d9de91ed9fb8cb::Message::MessageHolder"
}
],
"gas_used": 41,
"success": true,
"version": 3488,
"vm_status": "Executed successfully"
}
}endless move prove --package-dir <your-package-directory>This section references the CliArgs example package, which contains the following manifest:
Here, the package is deployed under the named address test_account.
Start by mining a vanity address for Ace, who will deploy the package:
Store Ace's address in a shell variable, so you can call it inline later on:
Fund Ace's account with the faucet (either devnet or testnet):
Now publish the package under Ace's account:
The only module in the package, cli_args.move, defines a simple Holder resource with fields of various data types:
A public entry function with multi-nested vectors can be used to set the fields:
After the package has been published, endless move run can be used to call set_vals():
The function ID, type arguments, and arguments can alternatively be specified in a JSON file: move-examples/cli_args/entry_function_arguments.json
Here, the call to endless move run looks like:
Once the values in a Holder have been set, the reveal() view function can be used to check the first three fields, and to compare type arguments against the last two fields:
This view function can be called with arguments specified either from the CLI or from a JSON file:
Output:
The package also contains a script, set_vals.move, which is a wrapper for the setter function:
First compile the package (this will compile the script):
Next, run endless move run-script Arguments via CLI
Arguments via JSON file
script_function_arguments.json
Both such script function invocations result in the following reveal() view function output:
Output:
[package]
name = "CliArgs"
version = "0.1.0"
upgrade_policy = "compatible"
[addresses]
test_account = "_"
[dependencies.EndlessFramework]
local = "../../framework/endless-framework"cd <endless-core-parent-directory>/endless-core/endless-move/move-examples/cli_argsendless key generate \
--vanity-prefix 0xace \
--output-file ace.key# Your exact address should vary
ace_addr=0xacef1b9b7d4ab208b99fed60746d18dcd74865edb7eb3c3f1428233988e4ba46endless account fund-with-move --account $ace_addr --private-key-file ace.keyendless move publish \
--named-addresses test_account=$ace_addr \
--private-key-file ace.key \
--assume-yesstruct Holder has key, drop {
u8_solo: u8,
bytes: vector<u8>,
utf8_string: String,
bool_vec: vector<bool>,
address_vec_vec: vector<vector<address>>,
type_info_1: TypeInfo,
type_info_2: TypeInfo,
}public entry fun set_vals<T1, T2>(
account: signer,
u8_solo: u8,
bytes: vector<u8>,
utf8_string: String,
bool_vec: vector<bool>,
address_vec_vec: vector<vector<address>>,
) acquires Holder {
let account_addr = signer::address_of(&account);
if (exists<Holder>(account_addr)) {
move_from<Holder>(account_addr);
};
move_to(&account, Holder {
u8_solo,
bytes,
utf8_string,
bool_vec,
address_vec_vec,
type_info_1: type_info::type_of<T1>(),
type_info_2: type_info::type_of<T2>(),
});
}endless move run \
--function-id $ace_addr::cli_args::set_vals \
--type-args \
0x1::account::Account \
0x1::chain_id::ChainId \
--args \
u8:123 \
"hex:0x1234" \
"string:hello, world\! ♥" \
"bool:[false, true, false, false]" \
'address:[["0xace", "0xbee"], ["0xcad"], []]' \
--private-key-file ace.key \
--assume-yes{
"function_id": "<test_account>::cli_args::set_vals",
"type_args": [
"0x1::account::Account",
"0x1::chain_id::ChainId"
],
"args": [
{
"type": "u8",
"value": 123
},
{
"type": "hex",
"value": "0x1234"
},
{
"type": "string",
"value": "hello, world! ♥"
},
{
"type": "bool",
"value": [
false,
true,
false,
false
]
},
{
"type": "address",
"value": [
[
"0xace",
"0xbee"
],
[
"0xcad"
],
[]
]
}
]
}endless move run \
--json-file entry_function_arguments.json \
--private-key-file ace.key \
--assume-yesstruct RevealResult has drop {
u8_solo: u8,
bytes: vector<u8>,
utf8_string: String,
bool_vec: vector<bool>,
address_vec_vec: vector<vector<address>>,
type_info_1_match: bool,
type_info_2_match: bool
}
#[view]
/// Pack into a `RevealResult` the first three fields in host's
/// `Holder`, as well as two `bool` flags denoting if `T1` & `T2`
/// respectively match `Holder.type_info_1` & `Holder.type_info_2`,
/// then return the `RevealResult`.
public fun reveal<T1, T2>(host: address): RevealResult acquires Holder {
let holder_ref = borrow_global<Holder>(host);
RevealResult {
u8_solo: holder_ref.u8_solo,
bytes: holder_ref.bytes,
utf8_string: holder_ref.utf8_string,
bool_vec: holder_ref.bool_vec,
address_vec_vec: holder_ref.address_vec_vec,
type_info_1_match:
type_info::type_of<T1>() == holder_ref.type_info_1,
type_info_2_match:
type_info::type_of<T2>() == holder_ref.type_info_2
}
}endless move view \
--function-id $ace_addr::cli_args::reveal \
--type-args \
0x1::account::Account \
0x1::account::Account \
--args address:$ace_addrendless move view --json-file view_function_arguments.json{
"function_id": "<test_account>::cli_args::reveal",
"type_args": [
"0x1::account::Account",
"0x1::account::Account"
],
"args": [
{
"type": "address",
"value": "<test_account>"
}
]
}{
"Result": [
{
"address_vec_vec": [
[
"0xace",
"0xbee"
],
[
"0xcad"
],
[]
],
"bool_vec": [
false,
true,
false,
false
],
"bytes": "0x1234",
"type_info_1_match": true,
"type_info_2_match": false,
"u8_solo": 123,
"utf8_string": "hello, world! ♥"
}
]
}script {
use test_account::cli_args;
use std::vector;
use std::string::String;
/// Get a `bool` vector where each element indicates `true` if the
/// corresponding element in `u8_vec` is greater than `u8_solo`.
/// Then pack `address_solo` in a `vector<vector<<address>>` and
/// pass resulting argument set to public entry function.
fun set_vals<T1, T2>(
account: signer,
u8_solo: u8,
bytes: vector<u8>,
utf8_string: String,
u8_vec: vector<u8>,
address_solo: address,
) {
let bool_vec = vector::map_ref(&u8_vec, |e_ref| *e_ref > u8_solo);
let addr_vec_vec = vector[vector[address_solo]];
cli_args::set_vals<T1, T2>(account, u8_solo, bytes, utf8_string, bool_vec, addr_vec_vec);
}
} endless move compile --named-addresses test_account=$ace_addrendless move run-script \
--compiled-script-path build/CliArgs/bytecode_scripts/set_vals.mv \
--type-args \
0x1::account::Account \
0x1::chain_id::ChainId \
--args \
u8:123 \
"hex:0x1234" \
"string:hello, world\! ♥" \
"u8:[122, 123, 124, 125]" \
address:"0xace" \
--private-key-file ace.key \
--assume-yesendless move run-script \
--compiled-script-path build/CliArgs/bytecode_scripts/set_vals.mv \
--json-file script_function_arguments.json \
--private-key-file ace.key \
--assume-yes{
"type_args": [
"0x1::account::Account",
"0x1::chain_id::ChainId"
],
"args": [
{
"type": "u8",
"value": 123
},
{
"type": "hex",
"value": "0x1234"
},
{
"type": "string",
"value": "hello, world! ♥"
},
{
"type": "u8",
"value": [
122,
123,
124,
125
]
},
{
"type": "address",
"value": "0xace"
}
]
}endless move view \
--function-id $ace_addr::cli_args::reveal \
--type-args \
0x1::account::Account \
0x1::chain_id::ChainId \
--args address:$ace_addr{
"Result": [
{
"address_vec_vec": [["0xace"]],
"bool_vec": [false, false, true, true],
"bytes": "0x1234",
"type_info_1_match": true,
"type_info_2_match": true,
"u8_solo": 123,
"utf8_string": "hello, world! ♥"
}
]
}