diff --git a/contract/.env.example b/contract/.env.example deleted file mode 100644 index db27492..0000000 --- a/contract/.env.example +++ /dev/null @@ -1,3 +0,0 @@ -SHINE_BOT_CONTRACT=shine.v1 -SHINE_BOT_WALLET_HOST=localhost -SHINE_BOT_WALLET_PORT=6666 diff --git a/contract/.envrc.example b/contract/.envrc.example new file mode 100644 index 0000000..43849b6 --- /dev/null +++ b/contract/.envrc.example @@ -0,0 +1,3 @@ +export SHINE_BOT_CONTRACT=shine +export SHINE_BOT_WALLET_HOST=localhost +export SHINE_BOT_WALLET_PORT=6666 diff --git a/contract/.gitignore b/contract/.gitignore index 736b045..4701377 100644 --- a/contract/.gitignore +++ b/contract/.gitignore @@ -1,5 +1,10 @@ -*.wast +CMakeCache.txt +cmake_install.cmake +compile_commands.json +eosc-vault.json +Makefile +.envrc -/.env - -.idea +build*/ +CMakeFiles/ +.vscode/ diff --git a/contract/CMakeLists.txt b/contract/CMakeLists.txt new file mode 100644 index 0000000..fa3258b --- /dev/null +++ b/contract/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.5) +project(shine VERSION 1.0.0) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(EOSIO_WASMSDK_DEPENDENCY "1.1") + +if(EOSIO_WASMSDK_ROOT STREQUAL "" OR NOT EOSIO_WASMSDK_ROOT) + set(EOSIO_WASMSDK_ROOT "/usr/local/eosio.wasmsdk") +endif() + +list(APPEND CMAKE_MODULE_PATH ${EOSIO_WASMSDK_ROOT}/lib/cmake) + +include(EosioWasmToolchain) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/abi/shine.abi" "${CMAKE_CURRENT_BINARY_DIR}" COPYONLY) + +add_executable(shine.wasm ${CMAKE_CURRENT_SOURCE_DIR}/src/shine.cpp) +target_include_directories(shine.wasm + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include) + +set_target_properties(shine.wasm + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/contract/Makefile b/contract/Makefile deleted file mode 100644 index 8a8a744..0000000 --- a/contract/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -BLOCKCHAIN_HOST := "localhost" -BLOCKCHAIN_PORT := "8888" -CONTRACT_ACCOUNT := "shine.v1" -WALLET_HOST := "localhost" -WALLET_PORT := "6666" - -HEADERS = asset.hpp shine.hpp table.hpp - -default: build - -build: shine.wast - -shine.wast: shine.cpp $(HEADERS) - eosiocpp -o shine.wast shine.cpp shine.abi - -install: build - cleos \ - --host ${BLOCKCHAIN_HOST} \ - --port ${BLOCKCHAIN_PORT} \ - --wallet-host ${WALLET_HOST} \ - --wallet-port ${WALLET_PORT} \ - set contract ${CONTRACT_ACCOUNT} `pwd` \ - shine.wast shine.abi - -clean: - -@rm -f shine.wast 2>/dev/null || true \ No newline at end of file diff --git a/contract/README.md b/contract/README.md index c62f7fd..c583cd8 100644 --- a/contract/README.md +++ b/contract/README.md @@ -1,109 +1,108 @@ -## EOS Shine SmartContract +## EOS Shine Smart Contract -This document describes various aspects of the EOS Shine SmartContract +This document describes various aspects of the EOS Shine smart contract implementation ranging from architecture, building, troubleshooting, etc. Moreover, this document also contains various information about EOS -SmartContract in general, mainly aimed at the developer audience. - -### Architecture & Features - -The Shine contract goal is to enable the implementation of a recognition -system based on praise and votes. Person (i.e. account) broadcast a praise -to all other members. Each member (i.e. account) can then vote for this -particular praise. - -TBC +smart contract in general, mainly aimed at the developer audience. #### Actions -* `praise` (`addpraise`) - Create a praise in the blockchain. -* `vote` (`addvote`) - Vote for a given praise in the blockchain. -* `rewards` (`calcrewards`) - Update the rewards table in the blockchain. +* `post` - Create a post in the blockchain. +* `vote` - Vote for a given praise in the blockchain. +* `reset` - Reset all collected stats to initial state. ### Development -#### Prerequisites +#### Compilation -For development, ideally you would have a testnet running on your machine -executing the EOS blockchain by configuring a local environment. Follow the instructions at https://github.com/EOSIO/eos/wiki/Local-Environment and when you have a `nodeos` -running with a producer emitting blocks, come back here. +##### Docker -There is a `shine_bot.rb` script that enables to interact with the contract -in a more rapid way. For this you will need Ruby 2.4+ installed along with the -following dependency installed globally: +The easiest way to compile is by using EOS Canada `gcr.io/eoscanada-public/eosio-wasmsdk` +Docker image. + +While at the root of this project: ``` -gem install 'tty-prompt' +cd contract +docker run --rm -it -v `pwd`:/shine -w /shine gcr.io/eoscanada-public/eosio-wasmsdk:v1.1.1 bash build.sh ``` -Note that this is not needed if you don't plan on using the - -#### Preparation +You will find the compiled `shine.abi` and `shine.wasm` in the `build` directory. -Let's prepare for the development of EOS Shine SmartContract. We will -need an account on a running blockchain. It's quite possible to run -you own test blockchain on your machine for development purposes. +##### Locally -Let's create the account by creating two EOS key sets (first one for owner -permission second one for active permission). Note the private keys outputted -somewhere as we will need them in later section: +Ensure that you have `https://github.com/EOSIO/eosio.wasmsdk` compiled locally. -**Note** You will need to have `eosios@active` private key imported into a -wallet for the account creation to work. Import it using `cleos wallet import `. +While at the root of this project: ``` -# Owner -cleos create key -Private key: 5H123 -Public key: EOSXYZ - -# Active -cleos create key -Private key: 5B456 -Public key: EOSABC - -cleos create account eosio shine EOSXYZ EOSABC +./build.sh ``` -Once the account is created, let's import the owner and active private keys -into the default wallet (you are free to use another wallet also): +You will find the compiled `shine.abi` and `shine.wasm` in the `build` directory. + +#### Installation -**Note** Ensures that the wallet is unlocked prior doing this operation. You -can unlock it by using `cleos wallet unlock` and entering the wallet password -that was outputted at wallet creation time. +While at the root of this project: ``` -# Of course, change 5H123 and 5B456 by real owner & active private keys respectively -cleos wallet import 5H123 -cleos wallet import 5B456 +cd contract +cleos set contract shine build build/shine.wasm build/shine.abi ``` -We are then good to go. Note that if the blockchain node is stopped, -wallet will need to be unlocked again prior doing any operations -in the upcoming sections. - -#### Building & Testing +#### Testing -Building the SmartContract ABI and code to WAST is performed through -the `eosiocpp` command line utility. Navigate to the root folder -of this project and then issue: - -``` -eosiocpp -o shine.wast shine.cpp -``` +First, install [eos-bios](https://github.com/eoscanada/eos-bios) then follow +the [local-development-environment](https://github.com/eoscanada/eos-bios#local-development-environment) +instructions to start a local `nodeos` for development. -Once the WAST has been generated correctly, next step is to set the contract -on the account `shine` that was created in the preparation step: +Ensure that your `boot_sequence.yaml` contains the following content: (the content must comes +before the `Replacing eosio account from eosio.bios contract to eosio.system` block): ``` -cleos set contract shine `pwd` +- op: system.newaccount + label: Create account eosioforum + data: + creator: eosio + new_account: shine + pubkey: EOS5MHPYyhjBjnQZejzZHqHewPWhGTfQWSVTWYEhDmJu4SXkzgweP + +- op: system.newaccount + label: Create user account for shine + data: + creator: eosio + new_account: matt + pubkey: EOS5MHPYyhjBjnQZejzZHqHewPWhGTfQWSVTWYEhDmJu4SXkzgweP + +- op: system.newaccount + label: Create user account for shine + data: + creator: eosio + new_account: eve + pubkey: EOS5MHPYyhjBjnQZejzZHqHewPWhGTfQWSVTWYEhDmJu4SXkzgweP + +- op: system.newaccount + label: Create user account for shine + data: + creator: eosio + new_account: evan + pubkey: EOS5MHPYyhjBjnQZejzZHqHewPWhGTfQWSVTWYEhDmJu4SXkzgweP + +- op: system.newaccount + label: Create user account for shine + data: + creator: eosio + new_account: mike + pubkey: EOS5MHPYyhjBjnQZejzZHqHewPWhGTfQWSVTWYEhDmJu4SXkzgweP ``` -##### Testing +Import the following private key in your wallet: `5JpjqdhVCQTegTjrLtCSXHce7c9M8w7EXYZS7xC13jVFF4Phcrx` +(this is the private key for the public one `EOS5MHPYyhjBjnQZejzZHqHewPWhGTfQWSVTWYEhDmJu4SXkzgweP`, of +course, you can use your own pair if you change the public key part in the boot sequence). To make it easier to develop, the `shine_bot.rb` is a small command line -utility to interact more easily with the SmartContract. +utility to interact more easily with the smart contract. First, it's possible to run all command in a quick way by passing the flag `-q` to the CLI tool. This will not ask for question for which a default value @@ -133,20 +132,20 @@ the `member_id` being pass to the contract. Possible usage: -* `./shine_bot.rb --praise` - Perform a praise (author, praisee, memo) +* `./shine_bot.rb --post` - Perform a post (from, to, memo) * `./shine_bot.rb --vote` - Perform a vote (praise_id, voter) -* `./shine_bot.rb --rewards` - Compute the rewards (pot) -* `./shine_bot.rb --scenario` - Perform a scenario adding 6 praises and 10 votes. +* `./shine_bot.rb --reset` - Reset the all state to initial values +* `./shine_bot.rb --scenario` - Perform a scenario adding 6 posts and 10 votes. By using the scenario, you will automatically add a bunch of praises and -votes so it's easier to test your SmartContract code and changes afterward. +votes so it's easier to test your smart contract code and changes afterward. -### EOS SmartContract +### EOS smart contract #### References This section aims at providing links to documentation related to some concept -of building SmartContract for the EOS blockchain. +of building smart contract for the EOS blockchain. * `eosio::multi_index` diff --git a/contract/shine.abi b/contract/abi/shine.abi similarity index 98% rename from contract/shine.abi rename to contract/abi/shine.abi index a6f122b..9263842 100644 --- a/contract/shine.abi +++ b/contract/abi/shine.abi @@ -1,5 +1,8 @@ { "types": [{ + "new_type_name": "account_name", + "type": "name" + },{ "new_type_name": "post_id", "type": "uint64" }], diff --git a/contract/asset.hpp b/contract/asset.hpp deleted file mode 100644 index 477e3bf..0000000 --- a/contract/asset.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -#include -#include - -namespace eoscanada { - -static const uint64_t EOS_PRECISION = 4; -static const asset_symbol EOS_SYMBOL = S(EOS_PRECISION, EOS); - -inline static eosio::asset double_to_asset(double amount) { - return eosio::asset((uint64_t)(pow(10, EOS_PRECISION) * amount), EOS_SYMBOL); -} - -inline static double asset_to_double(const eosio::asset& asset) { return asset.amount / pow(10, EOS_PRECISION); } - -} // namespace eoscanada diff --git a/contract/build.sh b/contract/build.sh new file mode 100755 index 0000000..247ee1e --- /dev/null +++ b/contract/build.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +GREEN='\033[0;33m' +RED='\033[0;31m' +NC='\033[0m' + +printf "${GREEN}=========== Building shine ===========${NC}\n\n" + +BUILD_SUFFIX=${1} +CORES=`getconf _NPROCESSORS_ONLN` + +mkdir -p build${BUILD_SUFFIX} +pushd build${BUILD_SUFFIX} &> /dev/null +cmake ../ +make -j${CORES} +popd &> /dev/null \ No newline at end of file diff --git a/contract/include/asset.hpp b/contract/include/asset.hpp new file mode 100644 index 0000000..39ce4ed --- /dev/null +++ b/contract/include/asset.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include +#include + +namespace eoscanada { + +static const eosio::symbol_type EOS_SYMBOL = S(4, EOS); + +inline static eosio::asset double_to_asset(double amount, eosio::symbol_type symbol) { + return eosio::asset((uint64_t)(pow(10, symbol.precision()) * amount), symbol); +} + +inline static double asset_to_double(const eosio::asset& asset) { return asset.amount / pow(10, asset.symbol.precision()); } + +} // namespace eoscanada diff --git a/contract/shine.hpp b/contract/include/shine.hpp similarity index 99% rename from contract/shine.hpp rename to contract/include/shine.hpp index a8c6194..7ae8c96 100644 --- a/contract/shine.hpp +++ b/contract/include/shine.hpp @@ -11,7 +11,7 @@ #include "table.hpp" // Configurable values -#define REWARD_post_count_WEIGHT 0.07 +#define REWARD_POST_COUNT_WEIGHT 0.07 #define REWARD_VOTE_RECEIVED_WEIGHT 0.9 #define REWARD_VOTE_GIVEN_WEIGHT 0.03 diff --git a/contract/table.hpp b/contract/include/table.hpp similarity index 100% rename from contract/table.hpp rename to contract/include/table.hpp diff --git a/contract/shine.wasm b/contract/shine.wasm deleted file mode 100644 index d45860f..0000000 Binary files a/contract/shine.wasm and /dev/null differ diff --git a/contract/shine_bot.rb b/contract/shine_bot.rb index 00ebb57..126df0f 100755 --- a/contract/shine_bot.rb +++ b/contract/shine_bot.rb @@ -5,6 +5,7 @@ require 'open3' require 'tty-prompt' +DEBUG = ENV['DEBUG'] || false EOS_NAME_REGEX = /^[\.1-5a-z]{1,12}[\.a-p]?$/ def main(arguments) @@ -20,7 +21,7 @@ def main(arguments) end def ask_contract(prompt) - default = ENV['CONTRACT_ACCOUNT'] + default = ENV['SHINE_BOT_CONTRACT'] return default if default prompt.ask('Contract:') do |question| @@ -197,6 +198,8 @@ def execute_cleos(arguments) options << '--wallet-port' << wallet_port if wallet_port options << '--wallet-host' << wallet_host if wallet_host + puts 'cleos', *options, *arguments if DEBUG + stdout, stderr, status = Open3.capture3('cleos', *options, *arguments) unless status.success? puts stderr diff --git a/contract/shine.cpp b/contract/src/shine.cpp similarity index 97% rename from contract/shine.cpp rename to contract/src/shine.cpp index 152400d..86dd2cc 100644 --- a/contract/shine.cpp +++ b/contract/src/shine.cpp @@ -173,9 +173,9 @@ void shine::distribute_rewards(const asset& pot, distribution_stat& distribution auto post_count_weight = post_vote_received / (double)distribution.vote_explicit; auto vote_given_weight = vote_given_weighted / distribution.vote_given_weighted_total; - auto vote_received_amount = double_to_asset(vote_received_weight * pot_amount * REWARD_VOTE_RECEIVED_WEIGHT); - auto post_count_amount = double_to_asset(post_count_weight * pot_amount * REWARD_post_count_WEIGHT); - auto vote_given_amount = double_to_asset(vote_given_weight * pot_amount * REWARD_VOTE_GIVEN_WEIGHT); + auto vote_received_amount = double_to_asset(vote_received_weight * pot_amount * REWARD_VOTE_RECEIVED_WEIGHT, EOS_SYMBOL); + auto post_count_amount = double_to_asset(post_count_weight * pot_amount * REWARD_POST_COUNT_WEIGHT, EOS_SYMBOL); + auto vote_given_amount = double_to_asset(vote_given_weight * pot_amount * REWARD_VOTE_GIVEN_WEIGHT, EOS_SYMBOL); auto amount_total = vote_received_amount + post_count_amount + vote_given_amount; balance -= amount_total;