# Pontem Product Development Studios

![Pontem x Aptos](/files/pztyfdvHsyWe2yOuMisE)

Pontem is a product development studio working toward global financial inclusion powered by blockchains. We are partnered with Aptos to build foundational dApps and other infrastructure which enable adoption of their L1, such as development tooling, EVMs, AMMs, and more. The Move IntelliJ IDE and Move Playground are just the beginning.

The burgeoning ecosystem of Move-based, inclusion-focused infrastructure is where Pontem has a competitive advantage. Over the past four years, our team has developed deep expertise in Move. After working firsthand with the tech developed by Meta and Diem engineers, we knew we had to be ‘first Movers’ on developing a Move Virtual Machine to expand the reach of this incredible technology. Our skill set encompasses the essential building blocks for modern blockchain development and we feel we are not just well-positioned for the future, but also in a unique position to build it. Given this unique position we are in, we will create the first product development studios for the Aptos Blockchain across 3 key verticals: protocols, developer tooling and infrastructure. With our skills and experience, we will help grow and develop this nascent ecosystem and capture value across the technology stack by building core primitive dApps necessary for the Aptos L1 to be used by billions of people. We will work with incumbent dApps, infrastructure providers and L1s to help them transition to Move. Where we identify market gaps, we will build the core elements ourselves and make upgrades that stay up to date with innovation.

### Application protocols

We are going to first build the next generation of dApps with streamlined experiences enabled by Aptos and Move. This will fuel mainstream adoption globally for both customers and institutions. Starting with the key foundational protocol of an AMM for correlated and uncorrelated pairs. This will enable liquidity and discoverability for protocol tokens in the Aptos ecosystem.

### Developer tooling

Learning a new language can be a difficult aspect of building a blockchain application, but Pontem believes their future suite of developer tools will streamline adoption. All tools are free to use.

### Infrastructure

We have already developed a fork of the Diem Move Virtual Machine which can be readily deployed to other modern chains like Polkadot, Cosmos, Avalanche, and more. Our goal is for Move to flourish, so we plan to deploy in the future as the Move dApp ecosystem matures and the need grows for Move environments in other L1s. We will also research developing a new Ethereum VM that is compatible with the Move VM to connect the two technologies and allow dApp developers to enjoy all of Move’s benefits. This will allow them to migrate gradually and carefully, without the risk and expense of doing it in one monolithic app, and be the standard for migrating to Move VM deployments from Solidity on all L1s.

We are also making the Move VM compatible with legacy virtual machines like the EVM in order to enable easy deployment with a Solidity or Vyper codebase.


# Team

The Pontem Team has a long and established reputation in the blockchain industry, having previously developed the DPoS DApp Crypti in 2014, founded the Wings DAO platform in 2016 and more recently in the last 2 years built the Dfinance project, a decentralized infrastructure dedicated to various financial and DeFi instruments and products designed for non technical people.

We will partner with Aptos to prioritize a roadmap of dApps exclusively deployed on the Aptos Blockchain with technical support from the Aptos team. This collaboration enables the success of native Move-based dApps on the Aptos Blockchain and strengthens the ecosystem for developers and users. You can read more about the partnership here.

### Leadership

![Team](/files/hFqowtVfHd8Do3QKr9RC)


# Introduction

