Basic Contract

Here is a basic contract definition. Place example.cpp and CMakeLists.txt in an empty folder.

example.cpp

#include <eosio/asset.hpp>
#include <eosio/eosio.hpp>

// The contract class must be in a namespace
namespace example
{
   // The contract
   struct example_contract : public eosio::contract
   {
      // Use the base class constructors
      using eosio::contract::contract;

      // Action: user buys a dog
      void buydog(eosio::name user, eosio::name dog, const eosio::asset& price)
      {
         // TODO: buy a dog
      }
   };

   // First part of the dispatcher
   EOSIO_ACTIONS(example_contract,  //
                 "example"_n,       //
                 action(buydog, user, dog, price))
}  // namespace example

// Final part of the dispatcher
EOSIO_ACTION_DISPATCHER(example::actions)

// ABI generation
EOSIO_ABIGEN(actions(example::actions))

CMakeLists.txt

# All cmake projects need these
cmake_minimum_required(VERSION 3.16)
project(example)

# clsdk requires C++20
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Libraries for building contracts and tests
find_package(clsdk REQUIRED)

# Build example.wasm contract
add_executable(example example.cpp)
target_link_libraries(example eosio-contract-simple-malloc)

# Generate example.abi
# This is a 2-step process:
#   * Build example.abi.wasm. This must link to eosio-contract-abigen.
#   * Run the wasm to generate the abi
add_executable(example-abigen example.cpp)
target_link_libraries(example-abigen eosio-contract-abigen)
add_custom_command(TARGET example-abigen POST_BUILD
    COMMAND cltester example-abigen.wasm >example.abi
)

# These symlinks help vscode
execute_process(COMMAND ln -sf ${clsdk_DIR} ${CMAKE_CURRENT_BINARY_DIR}/clsdk)
execute_process(COMMAND ln -sf ${WASI_SDK_PREFIX} ${CMAKE_CURRENT_BINARY_DIR}/wasi-sdk)

# Generate compile_commands.json to aid vscode and other editors
set(CMAKE_EXPORT_COMPILE_COMMANDS on)

Building

This will create example.wasm and example.abi:

mkdir build
cd build
cmake `clsdk-cmake-args` ..
make -j $(nproc)

Trying the contract

clsdk comes with nodeos, cleos, and keosd. The following will execute the contract:

# Start keosd on an empty directory
killall keosd
rm -rf testing-wallet testing-wallet-password
mkdir testing-wallet
keosd --wallet-dir `pwd`/testing-wallet --unlock-timeout 99999999 >keosd.log 2>&1 &

# Create a default wallet. This saves the password in testing-wallet-password
cleos wallet create -f testing-wallet-password

# Add the default development key
cleos wallet import --private-key 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3

# Start up a fresh chain
killall nodeos
rm -rf data config
nodeos -d data --config-dir config --plugin eosio::chain_api_plugin --plugin eosio::producer_api_plugin -e -p eosio >nodeos.log 2>&1 &

# Install the contract
cleos create account eosio example EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
cleos set abi example example.abi
cleos set code example example.wasm

# Try out the contract (does nothing)
cleos push action example buydog '["eosio", "fido", "100.0000 EOS"]' -p eosio

vscode support

The following files configure vscode:

Code completion and symbol lookup does not work until the project is built (above).