:exclamation:*You are reviewing an outdated version of the Pontem Wallet documentation! We recommend switching to the most recent version from the new* [*official website*](https://docs.pontemwallet.xyz/)! :warning:<br>

![Pontem Wallet](/files/eoaSpYY2IP7VaTq9a4wg)

Welcome to the Pontem Wallet documentation. With this documentation, you will understand how to integrate Pontem Wallet into your web page and how to interact with it.

## Extension

[![](https://badgen.net/chrome-web-store/v/phkbamefinggmakgklpkljjmgibohnba?label=Chrome%20Web%20Store)](https://badgen.net/chrome-web-store/v/phkbamefinggmakgklpkljjmgibohnba?label=Chrome%20Web%20Store) [![](https://badgen.net/github/release/pontem-network/pontem-wallet?label=GitHub)](https://badgen.net/github/release/pontem-network/pontem-wallet?label=GitHub)

You can find the current version of the wallet in the [Google Chrome Store](https://chrome.google.com/webstore/detail/pontem-wallet/phkbamefinggmakgklpkljjmgibohnba) and newest version in the [Github](https://github.com/pontem-network/pontem-wallet/releases).

[![Download From Chrome Store](/files/ZeB106ZfMqgeFZjt2g3y)](https://chrome.google.com/webstore/detail/pontem-wallet/phkbamefinggmakgklpkljjmgibohnba) [![Download From Github](/files/uEUfCH2GSCvIEqbaWO7b)](https://github.com/pontem-network/pontem-wallet/releases).

To have all recent changes and bug fixes use Github version as it takes time to reach Chrome Store due to Google Review policy.


# Getting Started

:exclamation:*You are reviewing an outdated version of the Pontem Wallet documentation! We recommend switching to the most recent version from the new* [*official website*](https://docs.pontemwallet.xyz/)! :warning:<br>

## Getting Started

Use the v1.3.0 or higher version of Pontem Wallet to go through the current docs.

### Wallets Adapter

If you want to use [Aptos Wallet Adapter](https://github.com/hippospace/aptos-wallet-adapter), navigate to the [Wallet Adapter documentation](/01.-wallet/wallet_adapter) and skip the current doc.

#### Provider Browser Detection

When the page is loaded, the provider is integrated into the site page. You can check it this way:

```javascript
if (typeof window.pontem !== 'undefined') {
  console.log('Pontem Wallet is installed!');
}
```

After that, you need to request access to the site from the user, for this use the connect method:

```javascript
window.pontem.connect()
    .then(address => console.log(`Access for address ${address} allowed by user`))
    .catch(e => console.log('Access denied by user', e))
```

After that, you can fully interact with all wallet methods.


# API Reference

:exclamation:*You are reviewing an outdated version of the Pontem Wallet documentation! We recommend switching to the most recent version from the new* [*official website*](https://docs.pontemwallet.xyz/)! :warning:<br>

### API Reference

#### Extension Version

To get the installed extension version, use the following code.

```javascript
const extensionVersion = window.pontem.version;
console.log(`Pontem Wallet v${extensionVersion}`); // 2.0.0
```

#### Connect

For the initial connection to the wallet, use the connect method. It requests access to the site from the user and returns the current account address. If you already have access to the site, it will also return the current account address.

```javascript
window.pontem.connect()
  .then(address => console.log(`Access for address ${address} allowed by user`))
  .catch(e => console.log('Access denied by user', e))
```

#### Check Connection Status ![API Check Connection Status](https://badgen.net/badge/included%20in/%3E=1.5.0)

To check if any wallet is connected to the page, use the `isConnected` method.

```javascript
window.pontem.isConnected()
  .then(result => {
    console.log('isConnected', result) // true or false
  })
  .catch(e => console.log('Error', e))
```

#### Disconnecting ![API Disconnecting](https://badgen.net/badge/included%20in/%3E=1.5.0)

To disconnect the current account from the site, use the `disconnect` method.

> Important: all methods that require permission from the user will stop working, but the entry in the "Connected Sites" list of the account will not disappear. Only the user can remove access completely through the UI.\
> If you call the `disconnect()` method and then `connect()`, the user will not be asked for permission again. This will only happen if the user manually removes access through the UI

```javascript
window.pontem.disconnect()
  .catch(e => console.log('Error', e))
```

#### Change Active Account Event

To keep track of when a user changed their account, use the `onChangeAccount` method. When the account is changed, it calls the method you passed in the first argument. If the user at some point revokes the extension's access to the site, then this method will also be called.

```javascript
window.pontem.onChangeAccount((address) => {
  if(address) {
    console.log('New selected account: ', address);
  } else {
    console.log('The user has selected an account that is not allowed to access');
  }
})
```

#### Change Active Network Event ![API Change Active Network Event](https://badgen.net/badge/included%20in/%3E=1.6.0)

To keep track of when a user changed network, use the `onChangeNetwork` method. When the network is changed, it calls the method you passed in the first argument.

```javascript
window.pontem.onChangeNetwork((network) => {
  console.log(network);
  // { api: 'https://fullnode.devnet.aptoslabs.com/v1/', chainId: '31', name: 'Aptos devnet' }
})
```

#### Get Current Network ![API Get Current Network](https://badgen.net/badge/included%20in/%3E=1.6.0)

To get the current connected network, use the `network` method.

```javascript
window.pontem.network()
  .then(network => {
    console.log(network);
    // { api: 'https://fullnode.devnet.aptoslabs.com/v1/', chainId: '31', name: 'Aptos devnet' }
  })
```

#### Get Current ChainId ![API Get Current Network](https://badgen.net/badge/included%20in/%3E=1.6.0)

To get the current chainId, use the `chainId` method.

```javascript
window.pontem.chainId()
  .then(chainId => {
    console.log(chainId); // 31
  })
```

#### Get Current Account

To get the address of the current account, use the `account` method.

```javascript
window.pontem.account()
  .then(address => {
    if(address) {
      console.log('Account address: ', address);
    } else {
      console.log('The user has selected an account that is not allowed to access');
    }
  })
```

#### Get Public Key of the Current Account ![API Get Public Key](https://badgen.net/badge/included%20in/%3E=1.5.0)

To get the public key of the current account , use the `publicKey` method.

```javascript
window.pontem.publicKey()
  .then(key => {
    console.log('Public key: ', key);
  })
```

#### Sign and Submit Transaction

To request a signature and send a transaction to the blockchain, use the `signAndSubmit` method.

`payload` - mandatory parameter containing the transaction body.\
`otherOptions` - optional parameter that overrides transaction parameters.

> Included in >=1.7.0.\
> You can also pass a UInt8Array as transaction arguments, or an array with a `UInt8Array`. This forms a vector, or a vector of vectors.

```javascript
const payload = {
  function: "0x1::coin::transfer",
  type_arguments: ["0x1::aptos_coin::AptosCoin"],
  arguments: ["0xeb442855143ce3e26babc6152ad98e9da7db7f0820f08be3d006535b663a6292", "1000"]
};
const otherOptions = {
  max_gas_amount: '1000',
  gas_unit_price: '1',
  expiration_timestamp_secs: '1646793600',
  sequence_number: '10'
}
window.pontem.signAndSubmit(payload, otherOptions)
  .then(tx => {
    console.log('Transaction', tx)
  })
  .catch(e => console.log('Error', e))
```

#### Sign Transaction ![API Sign Transaction](https://badgen.net/badge/included%20in/%3E=1.4.0)

To request a signature of transaction, use the `signTransaction` method.

`payload` - mandatory parameter containing the transaction body.\
`otherOptions` - optional parameter that overrides transaction parameters.

You can also pass a UInt8Array as transaction arguments, or an array with a `UInt8Array`. This forms a vector, or a vector of vectors.

```javascript
const payload = {
  function: "0x1::coin::transfer",
  type_arguments: ["0x1::aptos_coin::AptosCoin"],
  arguments: ["0xeb442855143ce3e26babc6152ad98e9da7db7f0820f08be3d006535b663a6292", "1000"]
};
const otherOptions = {
  max_gas_amount: '1000',
  gas_unit_price: '1',
  expiration_timestamp_secs: '1646793600',
  sequence_number: '10'
}
window.pontem.signTransaction(payload, otherOptions)
  .then(tx => {
    console.log('Transaction', tx)
  })
  .catch(e => console.log('Error', e))
```

#### Sign Message ![API Sign Message](https://badgen.net/badge/included%20in/%3E=1.7.0)

To request a signature of message, use the `signMessage` method.

```javascript
window.pontem.signMessage({
  address: true, // set true if you want include current address to message
  application: true, // // set true if you want include current application to message
  chainId: true, // set true if you want include current chain id to message
  message: 'a message i trust', // message like string or Uint8Array
  nonce: 'random nonce' // random nonce like string
})
  .then(result => {
    console.log('Signed Message', result)
  })
  .catch(e => console.log('Error', e))
```


# Wallet Adapter

:exclamation:*You are reviewing an outdated version of the Pontem Wallet documentation! We recommend switching to the most recent version from the new* [*official website*](https://docs.pontemwallet.xyz/)! :warning:<br>

The wallet adapter helps you to integrate many different wallets at once and use the same interface to interact with any supported wallet.

Developed by Hippo team, main repository - <https://github.com/hippospace/aptos-wallet-adapter>.

Supports:

* [Pontem Wallet](https://pontem.network/pontem-wallet)
* [Aptos official wallet](https://github.com/aptos-labs/aptos-core/releases/tag/wallet-v0.1.1)
* [Martian wallet](https://martianwallet.xyz/)
* [Fewcha wallet](https://fewcha.app/)
* [Hippo wallet](https://github.com/hippospace/hippo-wallet)
* [Hippo web wallet](https://hippo-wallet-test.web.app/)

## Installation

With `yarn`

```
yarn add @manahippo/aptos-wallet-adapter
```

With `npm`

```
npm install @manahippo/aptos-wallet-adapter
```

## Examples

### Add Pontem Wallet to an existing codebase (React Provider)

```typescript
import React from "react";
import {
  PontemWalletAdapter, // Import Pontem Wallet Adapter.
  HippoWalletAdapter,
  ...
  WalletProvider,
} from '@manahippo/aptos-wallet-adapter';

const wallets = () => [
  new PontemWalletAdapter(),
  new HippoWalletAdapter(),
   // Add Pontem Wallet Adapter to list of supported wallets.
  ...
  new HippoExtensionWalletAdapter(),
];

...

```

### Use React Provider

```typescript
import React from "react";
import {
  PontemWalletAdapter,
  HippoWalletAdapter,
  AptosWalletAdapter,
  HippoExtensionWalletAdapter,
  MartianWalletAdapter,
  FewchaWalletAdapter,
  WalletProvider,
} from '@manahippo/aptos-wallet-adapter';

const wallets = () => [
  new PontemWalletAdapter(),
  new MartianWalletAdapter(),
  new AptosWalletAdapter(),
  new FewchaWalletAdapter(),
  new HippoWalletAdapter(),
  new HippoExtensionWalletAdapter(),
];

const App: React.FC = () => {
  return (
    <WalletProvider
      wallets={wallets}
      onError={(error: Error) => {
        console.log('Handle Error Message', error)
      }}>
      {/* your website */}
    </WalletProvider>
  );
};

export default App;
```

## Web3 Hook

```typescript
import { useWallet } from '@manahippo/aptos-wallet-adapter';

const { connected, account, ...rest } = useWallet();

/*
  ** Properties available: **

  wallets: Wallet[]; - Array of wallets
  wallet: Wallet | null; - Selected wallet
  account(): AccountKeys | null; - Wallet info: address, publicKey, authKey
  connected: boolean; - check the website is connected yet
  connecting: boolean; - true while adapter waits connect() to finish
  disconnecting: boolean; - true while adapter waits disconnect() to finish
  connect(walletName: string): Promise<void>; - trigger connect popup
  disconnect(): Promise<void>; - trigger disconnect action
  signAndSubmitTransaction(
    transaction: TransactionPayload
  ): Promise<PendingTransaction>; - function to sign and submit the transaction to chain
  signTransaction(transaction: TransactionPayload): Promise<SubmitTransactionRequest>;
  - function to sign the transaction, but not submit
  signMessage(message: string): Promise<string> - function to sign message
  
*/
```

## Connect & Disconnect

```typescript
const { wallets, connect, disconnect, isConnected } = useWallet();
const wallet = 'PontemWallet';

if (!isConnected) {
  return (
    <Button
      onClick={() => {
        connect(wallet);
      }}
    >
      Connect
    </Button>
  );
} else {
  return (
    <Button
      onClick={() => {
        disconnect();
      }}
    >
      Disconnect
    </Button>
  );
}
```


# Demo

:exclamation:*You are reviewing an outdated version of the Pontem Wallet documentation! We recommend switching to the most recent version from the new* [*official website*](https://docs.pontemwallet.xyz/)! :warning:<br>

## Wallet Demo

We prepared two demos: one with a wallet adapter and another one just using native Pontem Wallet integration.

![Pontem Wallet Demo](/files/ksahGOisUA5ozSyuqPkp)

It contains basic features like:

* Choose wallet to connect
* Connect wallet
* Show address
* Sign transaction

But still good enough for a good start with Pontem Wallet and Wallet Adapter.

Try demo using the following links:

* [Integrations Demo](https://pontem-network.github.io/pontem-wallet-demo/#/pontem-native)

The source code for the demo is available on our Github - [Pontem Wallet Demo Github](https://github.com/pontem-network/pontem-wallet-demo)


# Introduction

![Move Langugage](/files/XcBU87NfSfrhVVRwglsH)

Many crypto developers are interested in using the Move language. The reasons for this are its high security and the emerging use cases that will grow as soon as crypto and non-crypto users are merged.

{% hint style="info" %}
🧙‍♂️ The Move Language is the most secure smart contracts language and will probably become a standard after Solidity.
{% endhint %}

It combines security by design (**formal verification from box, atomic resource model**) with ease of use, being Turing complete, safe and flexible. It is developed and used by ex-Diem team transformed to Aptos.

Although it has built-in security by design such as resource-oriented architecture and formal verification, Move VM still severely lacks toolsets and documentation. Therefore more research and development is still needed in this area and Pontem will help seed this ecosystem.

Unique features implemented in Move Language:

* **Access Control** - In Move, any custom asset such as a token can be declared as a resource type, making it safe and access-controlled by default. This feature allows for maintaining ownership information and privileges of digital assets within smart contracts. If an asset is sent to a smart contract, ownership is not changed. For example, if a hacker gets access to a Move smart contract, he would not be able to withdraw the assets to his own wallet unless that functionality is a feature of the smart contract.
* **Atomic resource architecture** - Prevents developers from making basic mistakes that are common in smart contract development such as reentrance errors or double-spending errors. In Move, resources can never be copied or implicitly discarded, only moved between storage locations.
* **Modules** - Are akin to smart contracts but more similar to banks using object oriented programming. Each resource (object) is stored in an individual vault, controlled by the owner’s account. Resource operations are limited by the functions supported by the specific module(class), which may be called from outside the module. Developers can deploy new modules to the network.
* **Scripts** - Each transaction on the network may contain a script that can call several modules or initiate several actions. Developers can use one transaction to engage various actions which significantly reduces the number of smart contracts required for an application. This results in safer applications, better user experience, and significantly more flexibility.
* **Bytecode verifier** - The verifier is an integral part of Move which checks new modules and scripts for security purposes before these are published. Once verified, the Bytecode interpreter module executes the code. This feature reduces the number of runtime errors.
* **Formal verification** - Modules can be verified using formal verification automatically before being deployed.
* **Gas system** - Similar to the Solidity gas usage system, users can set gas prices for their transactions to be competitively processed by validators.

Because the Move language is very young, there is not much information about it, and this is why we are ready to present available documentation so you can learn Move language through examples and using existing books/tutorials.

List of recommended resources:

* [Move Documentation](https://developers.diem.com/docs/welcome-to-diem) - official Move language documentation.
* [Aptos Documentation](https://aptos.dev/)


# Move Playground

![Move Playground](/files/LT25xfouAxyTXc2tjCEw)

The Move Playground is a web version of the Move VM, Move CLI and basic IDE. This allows developer to write, test, build their Smart Contracts in the browser.

## Quick Guide

### Create module

1. Go to [Move Playground](https://playground.pontem.network/) and create a new project by clicking on **"+" near "Projects**".
2. Put the name of your project into the input field.
3. Click on the created project.
4. Add a new module to the project by clicking on **"+"** near the `sources` folder.
5. Put the name of the module in the input field, e.g. `test_module.move` (file extension is required).
6. Put your Move code inside, e.g.:

```rust
module 0x01::TestModule {
}
```

Click on the 🛠️ button in the top menu to build the new module then close the console.

### Run script

1. Create a new script similarly to how you created a module (but inside the script folder), e.g. `test_script.move`.
2. Put the following code inside:

```rust
script {
   fun test_script(val: u128) {
     assert!(val == 15, 101);
   }
}
```

1. Build it by clicking the 🛠️ button in the top menu.
2. Navigate to the `Run` section in left menu.
3. In the bottom of the screen you can input a script command to execute, e.g.: `test_script(100)`.
4. Enjoy experimenting with arguments 👩‍🔬

### Custom addresses

1. Click on the 🔗 icon in the left menu.
2. Add a new address by entering the name and address in the fields inside the popup.
3. Use the named address in your code.

## Roadmap

Playground is currently in alpha stage. The current Roadmap is:

* Tests in browser.
* Allow watching a stored resource.
* Add support for different Move VM networks.
* Move Prover in browser.
* Ability to save/share projects and code samples.

## Tech stack

The Move Playground is possible due to:

* [Move VM WASM](https://github.com/pontem-network/sp-move-vm) fork developed by our team.
* [Dove Light](https://github.com/pontem-network/dove) - Dove package manager built for Web.
* [Monaco Editor](https://github.com/microsoft/monaco-editor) for frontend.


# Intellij IDE Extension Tutorial

Start coding in Move 100% free with PyCharm Community Edition and Pontem Move Intellij Plugin

![IDE Screen 1](/files/Tzc8Ali7ZUXRZvFQqyyC)

Pontem’s Intellij plugin for Move is the first tool that allows you to add Move smart contract language to your projects built with various IDEs by JetBrains: PyCharm, CLion, IDEA, Android Studio, RIder, etc. Now you can build dApps for Aptos and other Move-compatible blockchains using the IDEs you are used to.&#x20;

The plugin is very advanced compared to JetBrains plugins for other smart contract languages like Solidity. It supports syntax highlighting, on-the-go error checks, auto-formatting, symbols, etc. It’s also **completely free** and really easy to use.

**Key Features:**

* Syntax highlighting
* Code formatting
* Go-to-definition
* Rename refactoring
* Type inference
* `Move.toml` and `aptos` binary integration

In this tutorial, we'll focus on using the Intellij Move plugin with PyCharm. It's also been tested to work with Intellij [CLion](https://www.jetbrains.com/clion/). Since the installation and use are almost identical, you can use this tutorial for CLion, too, but note that CLion doesn't have a free Community Edition yet.

### What is PyCharm Community Edition?

PyCharm is a popular IDE for coding in Python, developed by JetBrains. Most people are familiar with the paid Professional version, but there is also a completely free Community Edition. It works perfectly with Pontem’s Intellij plugin for Move and has all the features you’ll need to start building dApps for Aptos.&#x20;

In this tutorial, we’ll describe how to install and use the free version with PyCharm Community Edition. See here for the differences between PyCharm Professional and Community Edition. You can also use the Move plugin for free with Intellij IDEA Community Edition, if you are used to the IDEA IDE, as well as with most other JetBrains IDEs, such as CLion. The installation process is almost identical.

## Install PyCharm Community Edition

### 1) Download and run JetBrains Toolbox

Toolbox is an installer utility by JetBrains (around 66 MB). Download the correct file for your OS from the [JetBrains Toolbox page](https://www.jetbrains.com/toolbox-app/). &#x20;

For Linux, Toolbox comes as a .tar.gz archive; for Windows, it’s an .exe file, and for MacOS, it’s a .dmg app file. If using Linux, extract the .tar.gz to get to the Jetbrains-toolbox installer inside.&#x20;

<br>

<figure><img src="https://lh6.googleusercontent.com/2oVGA2hxf7dRP3uT8I-hpYtVB0GEP8qcDOOLVXaJcSUtO4bjuLmUsBSIjOs9pY_c7lPLU_CZTT2hDz78R15kh46IeLM6rG--pjVSKz4EiRcyKowPsymVbxwAbMLZdJWsYgrTXL0xBTbxoXNvTmU_4k0" alt=""><figcaption></figcaption></figure>

### 2) Run the installer

Locate PyCharm Community on the list → “Install”. The process takes just a couple of minutes.

<figure><img src="/files/FenQ7bWM5EDzRxQgptCn" alt=""><figcaption></figcaption></figure>

## Install Pontem Intellij Plugin

The easiest way to install our Move plugin is from PyCharm itself.&#x20;

In PyCharm Community Edition, go to the Plugins tab and search for Move Language. Click Install and accept the third-party plugin terms. Move will be added to your Installed Plugins tab. Make sure to check for updates regularly, as Pontem poften adds new features to the plugin.

<figure><img src="/files/WoKdGbB8kJe54i2924DZ" alt=""><figcaption></figcaption></figure>

## Install Aptos CLI

[Aptos CLI](https://github.com/aptos-labs/aptos-core/blob/main/crates/aptos/README.md#install-the-aptos-cli) is a command-line interface that will allow you to write code in Move. We are planning to add a CLI installation button to our Intellij plugin so that you can use it right out of the box, but for now, you’ll need to install it separately. We’ll describe how to do it on MacOS, Linux, and Windows.

Add Aptos CLI to Linux with Terminal

### **1) Check that you have Python**

Most recent Linux distros come with Python, which you’ll need to install the CLI. To check your version, run the command:&#x20;

```jsx
$ python3 -version
```

If you are running an old distro that doesn’t have Python, it makes sense to upgrade the OS.

### **2) Install the CLI with a single command from Terminal**

The easiest way to get Aptos CLI on Linux is an automated install: it takes just one command. See the [official Aptos documentation directory](https://aptos.dev/tools/install-cli/automated-install) for more detailed instructions and alternative ways to install the CLI, such as downloading the binaries manually.&#x20;

Now execute the following command:

```jsx
wget -qO- "https://aptos.dev/scripts/install_cli.py" | python3
```

Run `$ aptos info` to make sure that everything works. If it doesn’t work straight away, try rebooting the computer.&#x20;

`Wget` is a utility for downloading files from the internet. By default, Wget will install Aptos CLI into the folder Home/(username)/.local/bin.  To check that it’s really there, go to Home in the file explorer app and click Ctrl+H to display hidden folders, then open /.local/bin – you should find an executable file called “aptos”.

### Add Aptos CLI to MacOS with Terminal

The best way to install Aptos CLI (and all sorts of other utilities) on Mac is with [Homebrew](https://brew.sh/) - an automated software package manager. To download Homebrew, open Terminal from Applications -> Utilities and run the command (you’ll need to enter your admin password):&#x20;

{% code overflow="wrap" %}

```jsx
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

{% endcode %}

During the installation, you may be prompted to also install the Xcode command line developer tools package. After that, the Homebrew installation will finish. Make sure to run the two additional commands that Homebrew will prompt you to execute.

<figure><img src="/files/Ji195Nj43gYZ7vsTxMZ9" alt=""><figcaption></figcaption></figure>

Once Homebrew is installed, update it:

```jsx
brew update
```

And finally, install Aptos CLI:

```jsx
brew install aptos
```

Run `$ aptos help` to make sure that everything works. <br>

<figure><img src="https://lh5.googleusercontent.com/D0VYf6QQ0FYypOktMvWqra933yyUoZAQrJW_J3uN0uU_2oxr7LqjN9H0iw53lEwImp2xdUVd-AHgilIEY2nIqPO5psBzo4SZ8JTDMZcEcWDalMVyQrGFNrxLO68fSNbhf1S9BDHA5ofaiuzX3UlCAxg" alt=""><figcaption></figcaption></figure>

See the [official Aptos documentation directory](https://aptos.dev/tools/install-cli/automated-install) for more detailed instructions and alternative ways to install the CLI on Mac.

### Add Aptos CLI to Windows with Powershell

The recommended way to install Aptos CLI on Windows  is with a command in Powershell. To launch Powershell, click on the search icon in the Start menu, type “`powershell`”, and click Open or Run as Administrator. See [here](https://www.howtogeek.com/662611/9-ways-to-open-powershell-in-windows-10/) for more ways to open Powershell or  [here](https://learn.microsoft.com/en-us/powershell/scripting/windows-powershell/starting-windows-powershell?view=powershell-7.3) for how to install and open Powershell in earlier versions of Windows.&#x20;

In Powershell, execute the following command to install Aptos CLI:

{% code overflow="wrap" fullWidth="false" %}

```jsx
iwr "https://aptos.dev/scripts/install_cli.py" -useb | Select-Object -ExpandProperty Content | python3
```

{% endcode %}

\
See the [official Aptos documentation directory](https://aptos.dev/tools/aptos-cli/install-cli/automated-install/) for more detailed instructions and alternative ways to install the CLI on Windows, including from source code.

## Create your first Move project

1. In the main PyCharm menu, choose “File” → “New Project”.

<figure><img src="https://lh6.googleusercontent.com/WZfWf6POABNrCiXudbSyvwutAeL49SdT3tBIsmJWqR_5T-kEfqJcCw0oOjU_n7Th5Lv5bAJQHNpf19IXqukY5d9VynasWq1CGjUQ5X23dHGmSsKbqO3TNBOaz3-iXSE_brXTE_m-5YRHFy5QXf46Nak" alt=""><figcaption></figcaption></figure>

2. Choose “Move” in the menu on the left. Enter a name for your project - for example “MyFirstMoveProject”.

<figure><img src="/files/xznrDpaTNjmbJpGYCnBy" alt=""><figcaption></figcaption></figure>

3. A path to Aptos CLI should be inserted already. If it’s not, open the Terminal/Console and run `which aptos`, then navigate to that directory in PyCharm’s Aptos CLI field.

If you installed Aptos CLI using Terminal/Console/Powershell, it can be located in a hidden folder like .local/bin. Make sure to click the “Show Hidden Files and Directories” icon (the eye icon) in the navigation popup.

<br>

<figure><img src="https://lh6.googleusercontent.com/EV3J9vP49ZQPD1FVZ-IHug8FvQtdG4c0HEe2EdZew8j5GsD3MqyW4_zBYELANJTYf5w-R4u74IL6_9nx4GHgghmsGdaGGAnFS84RF51oJ7MOsv9KIp8UhRr-MGTRgMWq-EY3SzcWOoZ5P2vHV37oB1o" alt=""><figcaption></figcaption></figure>

4. Click on “Create”. In the new project, the Move.toml file should open automatically. If it doesn’t, unroll the dropdown under the project’s name on the left and click on Move.toml.

<figure><img src="https://lh4.googleusercontent.com/OtOmsL1ZCUPRChfyZikXRuJsCg8-VsuvaVaedhYInaE1gbJOXTRUot9apYzFYQTmQ99RQ_mWp9QNtWadvwGYOSL9V73ODOTKKK4L5wI4N_g5oKtWKSAPOHtiVbQQdJd4Ow1SjNoPe-QXqQ-iszWLmp0" alt=""><figcaption></figcaption></figure>

5. Open the Terminal emulator in PyCharm by pressing Alt+F12. Alternatively, you can launch Terminal from PyCharm’s main sandwich menu (top left corner) -> View -> Tool Windows -> Terminal.

<figure><img src="https://lh4.googleusercontent.com/4wKx-i_gLelk8ht_E0ROitRFYQSYfoVm_yaAXRZojH66WIKowrgll0gTgSo74XaVT0VUNJS8EeR0kbfzx93voMpLTIgM-YQxOiYjNCcXmOGXvBqyGUvQ4APsIvik0NYkEx-FkGmKHXc5br3QiPkO8v4" alt=""><figcaption></figcaption></figure>

6. In the Terminal, run the following command: `aptos init`. When prompted to choose a network, press Enter to choose devnet (the default option), then Enter again to generate a new Aptos private key - unless you want to use an existing private key (0x…), in which case paste it in.
7. The Pontem Move plugin will generate a new Aptos account and fund it with 100,000,000 testnet octas. This is equivalent to 1 APT. Note that testnet APT doesn’t have any real value and can’t be bridged to the mainnet. &#x20;
8. Copy the address of the newly generated account. In the Move.toml, file, locate the “addresses” line. Go to the next line and enter: `Sender = “(your account address)”` (see the screenshot).

<figure><img src="https://lh5.googleusercontent.com/nBzNaEeluIWZsqghGTnBx39c5fuEBhTTlr4TM4UlHiyNQmZmNIpzkq26CIlCQf5AxK6d_TR9b7Lgxgxr2gnbJ5zagzRtYRldFLpDRSmfUAQdy4AtYlRb4NNrUn5c0v3Cg5ncUflKRtOFJJ75K8Z4lCg" alt=""><figcaption></figcaption></figure>

9. Create a new Move module file: right-click on the “Sources” folder -> New -> Move FIle. Choose a name (we’ll call it “Math”) and Module as file type. Press Enter.

<figure><img src="https://lh3.googleusercontent.com/sMS5oPUlxUzjGp1xMjPIEwEPGGz-ECFTyTJ2HEYSHcih4onooVsUXpAUDuDKwsffjuMK8_DOg3afxpGkVBGctCA-iQ2kzn9Q4hbO7k3hf8oIfXa-lpCp9EcX0mXp_C0Kl5l-oE7L47WZAwoHOk4kxP0" alt=""><figcaption></figcaption></figure>

10\. In the Math.move module, copy the following code into the brackets after “module Sender: Math”:

{% code overflow="wrap" %}

```jsx
public fun add(a: u128, b: u128): u128 { a + b }

```

{% endcode %}

<figure><img src="https://lh3.googleusercontent.com/446afOcCoqkOG78ztVbv9Tin78Zrej3n1STwszaUNMSVaZGEGrn_Xg-CGwG0PabzCRYnDqvHiUlEcEGuiVEtzhSuJRp6B_N2KV-0cybuWWdbqNprIbJo7jBTjNycnu5f3RakB__Zmpv5TKknQ94lvwE" alt=""><figcaption></figcaption></figure>

11\. Open the Run Build display tool: click on the main sandwich menu in the top left -> View -> Tool Windows -> Run.&#x20;

<figure><img src="https://lh4.googleusercontent.com/x3O7CN-t_hm9Vl7n4M_IPARzP0KQGW_eoJochJ3jsjO5LIfb_b_IBriJllC-Eh_05M1_Z-d7maW0t3mP0J0uTvTnvr6fziAcXDcVKnxRVeK4ogyVh1tk2ctORZqLj2zhnWWUotZbnVnw_sHNXpMUY6c" alt=""><figcaption></figcaption></figure>

12. Check if you have an active build configuration: if you do, you’ll see a Run Move button. If you don’t, you’ll see something like Add Configuration or Current File.

<figure><img src="https://lh6.googleusercontent.com/OfPUO0GTlX7kkMzcIH-UXykVJ2V9RtBnrVJz1ULP10_MeB-vgnd8SRrHRKs5aWFxxhZCjbsTUeWVhODVt9VYwqhrx_DL3Bf5dXg9RmQjYVtT9xcMDhqqHL1TqLJAOi49ld3zLfFtSBrRNz3-_bhkqic" alt=""><figcaption></figcaption></figure>

You need an active build configuration to be able to build the project. To create one, either press Alt+Shift+F10 -> Edit Configurations or click on the Build button in the top right to go to the Edit Configurations dialogue. Click on Add New Run Configuration or the + icon in the corner -> Aptos -> Any command.&#x20;

<figure><img src="https://lh4.googleusercontent.com/pv2JJbS18UzItvQz6CtJ60MihAc4hm62ALWv2933p9JADXSIs9Fw3Oo5Bnb3y27YzHoSgg8Qyd7HB_n7rC7Nyvv7PdRPR-rbgHhaVxwdN9Z41JbEUqnAa2Czdnhw03NjyA6Fhq_Hsy4u16hM64RC5j0" alt=""><figcaption></figcaption></figure>

Make sure that the `move compile` command is selected and that the directory path to the project is correct. Give your configuration a name (like Run Move). Click Run to build your Move project.

<figure><img src="https://lh6.googleusercontent.com/c8OTfh7hUpok6B_mqHcg2XesC63Wi6Vr6iT6x4DZhtcIWb_z72_rQPxlxj2NL_mZBN40DFj3pfoDX6Z2F2J-7P_jbQTg3i5vWVuPAePPi2E2ik6f3Dwz4knqadQs_RSWXhiJRR2yrARoUYc10IYb1hg" alt=""><figcaption></figcaption></figure>

The results will be displayed in the Run console at the bottom. You’ll also see a new build folder in the list of the project’s folders on the left.

If there are any errors in your code, you'll see them in the Problems console.

![](/files/FLPXH6tr9V2J45MP4Esf)

## Deploy modules

1. Open the file containing a module - in our case, Math.move. You’ll find it in the sources folder on the left.&#x20;
2. Check that the Run console is displayed - or call it through the main sandwich menu -> View -> Tool Windows -> Run. When prompted, agree to the transaction fee (just type yes).
3. Press Alt+Shift+F10 or click on Run Move -> Edit Configurations. Create a new configuration (click on the + sign -> Aptos -> any command, name it Publish Math, and enter move publish as command -> OK.&#x20;

<figure><img src="https://lh6.googleusercontent.com/6N-Emu2J1zhN08hA1o6Y0bqRerME60pc6ORlSMCxDyFajBzyMclEtpOSu6x-F1lDGHMsE9Xslw5JlnYorRKp3550ms1eEbzUXhUmvnjfPjtYmPQhY8LvRvrzcEku0IelHBd3c4wyVqT-DgM-tlk-l0o" alt=""><figcaption></figcaption></figure>

4. Run Publish Math on Math.move.&#x20;

5\. When prompted in the console, enter yes to agree to pay the gas fee by typing in yes. Publishing a module is a transaction on the blockchain that incurs a network fee. You should get a transaction hash once the deployment operation is finalized.

<figure><img src="https://lh5.googleusercontent.com/oW9mtRPaxx8BvkNo9NXJyzaARmCpPfNgqj1KHzYp56ODw44GSYI7rsUnne19rmCJfagrEADbJwvXq3FVhb6kFmqBfPN_zMgUX3o3E7Mm9uPeK6DHspdzGa6TM3vqV9-OPC_NWrJflqnsdLB3san_YVA" alt=""><figcaption></figcaption></figure>

## Write and run tests

1. The project directory should already have a folder called “tests”. If it doesn’t, right-click the project’s name in the menu on the left -> New -> Directory. Name the new folder “tests”.

<figure><img src="https://lh5.googleusercontent.com/tyTALS8QMuKtmKguodcCHloRnMh00YVqFYmq9JEy5GSBk25_CBjheEU3UBjUcEhV0JZcmTYEw6c9wFwIBIKPAMC77CCXjj3kkBaFDAXXMLZgBovovePMQIl3WkYjKY3uClfEGU3v_uqJTuNhIAHcAG8" alt=""><figcaption></figcaption></figure>

2. Navigate to the project’s folder in your computer’s file explorer and create a new folder within it, naming it Tests.&#x20;
3. Right-click the tests folder -> New -> Move File -> Test Module. Name the new file “MathTest” and choose Test Module as Type.&#x20;
4. Insert the following code in the new test file between the brackets after Sender: :MathTest. Be careful not to leave dangling brackets.

```jsx
#[test_only]
module Sender::MathTest {
    use Sender::Math;

    #[test]
    fun test_add() {
        let a = 20;
        let b = 30;

        let r = Math::add(a, b);
        assert!(r == (a+b), 1);
    }
}
```

5\. Right-click the MathTest file -> Test MathTest. If this run configuration isn’t available, create one through the Edit Configurations dialogue, using the `move test` command. You’ll see the results in the console.

<figure><img src="https://lh3.googleusercontent.com/WWS-6XtsdVEHGguL9D1lVrWltHwS5VaxhzF7UfI7u3U2dbRRmyY_E4sOa0Lov71zr5B7F7XslUmMPRzcOeQ6ZtBzxx6vIi0hbMllogiyx0_s4Pk6yu9Xp6VE38HR1fNFVuknH216A1RTHXxaNQ0rw1I" alt=""><figcaption></figcaption></figure>

Apart from running the test on the whole module, you can test individual lines in the gutter using  green Run buttons:

![](/files/gHUgkRyBt1H3S3weM38o)

Alternatively, just right click on the “tests” folder and run all tests.

![](/files/DiNiPMOI1hI2N4cT1Nh1)

## Troubleshooting

### "Error running "Build": Executable is not specified"&#x20;

![](/files/bGnXAO3O8EmorAVaNkV7)

Open the “Preferences” menu -> Languages & Frameworks -> Move Language. Insert the path to the Aptos CLI in your local system, click on “Apply”, and close the window.

![](/files/fT3gexMmjGyc3DeLNgVx)


# Aptos Tutorial

Aptos is a Layer 1 blockchain that allows developers to create their smart-contracts in Move language.

Aptos is focused on delivering the safest and most production-ready Layer 1 blockchain in the world. The team is comprised of the original creators, researchers, designers, and builders of Diem, the blockchain that was first built at Meta.

The key components of Aptos are AptosBFT consensus and the new Move language which allows developers to build safe and scalable decentralized applications.

With this tutorial you will start learning Move language and create your first smart contract for Aptos.

### Move

Move is a smart-contract language created with a heavy focus on security. Built on Rust, it inherits features that prevent developers from inadvertently introducting critical vulnerabilities.

The key feature of Move is the ability to define custom resource types with semantics inspired by linear logic. A resource can never be copied, double spent or implicitly discarded, only moved between program storage locations. These safety guarantees are enforced statically by Move’s type system.

You can read the Move whitepaper here: <https://developers.diem.com/papers/diem-move-a-language-with-programmable-resources/2019-06-18.pdf>

In this tutorial, we're going to create a simple module that allows users to store their username in the blockchain. This will allow us to explore unique features of Move and prepare for more complex projects.

### Aptos CLI

First we need to install the Aptos CLI for tools to interact with Aptos. Go to the Aptos CLI [releases page](https://github.com/aptos-labs/aptos-core/releases), and download the zip file for your OS.

The archive contains the `aptos` binary, which consists of:

* `aptos move` namespace has everything related to the Move language:
  * compiler
  * test runner
  * deploying Move modules to the blockchain
  * executing transactions
* `aptos key` allows you to generate a new private key
* `aptos init` allows you to initialize your Aptos project in order to:
  * set a private key for the project
  * specify REST API urls

Put the archive somewhere in your `$PATH`.

Optionally, you can also install Pontem's Move extension for CLion or PyCharm (all 2021.1+ versions are supported), and add the Intellij-Move plugin there. It provides support for the Move language.

To do this, go to <https://www.jetbrains.com/pycharm/download/> and follow instructions for your operating system.

After you install it, go to File -> Settings, select `Plugins` on the left, then `Marketplace` and search for the `Move language`.

### Creating a new project

Move projects are called Packages, and contain multiple Modules.

A Module is a smart-contract that combines types and functions, and provides a very unique set of rules and restrictions to manage relationships between them.

A Package is a set of related Move modules which share common dependencies and are often published to the same address in the Aptos blockchain.

First, create a directory and initialize it with a Package using the aptos binary:

```shell
mkdir userinfo
cd userinfo
aptos move init --name UserInfo
```

This should be the resulting directory structure of our new Package:

```
userinfo/
├── sources/
└── Move.toml
```

`sources/` - directory where you put your modules.\
`Move.toml` - manifest file for the package. Here, you define the package metadata, dependencies and addresses used in the code.

Let's add an address with name `sender` and value `0x42` under `[addresses]`. We're going to store all our modules in that address in the Aptos blockchain.

```toml
[package]
name = 'UserInfo'
version = '1.0.0'

[dependencies.AptosFramework]
git = 'https://github.com/aptos-labs/aptos-core.git'
rev = 'devnet'
subdir = 'aptos-move/framework/aptos-framework'

[addresses]
sender = "0x42"
```

The `move init` command automatically adds a dependency to the `AptosFramework` package. It also transitively adds a `MoveStdlib` dependency. Let's compile that empty package to make the Aptos CLI fetch the dependencies and inspect them.

Compiling for the first time could take a while because it fetches the whole `aptos-core` repo from Github.

```shell
~/userinfo $ ~/bin/aptos move compile
{
  "Result": []
}
```

Fetched dependencies as well as build artifacts are stored in the `build/` directory at the package root.

```shell
build/
└── UserInfo
    ├── bytecode_modules
    ├── source_maps
    └── sources
        └── dependencies
            ├── AptosFramework
                ├── account.move
                ├── coin.move
                ........
            └── MoveStdlib
                ├── string.move
                ├── signer.move
                ├── vector.move
                ........
```

`MoveStdlib` - standard library of the Move language consisting of modules that are indispensable such as functions to work with vectors and signers.

`AptosFramework` - a set of modules specific to the Aptos blockchain, like the `coin` module for an ERC20-like fungible token, and `accoint` for the account metadata.

### Resources and storage

Every user of the Aptos blockchain has their own object storage located at the user address.

There are built in methods which allow access to this storage from the Move code.

```
    /// check whether object is present in storage
    fun exists<T>(addr): bool;
    
    /// return read-only reference to the object
    fun borrow_global<T>(addr): &T;

    /// return mutable reference to the object
    fun borrow_global_mut<T>(addr): &mut T;

    /// add object to the storage
    fun move_to<T>(&signer, T);

    /// remove object from the storage
    fun move_from<T>(addr): T;
```

In that storage, smart-contracts store special structs called Resources. Those are marked with the `has key` ability after the name of the struct.

To place a resource on a user address, a developer should have the `&signer` argument in scope and call the `move_to` function. The `&signer` data type in the Move language represents the sender account of the current transaction, and is used mostly for resource store and access restrictions in modules. Developers can extract the address of the transaction sender using `signer::address_of(&signer)` function.

All functions that fetch resource objects from storage require an annotation on the function signature. For that, add `acquires ResourceName` after the return type.

### Implementation

#### UserProfile

First, let's add a `UserProfile` resource struct where we're going to store our username in a field of type `String`. Resources in Move are marked with the `has key` ability.

```
module sender::user_info {
    // imports String type from module string that resides on address std.
    // std is an address defined in the transitive std dependency of the AptosFramework dependency
    // and automatically available to all the package code
    use std::string::String;
    
    struct UserProfile has key { username: String }
}
```

There's no text strings in Move. All text is represented as `vector<u8>` objects or sequences of bytes. To use them more easily, the byte string literal was introduced, i.e. `b"MyUser", b"MyString"`.

Later, the `string` module was added to the standard library, which provides a `String` struct that wraps `vector<u8>` and ensures that it contains only UTF8 characters. In our usernames, we're going to use those.

#### Methods

Now let's add getter and setter methods for the `username`:

Let's implement getter first. We need to retrieve the `UserProfile` object from the user global storage. For that, we will use the `borrow_global()` method which needs the address of the user store as a parameter. This also allows us to fetch the username of any other user.

We also add `acquires UserProfile` which was explained earlier.

```
module sender::user_info {
    use std::string::String;
    
    struct UserProfile has key { username: String }
    
    public fun get_username(user_addr: address): String acquires UserProfile {
        // no need for the semicolon at the end, last expression is the returning one (just like in Rust)
        borrow_global<UserProfile>(user_addr).username
    }
}
```

Implementation of the setter is a bit more complex. The setter will be a public entry function. Unlike the usual function which can be called only by other modules, entry functions can be called by sending a transaction to the Aptos blockchain containing arguments, generics and name/path in the function. Using public entry functions, users of your DApp can interact with deployed modules.

We need to create an if-statement with two branches:

* first for the case when there's no `UserProfile` in the global storage, we need to create one with the correct username
* second is just to update username inside the existing `user_info`

We also need `&signer` here, as we want to only allow users themselves to change their profile.

```
module sender::user_info {
    use std::string::{String, utf8};
    use std::signer;

    struct UserProfile has key { username: String }

    public fun get_username(user_addr: address): String acquires UserProfile {
        borrow_global<UserProfile>(user_addr).username
    }

    public entry fun set_username(user_account: &signer, username_raw: vector<u8>) acquires UserProfile {
        // wrap username_raw (vector of bytes) to username string
        let username = utf8(username_raw);

        // get address of transaction sender
        let user_addr = signer::address_of(user_account);
        // `exists` just to check whether resource is present in storage
        if (!exists<UserProfile>(user_addr)) {
          let info_store = UserProfile{ username: username };
          move_to(user_account, info_store);
        } else {
          // `borrow_global_mut` is to fetch mutable reference, we can change resources in storage that way
          let existing_info_store = borrow_global_mut<UserProfile>(user_addr);
          existing_info_store.username = username;
        }
    }
}
```

### Tests

Now, let's write a test for our module to make sure everything works correctly. Test functions could be added anywhere, but it's a nice convention to store them in the `tests/{$MODULE_NAME}_tests.move` module.

Create a `tests/` directory to the root of the package, and add `user_info_tests.move` there. Test functions are marked with the `#[test]` attribute, this way Move knows it's a test and can apply special treatment. We also mark the module itself with a `#[test_only]` attribute to remove it from the public namespace.

```
#[test_only]
module sender::user_info_tests {
    use std::string::utf8;
    use std::signer;

    use sender::user_info;

    // this named parameter to the test attribute allows to provide a signer to the test function,
    // it should be named the same way as parameter of the function
    #[test(user_account = @0x42)]
    public entry fun test_getter_setter(user_account: signer) {
        let username = b"MyUser";
        user_info::set_username(&user_account, username);

        let user_addr = signer::address_of(&user_account);
        // assert! macro for asserts, needs an expression and a failure error code
        assert!(user_info::get_username(user_addr) == utf8(username), 1);
    }
}
```

To run this test:

```shell
~/userinfo $ ~/bin/aptos move test
INCLUDING DEPENDENCY AptosExperimental
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING test-tutorial
Running Move unit tests
[ PASS    ] 0x42::user_info_tests::test_getter_setter
Test result: OK. Total tests: 1; passed: 1; failed: 0
{
  "Result": "Success"
}
```

### Deployment to Aptos blockchain

Let's deploy our module to the Aptos blockchain and make it available for everyone.

We must initialize a new Aptos account and deployment configuration using the `aptos init` command.

During execution of the command a new Aptos account will be created and test coins will be deposited to it so we can cover gas costs of the `UserInfo` module publication.

Use default parameters proposed by the command:

```shell
~/userinfo $ ~/bin/aptos init
Configuring for profile default
Enter your rest endpoint [Current: None | No input: https://fullnode.devnet.aptoslabs.com]

No rest url given, using https://fullnode.devnet.aptoslabs.com...
Enter your faucet endpoint [Current: None | No input: https://faucet.devnet.aptoslabs.com]

No faucet url given, using https://faucet.devnet.aptoslabs.com...
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 6E81B91A98226A2622B6993B9D14D3244FA8AFACF622AA3CB11A32C799E93C42 doesn't exist, creating it and funding it with 10000 coins
Aptos is now set up for account 6E81B91A98226A2622B6993B9D14D3244FA8AFACF622AA3CB11A32C799E93C42!  Run `aptos help` for more information about commands
{
  "Result": "Success"
}
```

The deployment config which contains the private key of the new account will be created in `.aptos/config.yaml` in the root of the project. Don't share your private key with anyone! If you want to change the configuration or account, just run `aptos init` again and the configuration will be overwritten.

Copy the new generated address, in our example it's `0x6E81B91A98226A2622B6993B9D14D3244FA8AFACF622AA3CB11A32C799E93C42` (don't forget to add `0x` prefix to the start of the address), and replace the `sender` address in `Move.toml`.

You will get something like this but with your own address:

```toml
[addresses]
sender = "0x6E81B91A98226A2622B6993B9D14D3244FA8AFACF622AA3CB11A32C799E93C42"
```

Finally let's deploy the module using the `aptos move publish` command:

```shell
~/userinfo $ ~/bin/aptos move publish
{
  "Result": {
    "changes": [
      {
        "address": "6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
        "data": {
          "authentication_key": "0x6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
          "coin_register_events": {
            "counter": "1",
            "guid": {
              "id": {
                "addr": "0x6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
                "creation_num": "0"
              }
            }
          },
          "sequence_number": "1"
        },
        "event": "write_resource",
        "resource": "0x1::account::Account"
      },
      {
        "address": "6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
        "data": {
          "packages": [
            {
              "package info...",
              "modules": [
                {
                  "modules info..."
                }
              ],
              "name": "test-tutorial",
              "upgrade_policy": {
                "policy": 1
              }
            }
          ]
        },
        "event": "write_resource",
        "resource": "0x1::code::PackageRegistry"
      },
      {
        "address": "6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
        "data": {
          "coin": {
            "value": "9950"
          },
          "deposit_events": {
            "counter": "1",
            "guid": {
              "id": {
                "addr": "0x6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
                "creation_num": "1"
              }
            }
          },
          "withdraw_events": {
            "counter": "0",
            "guid": {
              "id": {
                "addr": "0x6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
                "creation_num": "2"
              }
            }
          }
        },
        "event": "write_resource",
        "resource": "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>"
      },
      {
        "address": "6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
        "event": "write_module"
      }
    ],
    "gas_used": 50,
    "success": true,
    "version": 20020209,
    "vm_status": "Executed successfully"
  }
}
```

You should get a similar output which means your module is now published.

## Setting username for our account

After we deployed the `user_info` module we can send a transaction to the Aptos blockchain which will call the `user_info::set_username` function and set the username for our account.

To execute the `set_username` function we need to utilize the `aptos move run` command. In this example we will use the username `AptosDev` as the username for our account which has to be provided as an argument. Also, `function-id` should contain a path to the deployed contract and function name. In your case the path will be different because you are using your own account.

```shell
~/userinfo $ ~/bin/aptos move run --function-id 0x6E81B91A98226A2622B6993B9D14D3244FA8AFACF622AA3CB11A32C799E93C42::user_info::set_username --args string:"AptosDev"
{
  "Result": {
    "changes": [
      {
        "address": "6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
        "data": {
          "authentication_key": "0x6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
          "coin_register_events": {
            "counter": "1",
            "guid": {
              "id": {
                "addr": "0x6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
                "creation_num": "0"
              }
            }
          },
          "sequence_number": "2"
        },
        "event": "write_resource",
        "resource": "0x1::account::Account"
      },
      {
        "address": "6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
        "data": {
          "coin": {
            "value": "9946"
          },
          "deposit_events": {
            "counter": "1",
            "guid": {
              "id": {
                "addr": "0x6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
                "creation_num": "1"
              }
            }
          },
          "withdraw_events": {
            "counter": "0",
            "guid": {
              "id": {
                "addr": "0x6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
                "creation_num": "2"
              }
            }
          }
        },
        "event": "write_resource",
        "resource": "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>"
      },
      {
        "address": "6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42",
        "data": {
          "username": "AptosDev"
        },
        "event": "write_resource",
        "resource": "0x6e81b91a98226a2622b6993b9d14d3244fa8afacf622aa3cb11a32c799e93c42::user_info::UserProfile"
      }
    ],
    "gas_used": 4,
    "success": true,
    "version": 20027657,
    "vm_status": "Executed successfully"
  }
}
```

If the transaction is executed successfully, you will see an output similar to the one above. Now you can query your username. In this example, the URL to the query resource would be:

<https://fullnode.devnet.aptoslabs.com/v1/accounts/0x6E81B91A98226A2622B6993B9D14D3244FA8AFACF622AA3CB11A32C799E93C42/resource/0x6E81B91A98226A2622B6993B9D14D3244FA8AFACF622AA3CB11A32C799E93C42::user_info::UserProfile>

To interact with the module deployed by you: replace the address of the account and the address of the module resource in the url with your own.

Enjoy! Please share your feedback and more tutorial requests in our [Discord](https://discord.gg/44QgPFHYqs) and [Telegram](https://t.me/pontemnetworkchat).


# Move Playground

![Welcome to the Move Code Playground.](/files/0BoxaUpWaFdV52uxHLmC)

## Testing Your First Move Project

In this guide, you’ll use the Pontem Network [Move Code Playground](https://playground.pontem.network/) to play with an example Move project. Along the way, we'll walk through the key features of this browser-based IDE to help jump start your own Move projects.

### This quick start guide shows you how to:

* Navigate the Move Code Playground (MCP) interface.
* Understand an example project's configuration within the MCP.
* Compile an example Move package within the MCP.
* Run an example script within the MCP.

## Before You Begin

Getting oriented to the Move Code Playground is easy. With just a web browser and a few key concepts, you can use this online code editor to build, test, and run Move packages on Move compatible blockchains like Aptos.

If you are not yet familiar with the Move language, the [Move Book](https://diem.github.io/move/) is a great developer resource.

For everyone else, let's check out the interface.

## Navigating an Example Project

To help developers quickly familiarize themselves with Move packages, the MCP automatically loads an example-project when you first visit the IDE. This project appears in the top left navigation pane when you click on 'Projects'.

| ![Welcome to the Move Code Playground.](/files/9oyY6DsnMM24WzexKJen)      |
| ------------------------------------------------------------------------- |
| *Fig.1 - Move Code Playground: Interface and pre-loaded example-project.* |

In order to expand the file tree, simply click on the 'example-project' label within the "Explorer" panel.

In this section, we'll expand the example project tree to highlight how your Move projects should be set up. We will briefly touch on the following key concepts:

* The Move folder structure
* Project dependencies
* Addresses
* Development reminders

#### A Move project folder structure

```
example-project/
  scripts/
    file_name.move
  sources/
    Filename.move
  tests/
    FileName.move
```

**Within the folder structure:**\
All Modules are listed under `sources/`.\
The scripts to interact with Modules are listed under `scripts/`.\
And all test files appropriately go under `tests/`.

#### Project Dependencies

Clicking on the left navigation panel's 'Dependencies' icon reveals that the Move Code Playground comes pre-loaded with two dependencies:

* AptosFramework - A set of modules specific to the Aptos blockchain.
* MoveStdlib - The standard library of the Move language.

*Note: When building your own projects, you may need to add these manually.*

| Description     | Url                                        | Rev                                      | Subdir                                |
| --------------- | ------------------------------------------ | ---------------------------------------- | ------------------------------------- |
| Aptos Framework | <https://github.com/aptos-labs/aptos-core> | 367608ab5cf726039ff44bfdac1f2177210b1440 | aptos-move/framework/aptos-framework/ |
| Move Std Lib    | <https://github.com/aptos-labs/aptos-core> | 367608ab5cf726039ff44bfdac1f2177210b1440 | aptos-move/framework/move-stdlib/     |

#### Addresses

Clicking on the left navigation panel's 'Addresses' icon reveals that the Move Code Playground comes pre-loaded with one Address:

*Note: When building your own projects, you may need to add these manually.*

| Name   | Address | Description                                                               |
| ------ | ------- | ------------------------------------------------------------------------- |
| Sender | 0x1     | Default address for use as a stand-in for storing this package's modules. |

#### Important Development Reminders

**Project Dependencies**

If beginning a project from scratch within the MCP, the StdLib dependency listed above must be added manually in order to utilize Move's core library features.

**Addresses**

In development, addresses can be abbreviated (0x1, 0x2, etc.), but they must be replaced by 'real' addresses before code can be deployed to production.

**Configuration File**

If you export the example project, you will notice a configuration file ("Move.toml") in the zipped folder that does not appear in the MCP directory tree. Opening this reveals the project's dependencies and addresses. Creating and importing your own "Move.toml" files can be an easy way to skip manually entering dependencies while testing new code in the Playground.

<br>

Now that we understand the example project's configuration, let's dive in to compiling and running some code.

## Understanding the Example Project

The goal of this first example is a simple demonstration of moving a generic resource. The code will allow us to store a value (of type u128) at an address (of our choosing) and then to retrieve it at a later time.

If you are programming in Move for the first time, it is key to understand two basic concepts before we begin:

* First, that Move is a sort of Resource-Oriented language. The simplified definition of this just states that resources can not be duplicated or destroyed once created, they can only be moved.
* Second, that Move's compiler strictly enforces the best practices needed to create the safe and efficient code that is needed specifically for blockchain deployment. This ensures that the first point listed above is baked-in to all code deployed for use.

Further tutorials will explain in detail the syntax and methodology behind constructing Move files, for our first demo, let's just get familiar with executing basic functions within the MCP.

#### For this first demo, you will use the example-project files to perform the following within the MCP:

* Compile a demo package.
* Store a value at a demo address.
* Retrieve the value from your demo address.
* Read common debugging messages.

Now, on to the code!

## Compiling the Example Code

As is the case with all Move packages: This example-project's modules are defined in the 'sources' sub-folder and we will use the functions defined within the 'scripts' sub-folder to interact with these modules.

#### Our demo uses the following files from the example-project:

```
example-project/
  scripts/
    get_u128.move
    store_u128.move
  sources/
    Storage.move
```

Before we run any scripts, let's make sure the package is compiled. To do this, click 'Build' in the top left navigation menu. A build status will be displayed in the console at the bottom of the screen (Fig.2).

| ![MCP Build Screenshot.](/files/NEYtNzSVQEy4YCCcUyXt)             |
| ----------------------------------------------------------------- |
| *Fig.2 - Move Code Playground: Build button and console message.* |

#### Build Success Message

A successful build will return a timestamp and console log message: `The project was successfully built` along with an execution time `(0.04s)`.

#### Build Error messages

A failed build will return error messages in the console. To test this, open the file `/scripts/get_u128.move` and make the following modification:

Change the line:

`let _ = Storage::get<u128>(&account);`

to read

`let A = Storage::get<u128>(&account);`.

Then try to 'Build' the project.

Your console will now light up with warnings and errors. Since this `get_u128` file uses external dependencies, the actual error may be buried at the bottom of a list. Scroll to the bottom of the console and you'll find the culprit (Fig.3):

| ![MCP Error Console.](/files/Vux30PwnCTDMKlxhlfUT)   |
| ---------------------------------------------------- |
| *Fig.3 - Move Code Playground: Build error message.* |

The console window lets us know we made a simple naming convention error:

```
error[E02010]: invalid name
  ┌─ /example-project/scripts/get_u128.move:6:13
  │
6 │         let A = Storage::get<u128>(&account);
  │             ^ Invalid local variable name 'A'. Local variable names must start with 'a'..'z' (or '_')
```

Change the `let A` back to a `let _`, hit 'Build' and we are back in business.

Let's move on to running our first script.

## Running an Example Script

In order to run scripts within the Move Code Playground. Click the 'Run Script' link on the left navigation pane (Fig.4). From here, you will type commands directly into the prompt in the 'Run' pane.

| ![MCP Run Script Screenshot.](/files/lXXkWcwyypfChzClApCU) |
| ---------------------------------------------------------- |
| *Fig.4 - Move Code Playground: Run Script Command Prompt.* |

For our demo, we'll be running the `get_u128()` and `store_u128()` functions. Both of these interact with our `Storage` resource, which is defined locally in our `sources/Storage.move` file. We are also going to be using a new demo address `0x5`.

Let's give it a try.

### Getting a Value From a Specified Address

| ![get\_u128() example script.](/files/QNsWwIdq051PP8zZxml6) |
| ----------------------------------------------------------- |
| *Fig.5 - get\_u128(0x5) example script.*                    |

1. In the 'Run' command prompt, type `get_u128(0x5)`.
2. To execute the script, press 'enter'.
3. This script will attempt to get a u128-type value from the `0x5` address.

This should produce the following error message in the console:

```
Execution aborted with code 102 in module 0000000000000000000000000000000000000000000000000000000000000001::Storage.
```

What has gone wrong? The message is letting us know to look in the `Storage` module at address `000...0x1` for `code 102`. If we remember from earlier in the tutorial that address `0x1` is our example-project's pre-defined `Sender` address, we can really understand the error message to be read as below:

```
Execution aborted with code 102 in module Sender::Storage.
```

Let's take a look in our `Storage` module to see what is going on.

### The Storage Module and Address

It is important to know that in our example-project package, `Storage` as a module is bound to the `Sender` address (0x1) as defined locally within the `/sources/Storage.move` file:

```
module Sender::Storage {
    ...
}
```

This is equivalent to defining the module as:

```
module 0x1::Storage {
    ...
}
```

A quick scan of the rest of our `Storage` module reveals that error `code 102` is a result of nothing being found at the specified address `0x5`.

```
module Sender::Storage {
 ...
 public fun get<T: store>(account: &signer): T acquires Storage {
   ...
   // Check if resource exists on address, otherwise throw error with code 102.
   assert!(exists<Storage<T>>(addr), 102);
   ...
 }
 ...
}
```

This is an obvious error, but it is helpful to show that our demo address `0x5` holds no values by default. Let's now use a script to store a value there.

*Note: In your own future projects, `Sender` may be replaced by other addresses. And in production, all modules will have unique addresses.*

### Storing a Value at a Specified Address

| ![store\_u128() example script.](/files/ile79Ry7BKdWK2L5kDkN) |
| ------------------------------------------------------------- |
| *Fig.6 - store\_u128(0x5) example script.*                    |

To demonstrate how this looks in Move, we are going to run a basic script that allows us to store a simple value (of type u128) at an address `0x5` and then to retrieve it later.

Let's give it a try.

1. In the 'Run' command prompt, type `store_u128(0x5, 123)`.
2. To execute the script, press 'enter'.
3. This script will attempt to store a u128-type value of `123` in the `0x5` address.

This should produce the following message in the console:

```
Gas used: 14
Changed resource(s) under 1 address(es):
  
Changed 1 resource(s) under address 0000000000000000000000000000000000000000000000000000000000000005:
    Added type 0x1::Storage::Storage<u128>: [123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (wrote 67 bytes)
      key 0x1::Storage::Storage<u128> {
          val: 123u128
      }
Wrote 67 bytes of resource ID's and data
```

There is a lot to unpack here in further documentation, but the general takeaway is that a value of `123u128` is now stored under address `0x5`.

Let's try adding another value to the same address.

1. In the 'Run' command prompt, type `store_u128(0x5, 456)`.
2. To execute the script, press 'enter'.
3. This script will attempt to store a u128-type value of `456` in the `0x5` address.

```
Execution aborted with code 101 in module 0000000000000000000000000000000000000000000000000000000000000001::Storage.
```

Whoops! What happened? We have forgotten another of the key concepts in Move: One unique resource for each address. Since we are currently holding a Storage resource at `0x5`, we cannot overwrite what already exists there or replace it with another Storage resource.

But what if we...wait for it...move that value from `0x5`?

1. In the 'Run' command prompt, type `get_u128(0x5)`.
2. To execute the script, press 'enter'.
3. This script will attempt to get a u128-type value from the `0x5` address.

Success!

```
Gas used: 10
Changed resource(s) under 1 address(es):
  
Changed 1 resource(s) under address 0000000000000000000000000000000000000000000000000000000000000005:
    Deleted type 0x1::Storage::Storage<u128> (wrote 51 bytes)
      key 0x1::Storage::Storage<u128> {
          val: 123u128
      }
Wrote 51 bytes of resource ID's and data
```

Again, a lot to unpack, but the general takeaway is that we retrieved that 'val' of `123u128` from `0x5`, and you can even see it has been deleted as a resource in the previous line, freeing the space for another Storage resource.

Let's re-try adding that `456` value to `0x5` by executing `store_u128(0x5, 456)` again.

```
Gas used: 14
Changed resource(s) under 1 address(es):
  
Changed 1 resource(s) under address 0000000000000000000000000000000000000000000000000000000000000005:
    Added type 0x1::Storage::Storage<u128>: [200, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] (wrote 67 bytes)
      key 0x1::Storage::Storage<u128> {
          val: 456u128
      }
Wrote 67 bytes of resource ID's and data
```

Success!

We have now seen a most basic example of how generic types can be stored and retrieved using Move within the Move Code Playground. The power of Move goes far beyond this, however. As further tutorials will show how we can use the same basic principles to define our own resource types to represent all sorts of things virtually.

## Recap & Next Steps

In this tutorial, we covered a number of core concepts to get started with the Move Code Playground. From touring the interface to running basic scripts and debugging common errors. For more advanced resources, check out or other tutorials and documentation and join us on Discord.

\ <br>


# Public nodes

### LLT

You can use [Pontem's public fullnode](https://aptos-testnet.pontem.network/v1) to interact with the Aptos LLT (long lived testnet). The Node is immediately updated to the latest version if necessary.

URL: <https://aptos-testnet.pontem.network/v1>


